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;
3521 * Portions of this file are based on pieces of Yahoo User Interface Library
3522 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3523 * YUI licensed under the BSD License:
3524 * http://developer.yahoo.net/yui/license.txt
3525 * <script type="text/javascript">
3528 Roo.lib.Bezier = new function() {
3530 this.getPosition = function(points, t) {
3531 var n = points.length;
3534 for (var i = 0; i < n; ++i) {
3535 tmp[i] = [points[i][0], points[i][1]];
3538 for (var j = 1; j < n; ++j) {
3539 for (i = 0; i < n - j; ++i) {
3540 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3541 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3545 return [ tmp[0][0], tmp[0][1] ];
3549 * Portions of this file are based on pieces of Yahoo User Interface Library
3550 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3551 * YUI licensed under the BSD License:
3552 * http://developer.yahoo.net/yui/license.txt
3553 * <script type="text/javascript">
3558 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3559 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3562 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3564 var fly = Roo.lib.AnimBase.fly;
3566 var superclass = Y.ColorAnim.superclass;
3567 var proto = Y.ColorAnim.prototype;
3569 proto.toString = function() {
3570 var el = this.getEl();
3571 var id = el.id || el.tagName;
3572 return ("ColorAnim " + id);
3575 proto.patterns.color = /color$/i;
3576 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3577 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3578 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3579 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3582 proto.parseColor = function(s) {
3583 if (s.length == 3) {
3587 var c = this.patterns.hex.exec(s);
3588 if (c && c.length == 4) {
3589 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3592 c = this.patterns.rgb.exec(s);
3593 if (c && c.length == 4) {
3594 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3597 c = this.patterns.hex3.exec(s);
3598 if (c && c.length == 4) {
3599 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3604 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3605 proto.getAttribute = function(attr) {
3606 var el = this.getEl();
3607 if (this.patterns.color.test(attr)) {
3608 var val = fly(el).getStyle(attr);
3610 if (this.patterns.transparent.test(val)) {
3611 var parent = el.parentNode;
3612 val = fly(parent).getStyle(attr);
3614 while (parent && this.patterns.transparent.test(val)) {
3615 parent = parent.parentNode;
3616 val = fly(parent).getStyle(attr);
3617 if (parent.tagName.toUpperCase() == 'HTML') {
3623 val = superclass.getAttribute.call(this, attr);
3628 proto.getAttribute = function(attr) {
3629 var el = this.getEl();
3630 if (this.patterns.color.test(attr)) {
3631 var val = fly(el).getStyle(attr);
3633 if (this.patterns.transparent.test(val)) {
3634 var parent = el.parentNode;
3635 val = fly(parent).getStyle(attr);
3637 while (parent && this.patterns.transparent.test(val)) {
3638 parent = parent.parentNode;
3639 val = fly(parent).getStyle(attr);
3640 if (parent.tagName.toUpperCase() == 'HTML') {
3646 val = superclass.getAttribute.call(this, attr);
3652 proto.doMethod = function(attr, start, end) {
3655 if (this.patterns.color.test(attr)) {
3657 for (var i = 0, len = start.length; i < len; ++i) {
3658 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3661 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3664 val = superclass.doMethod.call(this, attr, start, end);
3670 proto.setRuntimeAttribute = function(attr) {
3671 superclass.setRuntimeAttribute.call(this, attr);
3673 if (this.patterns.color.test(attr)) {
3674 var attributes = this.attributes;
3675 var start = this.parseColor(this.runtimeAttributes[attr].start);
3676 var end = this.parseColor(this.runtimeAttributes[attr].end);
3678 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3679 end = this.parseColor(attributes[attr].by);
3681 for (var i = 0, len = start.length; i < len; ++i) {
3682 end[i] = start[i] + end[i];
3686 this.runtimeAttributes[attr].start = start;
3687 this.runtimeAttributes[attr].end = end;
3693 * Portions of this file are based on pieces of Yahoo User Interface Library
3694 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3695 * YUI licensed under the BSD License:
3696 * http://developer.yahoo.net/yui/license.txt
3697 * <script type="text/javascript">
3703 easeNone: function (t, b, c, d) {
3704 return c * t / d + b;
3708 easeIn: function (t, b, c, d) {
3709 return c * (t /= d) * t + b;
3713 easeOut: function (t, b, c, d) {
3714 return -c * (t /= d) * (t - 2) + b;
3718 easeBoth: function (t, b, c, d) {
3719 if ((t /= d / 2) < 1) {
3720 return c / 2 * t * t + b;
3723 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3727 easeInStrong: function (t, b, c, d) {
3728 return c * (t /= d) * t * t * t + b;
3732 easeOutStrong: function (t, b, c, d) {
3733 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3737 easeBothStrong: function (t, b, c, d) {
3738 if ((t /= d / 2) < 1) {
3739 return c / 2 * t * t * t * t + b;
3742 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3747 elasticIn: function (t, b, c, d, a, p) {
3751 if ((t /= d) == 1) {
3758 if (!a || a < Math.abs(c)) {
3763 var s = p / (2 * Math.PI) * Math.asin(c / a);
3766 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3770 elasticOut: function (t, b, c, d, a, p) {
3774 if ((t /= d) == 1) {
3781 if (!a || a < Math.abs(c)) {
3786 var s = p / (2 * Math.PI) * Math.asin(c / a);
3789 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3793 elasticBoth: function (t, b, c, d, a, p) {
3798 if ((t /= d / 2) == 2) {
3806 if (!a || a < Math.abs(c)) {
3811 var s = p / (2 * Math.PI) * Math.asin(c / a);
3815 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3816 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3818 return a * Math.pow(2, -10 * (t -= 1)) *
3819 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3824 backIn: function (t, b, c, d, s) {
3825 if (typeof s == 'undefined') {
3828 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3832 backOut: function (t, b, c, d, s) {
3833 if (typeof s == 'undefined') {
3836 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3840 backBoth: function (t, b, c, d, s) {
3841 if (typeof s == 'undefined') {
3845 if ((t /= d / 2 ) < 1) {
3846 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3848 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3852 bounceIn: function (t, b, c, d) {
3853 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3857 bounceOut: function (t, b, c, d) {
3858 if ((t /= d) < (1 / 2.75)) {
3859 return c * (7.5625 * t * t) + b;
3860 } else if (t < (2 / 2.75)) {
3861 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3862 } else if (t < (2.5 / 2.75)) {
3863 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3865 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3869 bounceBoth: function (t, b, c, d) {
3871 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3873 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3876 * Portions of this file are based on pieces of Yahoo User Interface Library
3877 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3878 * YUI licensed under the BSD License:
3879 * http://developer.yahoo.net/yui/license.txt
3880 * <script type="text/javascript">
3884 Roo.lib.Motion = function(el, attributes, duration, method) {
3886 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3890 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3894 var superclass = Y.Motion.superclass;
3895 var proto = Y.Motion.prototype;
3897 proto.toString = function() {
3898 var el = this.getEl();
3899 var id = el.id || el.tagName;
3900 return ("Motion " + id);
3903 proto.patterns.points = /^points$/i;
3905 proto.setAttribute = function(attr, val, unit) {
3906 if (this.patterns.points.test(attr)) {
3907 unit = unit || 'px';
3908 superclass.setAttribute.call(this, 'left', val[0], unit);
3909 superclass.setAttribute.call(this, 'top', val[1], unit);
3911 superclass.setAttribute.call(this, attr, val, unit);
3915 proto.getAttribute = function(attr) {
3916 if (this.patterns.points.test(attr)) {
3918 superclass.getAttribute.call(this, 'left'),
3919 superclass.getAttribute.call(this, 'top')
3922 val = superclass.getAttribute.call(this, attr);
3928 proto.doMethod = function(attr, start, end) {
3931 if (this.patterns.points.test(attr)) {
3932 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3933 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3935 val = superclass.doMethod.call(this, attr, start, end);
3940 proto.setRuntimeAttribute = function(attr) {
3941 if (this.patterns.points.test(attr)) {
3942 var el = this.getEl();
3943 var attributes = this.attributes;
3945 var control = attributes['points']['control'] || [];
3949 if (control.length > 0 && !(control[0] instanceof Array)) {
3950 control = [control];
3953 for (i = 0,len = control.length; i < len; ++i) {
3954 tmp[i] = control[i];
3959 Roo.fly(el).position();
3961 if (isset(attributes['points']['from'])) {
3962 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3965 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3968 start = this.getAttribute('points');
3971 if (isset(attributes['points']['to'])) {
3972 end = translateValues.call(this, attributes['points']['to'], start);
3974 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3975 for (i = 0,len = control.length; i < len; ++i) {
3976 control[i] = translateValues.call(this, control[i], start);
3980 } else if (isset(attributes['points']['by'])) {
3981 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3983 for (i = 0,len = control.length; i < len; ++i) {
3984 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3988 this.runtimeAttributes[attr] = [start];
3990 if (control.length > 0) {
3991 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3994 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3997 superclass.setRuntimeAttribute.call(this, attr);
4001 var translateValues = function(val, start) {
4002 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4003 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4008 var isset = function(prop) {
4009 return (typeof prop !== 'undefined');
4013 * Portions of this file are based on pieces of Yahoo User Interface Library
4014 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4015 * YUI licensed under the BSD License:
4016 * http://developer.yahoo.net/yui/license.txt
4017 * <script type="text/javascript">
4021 Roo.lib.Scroll = function(el, attributes, duration, method) {
4023 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4027 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4031 var superclass = Y.Scroll.superclass;
4032 var proto = Y.Scroll.prototype;
4034 proto.toString = function() {
4035 var el = this.getEl();
4036 var id = el.id || el.tagName;
4037 return ("Scroll " + id);
4040 proto.doMethod = function(attr, start, end) {
4043 if (attr == 'scroll') {
4045 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4046 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4050 val = superclass.doMethod.call(this, attr, start, end);
4055 proto.getAttribute = function(attr) {
4057 var el = this.getEl();
4059 if (attr == 'scroll') {
4060 val = [ el.scrollLeft, el.scrollTop ];
4062 val = superclass.getAttribute.call(this, attr);
4068 proto.setAttribute = function(attr, val, unit) {
4069 var el = this.getEl();
4071 if (attr == 'scroll') {
4072 el.scrollLeft = val[0];
4073 el.scrollTop = val[1];
4075 superclass.setAttribute.call(this, attr, val, unit);
4081 * Ext JS Library 1.1.1
4082 * Copyright(c) 2006-2007, Ext JS, LLC.
4084 * Originally Released Under LGPL - original licence link has changed is not relivant.
4087 * <script type="text/javascript">
4091 // nasty IE9 hack - what a pile of crap that is..
4093 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4094 Range.prototype.createContextualFragment = function (html) {
4095 var doc = window.document;
4096 var container = doc.createElement("div");
4097 container.innerHTML = html;
4098 var frag = doc.createDocumentFragment(), n;
4099 while ((n = container.firstChild)) {
4100 frag.appendChild(n);
4107 * @class Roo.DomHelper
4108 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4109 * 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>.
4112 Roo.DomHelper = function(){
4113 var tempTableEl = null;
4114 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4115 var tableRe = /^table|tbody|tr|td$/i;
4117 // build as innerHTML where available
4119 var createHtml = function(o){
4120 if(typeof o == 'string'){
4129 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4130 if(attr == "style"){
4132 if(typeof s == "function"){
4135 if(typeof s == "string"){
4136 b += ' style="' + s + '"';
4137 }else if(typeof s == "object"){
4140 if(typeof s[key] != "function"){
4141 b += key + ":" + s[key] + ";";
4148 b += ' class="' + o["cls"] + '"';
4149 }else if(attr == "htmlFor"){
4150 b += ' for="' + o["htmlFor"] + '"';
4152 b += " " + attr + '="' + o[attr] + '"';
4156 if(emptyTags.test(o.tag)){
4160 var cn = o.children || o.cn;
4162 //http://bugs.kde.org/show_bug.cgi?id=71506
4163 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4164 for(var i = 0, len = cn.length; i < len; i++) {
4165 b += createHtml(cn[i], b);
4168 b += createHtml(cn, b);
4174 b += "</" + o.tag + ">";
4181 var createDom = function(o, parentNode){
4183 // defininition craeted..
4185 if (o.ns && o.ns != 'html') {
4187 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4188 xmlns[o.ns] = o.xmlns;
4191 if (typeof(xmlns[o.ns]) == 'undefined') {
4192 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4198 if (typeof(o) == 'string') {
4199 return parentNode.appendChild(document.createTextNode(o));
4201 o.tag = o.tag || div;
4202 if (o.ns && Roo.isIE) {
4204 o.tag = o.ns + ':' + o.tag;
4207 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4208 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4211 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4212 attr == "style" || typeof o[attr] == "function") continue;
4214 if(attr=="cls" && Roo.isIE){
4215 el.className = o["cls"];
4217 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4218 else el[attr] = o[attr];
4221 Roo.DomHelper.applyStyles(el, o.style);
4222 var cn = o.children || o.cn;
4224 //http://bugs.kde.org/show_bug.cgi?id=71506
4225 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4226 for(var i = 0, len = cn.length; i < len; i++) {
4227 createDom(cn[i], el);
4234 el.innerHTML = o.html;
4237 parentNode.appendChild(el);
4242 var ieTable = function(depth, s, h, e){
4243 tempTableEl.innerHTML = [s, h, e].join('');
4244 var i = -1, el = tempTableEl;
4251 // kill repeat to save bytes
4255 tbe = '</tbody>'+te,
4261 * Nasty code for IE's broken table implementation
4263 var insertIntoTable = function(tag, where, el, html){
4265 tempTableEl = document.createElement('div');
4270 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4273 if(where == 'beforebegin'){
4277 before = el.nextSibling;
4280 node = ieTable(4, trs, html, tre);
4282 else if(tag == 'tr'){
4283 if(where == 'beforebegin'){
4286 node = ieTable(3, tbs, html, tbe);
4287 } else if(where == 'afterend'){
4288 before = el.nextSibling;
4290 node = ieTable(3, tbs, html, tbe);
4291 } else{ // INTO a TR
4292 if(where == 'afterbegin'){
4293 before = el.firstChild;
4295 node = ieTable(4, trs, html, tre);
4297 } else if(tag == 'tbody'){
4298 if(where == 'beforebegin'){
4301 node = ieTable(2, ts, html, te);
4302 } else if(where == 'afterend'){
4303 before = el.nextSibling;
4305 node = ieTable(2, ts, html, te);
4307 if(where == 'afterbegin'){
4308 before = el.firstChild;
4310 node = ieTable(3, tbs, html, tbe);
4313 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4316 if(where == 'afterbegin'){
4317 before = el.firstChild;
4319 node = ieTable(2, ts, html, te);
4321 el.insertBefore(node, before);
4326 /** True to force the use of DOM instead of html fragments @type Boolean */
4330 * Returns the markup for the passed Element(s) config
4331 * @param {Object} o The Dom object spec (and children)
4334 markup : function(o){
4335 return createHtml(o);
4339 * Applies a style specification to an element
4340 * @param {String/HTMLElement} el The element to apply styles to
4341 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4342 * a function which returns such a specification.
4344 applyStyles : function(el, styles){
4347 if(typeof styles == "string"){
4348 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4350 while ((matches = re.exec(styles)) != null){
4351 el.setStyle(matches[1], matches[2]);
4353 }else if (typeof styles == "object"){
4354 for (var style in styles){
4355 el.setStyle(style, styles[style]);
4357 }else if (typeof styles == "function"){
4358 Roo.DomHelper.applyStyles(el, styles.call());
4364 * Inserts an HTML fragment into the Dom
4365 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4366 * @param {HTMLElement} el The context element
4367 * @param {String} html The HTML fragmenet
4368 * @return {HTMLElement} The new node
4370 insertHtml : function(where, el, html){
4371 where = where.toLowerCase();
4372 if(el.insertAdjacentHTML){
4373 if(tableRe.test(el.tagName)){
4375 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4381 el.insertAdjacentHTML('BeforeBegin', html);
4382 return el.previousSibling;
4384 el.insertAdjacentHTML('AfterBegin', html);
4385 return el.firstChild;
4387 el.insertAdjacentHTML('BeforeEnd', html);
4388 return el.lastChild;
4390 el.insertAdjacentHTML('AfterEnd', html);
4391 return el.nextSibling;
4393 throw 'Illegal insertion point -> "' + where + '"';
4395 var range = el.ownerDocument.createRange();
4399 range.setStartBefore(el);
4400 frag = range.createContextualFragment(html);
4401 el.parentNode.insertBefore(frag, el);
4402 return el.previousSibling;
4405 range.setStartBefore(el.firstChild);
4406 frag = range.createContextualFragment(html);
4407 el.insertBefore(frag, el.firstChild);
4408 return el.firstChild;
4410 el.innerHTML = html;
4411 return el.firstChild;
4415 range.setStartAfter(el.lastChild);
4416 frag = range.createContextualFragment(html);
4417 el.appendChild(frag);
4418 return el.lastChild;
4420 el.innerHTML = html;
4421 return el.lastChild;
4424 range.setStartAfter(el);
4425 frag = range.createContextualFragment(html);
4426 el.parentNode.insertBefore(frag, el.nextSibling);
4427 return el.nextSibling;
4429 throw 'Illegal insertion point -> "' + where + '"';
4433 * Creates new Dom element(s) and inserts them before el
4434 * @param {String/HTMLElement/Element} el The context element
4435 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4436 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4437 * @return {HTMLElement/Roo.Element} The new node
4439 insertBefore : function(el, o, returnElement){
4440 return this.doInsert(el, o, returnElement, "beforeBegin");
4444 * Creates new Dom element(s) and inserts them after el
4445 * @param {String/HTMLElement/Element} el The context element
4446 * @param {Object} o The Dom object spec (and children)
4447 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4448 * @return {HTMLElement/Roo.Element} The new node
4450 insertAfter : function(el, o, returnElement){
4451 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4455 * Creates new Dom element(s) and inserts them as the first child of el
4456 * @param {String/HTMLElement/Element} el The context element
4457 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4458 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4459 * @return {HTMLElement/Roo.Element} The new node
4461 insertFirst : function(el, o, returnElement){
4462 return this.doInsert(el, o, returnElement, "afterBegin");
4466 doInsert : function(el, o, returnElement, pos, sibling){
4467 el = Roo.getDom(el);
4469 if(this.useDom || o.ns){
4470 newNode = createDom(o, null);
4471 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4473 var html = createHtml(o);
4474 newNode = this.insertHtml(pos, el, html);
4476 return returnElement ? Roo.get(newNode, true) : newNode;
4480 * Creates new Dom element(s) and appends them to el
4481 * @param {String/HTMLElement/Element} el The context element
4482 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4483 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484 * @return {HTMLElement/Roo.Element} The new node
4486 append : function(el, o, returnElement){
4487 el = Roo.getDom(el);
4489 if(this.useDom || o.ns){
4490 newNode = createDom(o, null);
4491 el.appendChild(newNode);
4493 var html = createHtml(o);
4494 newNode = this.insertHtml("beforeEnd", el, html);
4496 return returnElement ? Roo.get(newNode, true) : newNode;
4500 * Creates new Dom element(s) and overwrites the contents of el with them
4501 * @param {String/HTMLElement/Element} el The context element
4502 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4503 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4504 * @return {HTMLElement/Roo.Element} The new node
4506 overwrite : function(el, o, returnElement){
4507 el = Roo.getDom(el);
4510 while (el.childNodes.length) {
4511 el.removeChild(el.firstChild);
4515 el.innerHTML = createHtml(o);
4518 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4522 * Creates a new Roo.DomHelper.Template from the Dom object spec
4523 * @param {Object} o The Dom object spec (and children)
4524 * @return {Roo.DomHelper.Template} The new template
4526 createTemplate : function(o){
4527 var html = createHtml(o);
4528 return new Roo.Template(html);
4534 * Ext JS Library 1.1.1
4535 * Copyright(c) 2006-2007, Ext JS, LLC.
4537 * Originally Released Under LGPL - original licence link has changed is not relivant.
4540 * <script type="text/javascript">
4544 * @class Roo.Template
4545 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4546 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4549 var t = new Roo.Template({
4550 html : '<div name="{id}">' +
4551 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4553 myformat: function (value, allValues) {
4554 return 'XX' + value;
4557 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4559 * For more information see this blog post with examples:
4560 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4561 - Create Elements using DOM, HTML fragments and Templates</a>.
4563 * @param {Object} cfg - Configuration object.
4565 Roo.Template = function(cfg){
4567 if(cfg instanceof Array){
4569 }else if(arguments.length > 1){
4570 cfg = Array.prototype.join.call(arguments, "");
4574 if (typeof(cfg) == 'object') {
4585 Roo.Template.prototype = {
4588 * @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..
4589 * it should be fixed so that template is observable...
4593 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4597 * Returns an HTML fragment of this template with the specified values applied.
4598 * @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'})
4599 * @return {String} The HTML fragment
4601 applyTemplate : function(values){
4605 return this.compiled(values);
4607 var useF = this.disableFormats !== true;
4608 var fm = Roo.util.Format, tpl = this;
4609 var fn = function(m, name, format, args){
4611 if(format.substr(0, 5) == "this."){
4612 return tpl.call(format.substr(5), values[name], values);
4615 // quoted values are required for strings in compiled templates,
4616 // but for non compiled we need to strip them
4617 // quoted reversed for jsmin
4618 var re = /^\s*['"](.*)["']\s*$/;
4619 args = args.split(',');
4620 for(var i = 0, len = args.length; i < len; i++){
4621 args[i] = args[i].replace(re, "$1");
4623 args = [values[name]].concat(args);
4625 args = [values[name]];
4627 return fm[format].apply(fm, args);
4630 return values[name] !== undefined ? values[name] : "";
4633 return this.html.replace(this.re, fn);
4651 this.loading = true;
4652 this.compiled = false;
4654 var cx = new Roo.data.Connection();
4658 success : function (response) {
4660 _t.html = response.responseText;
4664 failure : function(response) {
4665 Roo.log("Template failed to load from " + _t.url);
4672 * Sets the HTML used as the template and optionally compiles it.
4673 * @param {String} html
4674 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4675 * @return {Roo.Template} this
4677 set : function(html, compile){
4679 this.compiled = null;
4687 * True to disable format functions (defaults to false)
4690 disableFormats : false,
4693 * The regular expression used to match template variables
4697 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4700 * Compiles the template into an internal function, eliminating the RegEx overhead.
4701 * @return {Roo.Template} this
4703 compile : function(){
4704 var fm = Roo.util.Format;
4705 var useF = this.disableFormats !== true;
4706 var sep = Roo.isGecko ? "+" : ",";
4707 var fn = function(m, name, format, args){
4709 args = args ? ',' + args : "";
4710 if(format.substr(0, 5) != "this."){
4711 format = "fm." + format + '(';
4713 format = 'this.call("'+ format.substr(5) + '", ';
4717 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4719 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4722 // branched to use + in gecko and [].join() in others
4724 body = "this.compiled = function(values){ return '" +
4725 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4728 body = ["this.compiled = function(values){ return ['"];
4729 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4730 body.push("'].join('');};");
4731 body = body.join('');
4741 // private function used to call members
4742 call : function(fnName, value, allValues){
4743 return this[fnName](value, allValues);
4747 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4748 * @param {String/HTMLElement/Roo.Element} el The context element
4749 * @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'})
4750 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4751 * @return {HTMLElement/Roo.Element} The new node or Element
4753 insertFirst: function(el, values, returnElement){
4754 return this.doInsert('afterBegin', el, values, returnElement);
4758 * Applies the supplied values to the template and inserts the new node(s) before el.
4759 * @param {String/HTMLElement/Roo.Element} el The context element
4760 * @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'})
4761 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4762 * @return {HTMLElement/Roo.Element} The new node or Element
4764 insertBefore: function(el, values, returnElement){
4765 return this.doInsert('beforeBegin', el, values, returnElement);
4769 * Applies the supplied values to the template and inserts the new node(s) after el.
4770 * @param {String/HTMLElement/Roo.Element} el The context element
4771 * @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'})
4772 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4773 * @return {HTMLElement/Roo.Element} The new node or Element
4775 insertAfter : function(el, values, returnElement){
4776 return this.doInsert('afterEnd', el, values, returnElement);
4780 * Applies the supplied values to the template and appends the new node(s) to el.
4781 * @param {String/HTMLElement/Roo.Element} el The context element
4782 * @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'})
4783 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4784 * @return {HTMLElement/Roo.Element} The new node or Element
4786 append : function(el, values, returnElement){
4787 return this.doInsert('beforeEnd', el, values, returnElement);
4790 doInsert : function(where, el, values, returnEl){
4791 el = Roo.getDom(el);
4792 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4793 return returnEl ? Roo.get(newNode, true) : newNode;
4797 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4798 * @param {String/HTMLElement/Roo.Element} el The context element
4799 * @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'})
4800 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4801 * @return {HTMLElement/Roo.Element} The new node or Element
4803 overwrite : function(el, values, returnElement){
4804 el = Roo.getDom(el);
4805 el.innerHTML = this.applyTemplate(values);
4806 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4810 * Alias for {@link #applyTemplate}
4813 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4816 Roo.DomHelper.Template = Roo.Template;
4819 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4820 * @param {String/HTMLElement} el A DOM element or its id
4821 * @returns {Roo.Template} The created template
4824 Roo.Template.from = function(el){
4825 el = Roo.getDom(el);
4826 return new Roo.Template(el.value || el.innerHTML);
4829 * Ext JS Library 1.1.1
4830 * Copyright(c) 2006-2007, Ext JS, LLC.
4832 * Originally Released Under LGPL - original licence link has changed is not relivant.
4835 * <script type="text/javascript">
4840 * This is code is also distributed under MIT license for use
4841 * with jQuery and prototype JavaScript libraries.
4844 * @class Roo.DomQuery
4845 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).
4847 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>
4850 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.
4852 <h4>Element Selectors:</h4>
4854 <li> <b>*</b> any element</li>
4855 <li> <b>E</b> an element with the tag E</li>
4856 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4857 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4858 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4859 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4861 <h4>Attribute Selectors:</h4>
4862 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4864 <li> <b>E[foo]</b> has an attribute "foo"</li>
4865 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4866 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4867 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4868 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4869 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4870 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4872 <h4>Pseudo Classes:</h4>
4874 <li> <b>E:first-child</b> E is the first child of its parent</li>
4875 <li> <b>E:last-child</b> E is the last child of its parent</li>
4876 <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>
4877 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4878 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4879 <li> <b>E:only-child</b> E is the only child of its parent</li>
4880 <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>
4881 <li> <b>E:first</b> the first E in the resultset</li>
4882 <li> <b>E:last</b> the last E in the resultset</li>
4883 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4884 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4885 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4886 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4887 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4888 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4889 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4890 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4891 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4893 <h4>CSS Value Selectors:</h4>
4895 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4896 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4897 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4898 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4899 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4900 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4904 Roo.DomQuery = function(){
4905 var cache = {}, simpleCache = {}, valueCache = {};
4906 var nonSpace = /\S/;
4907 var trimRe = /^\s+|\s+$/g;
4908 var tplRe = /\{(\d+)\}/g;
4909 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4910 var tagTokenRe = /^(#)?([\w-\*]+)/;
4911 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4913 function child(p, index){
4915 var n = p.firstChild;
4917 if(n.nodeType == 1){
4928 while((n = n.nextSibling) && n.nodeType != 1);
4933 while((n = n.previousSibling) && n.nodeType != 1);
4937 function children(d){
4938 var n = d.firstChild, ni = -1;
4940 var nx = n.nextSibling;
4941 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4951 function byClassName(c, a, v){
4955 var r = [], ri = -1, cn;
4956 for(var i = 0, ci; ci = c[i]; i++){
4957 if((' '+ci.className+' ').indexOf(v) != -1){
4964 function attrValue(n, attr){
4965 if(!n.tagName && typeof n.length != "undefined"){
4974 if(attr == "class" || attr == "className"){
4977 return n.getAttribute(attr) || n[attr];
4981 function getNodes(ns, mode, tagName){
4982 var result = [], ri = -1, cs;
4986 tagName = tagName || "*";
4987 if(typeof ns.getElementsByTagName != "undefined"){
4991 for(var i = 0, ni; ni = ns[i]; i++){
4992 cs = ni.getElementsByTagName(tagName);
4993 for(var j = 0, ci; ci = cs[j]; j++){
4997 }else if(mode == "/" || mode == ">"){
4998 var utag = tagName.toUpperCase();
4999 for(var i = 0, ni, cn; ni = ns[i]; i++){
5000 cn = ni.children || ni.childNodes;
5001 for(var j = 0, cj; cj = cn[j]; j++){
5002 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5007 }else if(mode == "+"){
5008 var utag = tagName.toUpperCase();
5009 for(var i = 0, n; n = ns[i]; i++){
5010 while((n = n.nextSibling) && n.nodeType != 1);
5011 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5015 }else if(mode == "~"){
5016 for(var i = 0, n; n = ns[i]; i++){
5017 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5026 function concat(a, b){
5030 for(var i = 0, l = b.length; i < l; i++){
5036 function byTag(cs, tagName){
5037 if(cs.tagName || cs == document){
5043 var r = [], ri = -1;
5044 tagName = tagName.toLowerCase();
5045 for(var i = 0, ci; ci = cs[i]; i++){
5046 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5053 function byId(cs, attr, id){
5054 if(cs.tagName || cs == document){
5060 var r = [], ri = -1;
5061 for(var i = 0,ci; ci = cs[i]; i++){
5062 if(ci && ci.id == id){
5070 function byAttribute(cs, attr, value, op, custom){
5071 var r = [], ri = -1, st = custom=="{";
5072 var f = Roo.DomQuery.operators[op];
5073 for(var i = 0, ci; ci = cs[i]; i++){
5076 a = Roo.DomQuery.getStyle(ci, attr);
5078 else if(attr == "class" || attr == "className"){
5080 }else if(attr == "for"){
5082 }else if(attr == "href"){
5083 a = ci.getAttribute("href", 2);
5085 a = ci.getAttribute(attr);
5087 if((f && f(a, value)) || (!f && a)){
5094 function byPseudo(cs, name, value){
5095 return Roo.DomQuery.pseudos[name](cs, value);
5098 // This is for IE MSXML which does not support expandos.
5099 // IE runs the same speed using setAttribute, however FF slows way down
5100 // and Safari completely fails so they need to continue to use expandos.
5101 var isIE = window.ActiveXObject ? true : false;
5103 // this eval is stop the compressor from
5104 // renaming the variable to something shorter
5106 /** eval:var:batch */
5111 function nodupIEXml(cs){
5113 cs[0].setAttribute("_nodup", d);
5115 for(var i = 1, len = cs.length; i < len; i++){
5117 if(!c.getAttribute("_nodup") != d){
5118 c.setAttribute("_nodup", d);
5122 for(var i = 0, len = cs.length; i < len; i++){
5123 cs[i].removeAttribute("_nodup");
5132 var len = cs.length, c, i, r = cs, cj, ri = -1;
5133 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5136 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5137 return nodupIEXml(cs);
5141 for(i = 1; c = cs[i]; i++){
5146 for(var j = 0; j < i; j++){
5149 for(j = i+1; cj = cs[j]; j++){
5161 function quickDiffIEXml(c1, c2){
5163 for(var i = 0, len = c1.length; i < len; i++){
5164 c1[i].setAttribute("_qdiff", d);
5167 for(var i = 0, len = c2.length; i < len; i++){
5168 if(c2[i].getAttribute("_qdiff") != d){
5169 r[r.length] = c2[i];
5172 for(var i = 0, len = c1.length; i < len; i++){
5173 c1[i].removeAttribute("_qdiff");
5178 function quickDiff(c1, c2){
5179 var len1 = c1.length;
5183 if(isIE && c1[0].selectSingleNode){
5184 return quickDiffIEXml(c1, c2);
5187 for(var i = 0; i < len1; i++){
5191 for(var i = 0, len = c2.length; i < len; i++){
5192 if(c2[i]._qdiff != d){
5193 r[r.length] = c2[i];
5199 function quickId(ns, mode, root, id){
5201 var d = root.ownerDocument || root;
5202 return d.getElementById(id);
5204 ns = getNodes(ns, mode, "*");
5205 return byId(ns, null, id);
5209 getStyle : function(el, name){
5210 return Roo.fly(el).getStyle(name);
5213 * Compiles a selector/xpath query into a reusable function. The returned function
5214 * takes one parameter "root" (optional), which is the context node from where the query should start.
5215 * @param {String} selector The selector/xpath query
5216 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5217 * @return {Function}
5219 compile : function(path, type){
5220 type = type || "select";
5222 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5223 var q = path, mode, lq;
5224 var tk = Roo.DomQuery.matchers;
5225 var tklen = tk.length;
5228 // accept leading mode switch
5229 var lmode = q.match(modeRe);
5230 if(lmode && lmode[1]){
5231 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5232 q = q.replace(lmode[1], "");
5234 // strip leading slashes
5235 while(path.substr(0, 1)=="/"){
5236 path = path.substr(1);
5239 while(q && lq != q){
5241 var tm = q.match(tagTokenRe);
5242 if(type == "select"){
5245 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5247 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5249 q = q.replace(tm[0], "");
5250 }else if(q.substr(0, 1) != '@'){
5251 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5256 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5258 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5260 q = q.replace(tm[0], "");
5263 while(!(mm = q.match(modeRe))){
5264 var matched = false;
5265 for(var j = 0; j < tklen; j++){
5267 var m = q.match(t.re);
5269 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5272 q = q.replace(m[0], "");
5277 // prevent infinite loop on bad selector
5279 throw 'Error parsing selector, parsing failed at "' + q + '"';
5283 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5284 q = q.replace(mm[1], "");
5287 fn[fn.length] = "return nodup(n);\n}";
5290 * list of variables that need from compression as they are used by eval.
5300 * eval:var:byClassName
5302 * eval:var:byAttribute
5303 * eval:var:attrValue
5311 * Selects a group of elements.
5312 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5313 * @param {Node} root (optional) The start of the query (defaults to document).
5316 select : function(path, root, type){
5317 if(!root || root == document){
5320 if(typeof root == "string"){
5321 root = document.getElementById(root);
5323 var paths = path.split(",");
5325 for(var i = 0, len = paths.length; i < len; i++){
5326 var p = paths[i].replace(trimRe, "");
5328 cache[p] = Roo.DomQuery.compile(p);
5330 throw p + " is not a valid selector";
5333 var result = cache[p](root);
5334 if(result && result != document){
5335 results = results.concat(result);
5338 if(paths.length > 1){
5339 return nodup(results);
5345 * Selects a single element.
5346 * @param {String} selector The selector/xpath query
5347 * @param {Node} root (optional) The start of the query (defaults to document).
5350 selectNode : function(path, root){
5351 return Roo.DomQuery.select(path, root)[0];
5355 * Selects the value of a node, optionally replacing null with the defaultValue.
5356 * @param {String} selector The selector/xpath query
5357 * @param {Node} root (optional) The start of the query (defaults to document).
5358 * @param {String} defaultValue
5360 selectValue : function(path, root, defaultValue){
5361 path = path.replace(trimRe, "");
5362 if(!valueCache[path]){
5363 valueCache[path] = Roo.DomQuery.compile(path, "select");
5365 var n = valueCache[path](root);
5366 n = n[0] ? n[0] : n;
5367 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5368 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5372 * Selects the value of a node, parsing integers and floats.
5373 * @param {String} selector The selector/xpath query
5374 * @param {Node} root (optional) The start of the query (defaults to document).
5375 * @param {Number} defaultValue
5378 selectNumber : function(path, root, defaultValue){
5379 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5380 return parseFloat(v);
5384 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5385 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5386 * @param {String} selector The simple selector to test
5389 is : function(el, ss){
5390 if(typeof el == "string"){
5391 el = document.getElementById(el);
5393 var isArray = (el instanceof Array);
5394 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5395 return isArray ? (result.length == el.length) : (result.length > 0);
5399 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5400 * @param {Array} el An array of elements to filter
5401 * @param {String} selector The simple selector to test
5402 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5403 * the selector instead of the ones that match
5406 filter : function(els, ss, nonMatches){
5407 ss = ss.replace(trimRe, "");
5408 if(!simpleCache[ss]){
5409 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5411 var result = simpleCache[ss](els);
5412 return nonMatches ? quickDiff(result, els) : result;
5416 * Collection of matching regular expressions and code snippets.
5420 select: 'n = byClassName(n, null, " {1} ");'
5422 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5423 select: 'n = byPseudo(n, "{1}", "{2}");'
5425 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5426 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5429 select: 'n = byId(n, null, "{1}");'
5432 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5437 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5438 * 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, > <.
5441 "=" : function(a, v){
5444 "!=" : function(a, v){
5447 "^=" : function(a, v){
5448 return a && a.substr(0, v.length) == v;
5450 "$=" : function(a, v){
5451 return a && a.substr(a.length-v.length) == v;
5453 "*=" : function(a, v){
5454 return a && a.indexOf(v) !== -1;
5456 "%=" : function(a, v){
5457 return (a % v) == 0;
5459 "|=" : function(a, v){
5460 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5462 "~=" : function(a, v){
5463 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5468 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5469 * and the argument (if any) supplied in the selector.
5472 "first-child" : function(c){
5473 var r = [], ri = -1, n;
5474 for(var i = 0, ci; ci = n = c[i]; i++){
5475 while((n = n.previousSibling) && n.nodeType != 1);
5483 "last-child" : function(c){
5484 var r = [], ri = -1, n;
5485 for(var i = 0, ci; ci = n = c[i]; i++){
5486 while((n = n.nextSibling) && n.nodeType != 1);
5494 "nth-child" : function(c, a) {
5495 var r = [], ri = -1;
5496 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5497 var f = (m[1] || 1) - 0, l = m[2] - 0;
5498 for(var i = 0, n; n = c[i]; i++){
5499 var pn = n.parentNode;
5500 if (batch != pn._batch) {
5502 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5503 if(cn.nodeType == 1){
5510 if (l == 0 || n.nodeIndex == l){
5513 } else if ((n.nodeIndex + l) % f == 0){
5521 "only-child" : function(c){
5522 var r = [], ri = -1;;
5523 for(var i = 0, ci; ci = c[i]; i++){
5524 if(!prev(ci) && !next(ci)){
5531 "empty" : function(c){
5532 var r = [], ri = -1;
5533 for(var i = 0, ci; ci = c[i]; i++){
5534 var cns = ci.childNodes, j = 0, cn, empty = true;
5537 if(cn.nodeType == 1 || cn.nodeType == 3){
5549 "contains" : function(c, v){
5550 var r = [], ri = -1;
5551 for(var i = 0, ci; ci = c[i]; i++){
5552 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5559 "nodeValue" : function(c, v){
5560 var r = [], ri = -1;
5561 for(var i = 0, ci; ci = c[i]; i++){
5562 if(ci.firstChild && ci.firstChild.nodeValue == v){
5569 "checked" : function(c){
5570 var r = [], ri = -1;
5571 for(var i = 0, ci; ci = c[i]; i++){
5572 if(ci.checked == true){
5579 "not" : function(c, ss){
5580 return Roo.DomQuery.filter(c, ss, true);
5583 "odd" : function(c){
5584 return this["nth-child"](c, "odd");
5587 "even" : function(c){
5588 return this["nth-child"](c, "even");
5591 "nth" : function(c, a){
5592 return c[a-1] || [];
5595 "first" : function(c){
5599 "last" : function(c){
5600 return c[c.length-1] || [];
5603 "has" : function(c, ss){
5604 var s = Roo.DomQuery.select;
5605 var r = [], ri = -1;
5606 for(var i = 0, ci; ci = c[i]; i++){
5607 if(s(ss, ci).length > 0){
5614 "next" : function(c, ss){
5615 var is = Roo.DomQuery.is;
5616 var r = [], ri = -1;
5617 for(var i = 0, ci; ci = c[i]; i++){
5626 "prev" : function(c, ss){
5627 var is = Roo.DomQuery.is;
5628 var r = [], ri = -1;
5629 for(var i = 0, ci; ci = c[i]; i++){
5642 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5643 * @param {String} path The selector/xpath query
5644 * @param {Node} root (optional) The start of the query (defaults to document).
5649 Roo.query = Roo.DomQuery.select;
5652 * Ext JS Library 1.1.1
5653 * Copyright(c) 2006-2007, Ext JS, LLC.
5655 * Originally Released Under LGPL - original licence link has changed is not relivant.
5658 * <script type="text/javascript">
5662 * @class Roo.util.Observable
5663 * Base class that provides a common interface for publishing events. Subclasses are expected to
5664 * to have a property "events" with all the events defined.<br>
5667 Employee = function(name){
5674 Roo.extend(Employee, Roo.util.Observable);
5676 * @param {Object} config properties to use (incuding events / listeners)
5679 Roo.util.Observable = function(cfg){
5682 this.addEvents(cfg.events || {});
5684 delete cfg.events; // make sure
5687 Roo.apply(this, cfg);
5690 this.on(this.listeners);
5691 delete this.listeners;
5694 Roo.util.Observable.prototype = {
5696 * @cfg {Object} listeners list of events and functions to call for this object,
5700 'click' : function(e) {
5710 * Fires the specified event with the passed parameters (minus the event name).
5711 * @param {String} eventName
5712 * @param {Object...} args Variable number of parameters are passed to handlers
5713 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5715 fireEvent : function(){
5716 var ce = this.events[arguments[0].toLowerCase()];
5717 if(typeof ce == "object"){
5718 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5725 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5728 * Appends an event handler to this component
5729 * @param {String} eventName The type of event to listen for
5730 * @param {Function} handler The method the event invokes
5731 * @param {Object} scope (optional) The scope in which to execute the handler
5732 * function. The handler function's "this" context.
5733 * @param {Object} options (optional) An object containing handler configuration
5734 * properties. This may contain any of the following properties:<ul>
5735 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5736 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5737 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5738 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5739 * by the specified number of milliseconds. If the event fires again within that time, the original
5740 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5743 * <b>Combining Options</b><br>
5744 * Using the options argument, it is possible to combine different types of listeners:<br>
5746 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5748 el.on('click', this.onClick, this, {
5755 * <b>Attaching multiple handlers in 1 call</b><br>
5756 * The method also allows for a single argument to be passed which is a config object containing properties
5757 * which specify multiple handlers.
5766 fn: this.onMouseOver,
5770 fn: this.onMouseOut,
5776 * Or a shorthand syntax which passes the same scope object to all handlers:
5779 'click': this.onClick,
5780 'mouseover': this.onMouseOver,
5781 'mouseout': this.onMouseOut,
5786 addListener : function(eventName, fn, scope, o){
5787 if(typeof eventName == "object"){
5790 if(this.filterOptRe.test(e)){
5793 if(typeof o[e] == "function"){
5795 this.addListener(e, o[e], o.scope, o);
5797 // individual options
5798 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5803 o = (!o || typeof o == "boolean") ? {} : o;
5804 eventName = eventName.toLowerCase();
5805 var ce = this.events[eventName] || true;
5806 if(typeof ce == "boolean"){
5807 ce = new Roo.util.Event(this, eventName);
5808 this.events[eventName] = ce;
5810 ce.addListener(fn, scope, o);
5814 * Removes a listener
5815 * @param {String} eventName The type of event to listen for
5816 * @param {Function} handler The handler to remove
5817 * @param {Object} scope (optional) The scope (this object) for the handler
5819 removeListener : function(eventName, fn, scope){
5820 var ce = this.events[eventName.toLowerCase()];
5821 if(typeof ce == "object"){
5822 ce.removeListener(fn, scope);
5827 * Removes all listeners for this object
5829 purgeListeners : function(){
5830 for(var evt in this.events){
5831 if(typeof this.events[evt] == "object"){
5832 this.events[evt].clearListeners();
5837 relayEvents : function(o, events){
5838 var createHandler = function(ename){
5840 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5843 for(var i = 0, len = events.length; i < len; i++){
5844 var ename = events[i];
5845 if(!this.events[ename]){ this.events[ename] = true; };
5846 o.on(ename, createHandler(ename), this);
5851 * Used to define events on this Observable
5852 * @param {Object} object The object with the events defined
5854 addEvents : function(o){
5858 Roo.applyIf(this.events, o);
5862 * Checks to see if this object has any listeners for a specified event
5863 * @param {String} eventName The name of the event to check for
5864 * @return {Boolean} True if the event is being listened for, else false
5866 hasListener : function(eventName){
5867 var e = this.events[eventName];
5868 return typeof e == "object" && e.listeners.length > 0;
5872 * Appends an event handler to this element (shorthand for addListener)
5873 * @param {String} eventName The type of event to listen for
5874 * @param {Function} handler The method the event invokes
5875 * @param {Object} scope (optional) The scope in which to execute the handler
5876 * function. The handler function's "this" context.
5877 * @param {Object} options (optional)
5880 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5882 * Removes a listener (shorthand for removeListener)
5883 * @param {String} eventName The type of event to listen for
5884 * @param {Function} handler The handler to remove
5885 * @param {Object} scope (optional) The scope (this object) for the handler
5888 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5891 * Starts capture on the specified Observable. All events will be passed
5892 * to the supplied function with the event name + standard signature of the event
5893 * <b>before</b> the event is fired. If the supplied function returns false,
5894 * the event will not fire.
5895 * @param {Observable} o The Observable to capture
5896 * @param {Function} fn The function to call
5897 * @param {Object} scope (optional) The scope (this object) for the fn
5900 Roo.util.Observable.capture = function(o, fn, scope){
5901 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5905 * Removes <b>all</b> added captures from the Observable.
5906 * @param {Observable} o The Observable to release
5909 Roo.util.Observable.releaseCapture = function(o){
5910 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5915 var createBuffered = function(h, o, scope){
5916 var task = new Roo.util.DelayedTask();
5918 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5922 var createSingle = function(h, e, fn, scope){
5924 e.removeListener(fn, scope);
5925 return h.apply(scope, arguments);
5929 var createDelayed = function(h, o, scope){
5931 var args = Array.prototype.slice.call(arguments, 0);
5932 setTimeout(function(){
5933 h.apply(scope, args);
5938 Roo.util.Event = function(obj, name){
5941 this.listeners = [];
5944 Roo.util.Event.prototype = {
5945 addListener : function(fn, scope, options){
5946 var o = options || {};
5947 scope = scope || this.obj;
5948 if(!this.isListening(fn, scope)){
5949 var l = {fn: fn, scope: scope, options: o};
5952 h = createDelayed(h, o, scope);
5955 h = createSingle(h, this, fn, scope);
5958 h = createBuffered(h, o, scope);
5961 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5962 this.listeners.push(l);
5964 this.listeners = this.listeners.slice(0);
5965 this.listeners.push(l);
5970 findListener : function(fn, scope){
5971 scope = scope || this.obj;
5972 var ls = this.listeners;
5973 for(var i = 0, len = ls.length; i < len; i++){
5975 if(l.fn == fn && l.scope == scope){
5982 isListening : function(fn, scope){
5983 return this.findListener(fn, scope) != -1;
5986 removeListener : function(fn, scope){
5988 if((index = this.findListener(fn, scope)) != -1){
5990 this.listeners.splice(index, 1);
5992 this.listeners = this.listeners.slice(0);
5993 this.listeners.splice(index, 1);
6000 clearListeners : function(){
6001 this.listeners = [];
6005 var ls = this.listeners, scope, len = ls.length;
6008 var args = Array.prototype.slice.call(arguments, 0);
6009 for(var i = 0; i < len; i++){
6011 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6012 this.firing = false;
6016 this.firing = false;
6023 * Ext JS Library 1.1.1
6024 * Copyright(c) 2006-2007, Ext JS, LLC.
6026 * Originally Released Under LGPL - original licence link has changed is not relivant.
6029 * <script type="text/javascript">
6033 * @class Roo.EventManager
6034 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6035 * several useful events directly.
6036 * See {@link Roo.EventObject} for more details on normalized event objects.
6039 Roo.EventManager = function(){
6040 var docReadyEvent, docReadyProcId, docReadyState = false;
6041 var resizeEvent, resizeTask, textEvent, textSize;
6042 var E = Roo.lib.Event;
6043 var D = Roo.lib.Dom;
6046 var fireDocReady = function(){
6048 docReadyState = true;
6051 clearInterval(docReadyProcId);
6053 if(Roo.isGecko || Roo.isOpera) {
6054 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6057 var defer = document.getElementById("ie-deferred-loader");
6059 defer.onreadystatechange = null;
6060 defer.parentNode.removeChild(defer);
6064 docReadyEvent.fire();
6065 docReadyEvent.clearListeners();
6070 var initDocReady = function(){
6071 docReadyEvent = new Roo.util.Event();
6072 if(Roo.isGecko || Roo.isOpera) {
6073 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6075 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6076 var defer = document.getElementById("ie-deferred-loader");
6077 defer.onreadystatechange = function(){
6078 if(this.readyState == "complete"){
6082 }else if(Roo.isSafari){
6083 docReadyProcId = setInterval(function(){
6084 var rs = document.readyState;
6085 if(rs == "complete") {
6090 // no matter what, make sure it fires on load
6091 E.on(window, "load", fireDocReady);
6094 var createBuffered = function(h, o){
6095 var task = new Roo.util.DelayedTask(h);
6097 // create new event object impl so new events don't wipe out properties
6098 e = new Roo.EventObjectImpl(e);
6099 task.delay(o.buffer, h, null, [e]);
6103 var createSingle = function(h, el, ename, fn){
6105 Roo.EventManager.removeListener(el, ename, fn);
6110 var createDelayed = function(h, o){
6112 // create new event object impl so new events don't wipe out properties
6113 e = new Roo.EventObjectImpl(e);
6114 setTimeout(function(){
6120 var listen = function(element, ename, opt, fn, scope){
6121 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6122 fn = fn || o.fn; scope = scope || o.scope;
6123 var el = Roo.getDom(element);
6125 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6127 var h = function(e){
6128 e = Roo.EventObject.setEvent(e);
6131 t = e.getTarget(o.delegate, el);
6138 if(o.stopEvent === true){
6141 if(o.preventDefault === true){
6144 if(o.stopPropagation === true){
6145 e.stopPropagation();
6148 if(o.normalized === false){
6152 fn.call(scope || el, e, t, o);
6155 h = createDelayed(h, o);
6158 h = createSingle(h, el, ename, fn);
6161 h = createBuffered(h, o);
6163 fn._handlers = fn._handlers || [];
6164 fn._handlers.push([Roo.id(el), ename, h]);
6167 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6168 el.addEventListener("DOMMouseScroll", h, false);
6169 E.on(window, 'unload', function(){
6170 el.removeEventListener("DOMMouseScroll", h, false);
6173 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6174 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6179 var stopListening = function(el, ename, fn){
6180 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6182 for(var i = 0, len = hds.length; i < len; i++){
6184 if(h[0] == id && h[1] == ename){
6191 E.un(el, ename, hd);
6192 el = Roo.getDom(el);
6193 if(ename == "mousewheel" && el.addEventListener){
6194 el.removeEventListener("DOMMouseScroll", hd, false);
6196 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6197 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6201 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6208 * @scope Roo.EventManager
6213 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6214 * object with a Roo.EventObject
6215 * @param {Function} fn The method the event invokes
6216 * @param {Object} scope An object that becomes the scope of the handler
6217 * @param {boolean} override If true, the obj passed in becomes
6218 * the execution scope of the listener
6219 * @return {Function} The wrapped function
6222 wrap : function(fn, scope, override){
6224 Roo.EventObject.setEvent(e);
6225 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6230 * Appends an event handler to an element (shorthand for addListener)
6231 * @param {String/HTMLElement} element The html element or id to assign the
6232 * @param {String} eventName The type of event to listen for
6233 * @param {Function} handler The method the event invokes
6234 * @param {Object} scope (optional) The scope in which to execute the handler
6235 * function. The handler function's "this" context.
6236 * @param {Object} options (optional) An object containing handler configuration
6237 * properties. This may contain any of the following properties:<ul>
6238 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6239 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6240 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6241 * <li>preventDefault {Boolean} True to prevent the default action</li>
6242 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6243 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6244 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6245 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6246 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6247 * by the specified number of milliseconds. If the event fires again within that time, the original
6248 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6251 * <b>Combining Options</b><br>
6252 * Using the options argument, it is possible to combine different types of listeners:<br>
6254 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6256 el.on('click', this.onClick, this, {
6263 * <b>Attaching multiple handlers in 1 call</b><br>
6264 * The method also allows for a single argument to be passed which is a config object containing properties
6265 * which specify multiple handlers.
6275 fn: this.onMouseOver
6284 * Or a shorthand syntax:<br>
6287 'click' : this.onClick,
6288 'mouseover' : this.onMouseOver,
6289 'mouseout' : this.onMouseOut
6293 addListener : function(element, eventName, fn, scope, options){
6294 if(typeof eventName == "object"){
6300 if(typeof o[e] == "function"){
6302 listen(element, e, o, o[e], o.scope);
6304 // individual options
6305 listen(element, e, o[e]);
6310 return listen(element, eventName, options, fn, scope);
6314 * Removes an event handler
6316 * @param {String/HTMLElement} element The id or html element to remove the
6318 * @param {String} eventName The type of event
6319 * @param {Function} fn
6320 * @return {Boolean} True if a listener was actually removed
6322 removeListener : function(element, eventName, fn){
6323 return stopListening(element, eventName, fn);
6327 * Fires when the document is ready (before onload and before images are loaded). Can be
6328 * accessed shorthanded Roo.onReady().
6329 * @param {Function} fn The method the event invokes
6330 * @param {Object} scope An object that becomes the scope of the handler
6331 * @param {boolean} options
6333 onDocumentReady : function(fn, scope, options){
6334 if(docReadyState){ // if it already fired
6335 docReadyEvent.addListener(fn, scope, options);
6336 docReadyEvent.fire();
6337 docReadyEvent.clearListeners();
6343 docReadyEvent.addListener(fn, scope, options);
6347 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6348 * @param {Function} fn The method the event invokes
6349 * @param {Object} scope An object that becomes the scope of the handler
6350 * @param {boolean} options
6352 onWindowResize : function(fn, scope, options){
6354 resizeEvent = new Roo.util.Event();
6355 resizeTask = new Roo.util.DelayedTask(function(){
6356 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6358 E.on(window, "resize", function(){
6360 resizeTask.delay(50);
6362 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6366 resizeEvent.addListener(fn, scope, options);
6370 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6371 * @param {Function} fn The method the event invokes
6372 * @param {Object} scope An object that becomes the scope of the handler
6373 * @param {boolean} options
6375 onTextResize : function(fn, scope, options){
6377 textEvent = new Roo.util.Event();
6378 var textEl = new Roo.Element(document.createElement('div'));
6379 textEl.dom.className = 'x-text-resize';
6380 textEl.dom.innerHTML = 'X';
6381 textEl.appendTo(document.body);
6382 textSize = textEl.dom.offsetHeight;
6383 setInterval(function(){
6384 if(textEl.dom.offsetHeight != textSize){
6385 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6387 }, this.textResizeInterval);
6389 textEvent.addListener(fn, scope, options);
6393 * Removes the passed window resize listener.
6394 * @param {Function} fn The method the event invokes
6395 * @param {Object} scope The scope of handler
6397 removeResizeListener : function(fn, scope){
6399 resizeEvent.removeListener(fn, scope);
6404 fireResize : function(){
6406 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6410 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6414 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6416 textResizeInterval : 50
6421 * @scopeAlias pub=Roo.EventManager
6425 * Appends an event handler to an element (shorthand for addListener)
6426 * @param {String/HTMLElement} element The html element or id to assign the
6427 * @param {String} eventName The type of event to listen for
6428 * @param {Function} handler The method the event invokes
6429 * @param {Object} scope (optional) The scope in which to execute the handler
6430 * function. The handler function's "this" context.
6431 * @param {Object} options (optional) An object containing handler configuration
6432 * properties. This may contain any of the following properties:<ul>
6433 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6434 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6435 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6436 * <li>preventDefault {Boolean} True to prevent the default action</li>
6437 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6438 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6439 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6440 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6441 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6442 * by the specified number of milliseconds. If the event fires again within that time, the original
6443 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6446 * <b>Combining Options</b><br>
6447 * Using the options argument, it is possible to combine different types of listeners:<br>
6449 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6451 el.on('click', this.onClick, this, {
6458 * <b>Attaching multiple handlers in 1 call</b><br>
6459 * The method also allows for a single argument to be passed which is a config object containing properties
6460 * which specify multiple handlers.
6470 fn: this.onMouseOver
6479 * Or a shorthand syntax:<br>
6482 'click' : this.onClick,
6483 'mouseover' : this.onMouseOver,
6484 'mouseout' : this.onMouseOut
6488 pub.on = pub.addListener;
6489 pub.un = pub.removeListener;
6491 pub.stoppedMouseDownEvent = new Roo.util.Event();
6495 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6496 * @param {Function} fn The method the event invokes
6497 * @param {Object} scope An object that becomes the scope of the handler
6498 * @param {boolean} override If true, the obj passed in becomes
6499 * the execution scope of the listener
6503 Roo.onReady = Roo.EventManager.onDocumentReady;
6505 Roo.onReady(function(){
6506 var bd = Roo.get(document.body);
6511 : Roo.isGecko ? "roo-gecko"
6512 : Roo.isOpera ? "roo-opera"
6513 : Roo.isSafari ? "roo-safari" : ""];
6516 cls.push("roo-mac");
6519 cls.push("roo-linux");
6521 if(Roo.isBorderBox){
6522 cls.push('roo-border-box');
6524 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6525 var p = bd.dom.parentNode;
6527 p.className += ' roo-strict';
6530 bd.addClass(cls.join(' '));
6534 * @class Roo.EventObject
6535 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6536 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6539 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6541 var target = e.getTarget();
6544 var myDiv = Roo.get("myDiv");
6545 myDiv.on("click", handleClick);
6547 Roo.EventManager.on("myDiv", 'click', handleClick);
6548 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6552 Roo.EventObject = function(){
6554 var E = Roo.lib.Event;
6556 // safari keypress events for special keys return bad keycodes
6559 63235 : 39, // right
6562 63276 : 33, // page up
6563 63277 : 34, // page down
6564 63272 : 46, // delete
6569 // normalize button clicks
6570 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6571 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6573 Roo.EventObjectImpl = function(e){
6575 this.setEvent(e.browserEvent || e);
6578 Roo.EventObjectImpl.prototype = {
6580 * Used to fix doc tools.
6581 * @scope Roo.EventObject.prototype
6587 /** The normal browser event */
6588 browserEvent : null,
6589 /** The button pressed in a mouse event */
6591 /** True if the shift key was down during the event */
6593 /** True if the control key was down during the event */
6595 /** True if the alt key was down during the event */
6654 setEvent : function(e){
6655 if(e == this || (e && e.browserEvent)){ // already wrapped
6658 this.browserEvent = e;
6660 // normalize buttons
6661 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6662 if(e.type == 'click' && this.button == -1){
6666 this.shiftKey = e.shiftKey;
6667 // mac metaKey behaves like ctrlKey
6668 this.ctrlKey = e.ctrlKey || e.metaKey;
6669 this.altKey = e.altKey;
6670 // in getKey these will be normalized for the mac
6671 this.keyCode = e.keyCode;
6672 // keyup warnings on firefox.
6673 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6674 // cache the target for the delayed and or buffered events
6675 this.target = E.getTarget(e);
6677 this.xy = E.getXY(e);
6680 this.shiftKey = false;
6681 this.ctrlKey = false;
6682 this.altKey = false;
6692 * Stop the event (preventDefault and stopPropagation)
6694 stopEvent : function(){
6695 if(this.browserEvent){
6696 if(this.browserEvent.type == 'mousedown'){
6697 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6699 E.stopEvent(this.browserEvent);
6704 * Prevents the browsers default handling of the event.
6706 preventDefault : function(){
6707 if(this.browserEvent){
6708 E.preventDefault(this.browserEvent);
6713 isNavKeyPress : function(){
6714 var k = this.keyCode;
6715 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6716 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6719 isSpecialKey : function(){
6720 var k = this.keyCode;
6721 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6722 (k == 16) || (k == 17) ||
6723 (k >= 18 && k <= 20) ||
6724 (k >= 33 && k <= 35) ||
6725 (k >= 36 && k <= 39) ||
6726 (k >= 44 && k <= 45);
6729 * Cancels bubbling of the event.
6731 stopPropagation : function(){
6732 if(this.browserEvent){
6733 if(this.type == 'mousedown'){
6734 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6736 E.stopPropagation(this.browserEvent);
6741 * Gets the key code for the event.
6744 getCharCode : function(){
6745 return this.charCode || this.keyCode;
6749 * Returns a normalized keyCode for the event.
6750 * @return {Number} The key code
6752 getKey : function(){
6753 var k = this.keyCode || this.charCode;
6754 return Roo.isSafari ? (safariKeys[k] || k) : k;
6758 * Gets the x coordinate of the event.
6761 getPageX : function(){
6766 * Gets the y coordinate of the event.
6769 getPageY : function(){
6774 * Gets the time of the event.
6777 getTime : function(){
6778 if(this.browserEvent){
6779 return E.getTime(this.browserEvent);
6785 * Gets the page coordinates of the event.
6786 * @return {Array} The xy values like [x, y]
6793 * Gets the target for the event.
6794 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6795 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6796 search as a number or element (defaults to 10 || document.body)
6797 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6798 * @return {HTMLelement}
6800 getTarget : function(selector, maxDepth, returnEl){
6801 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6804 * Gets the related target.
6805 * @return {HTMLElement}
6807 getRelatedTarget : function(){
6808 if(this.browserEvent){
6809 return E.getRelatedTarget(this.browserEvent);
6815 * Normalizes mouse wheel delta across browsers
6816 * @return {Number} The delta
6818 getWheelDelta : function(){
6819 var e = this.browserEvent;
6821 if(e.wheelDelta){ /* IE/Opera. */
6822 delta = e.wheelDelta/120;
6823 }else if(e.detail){ /* Mozilla case. */
6824 delta = -e.detail/3;
6830 * Returns true if the control, meta, shift or alt key was pressed during this event.
6833 hasModifier : function(){
6834 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6838 * Returns true if the target of this event equals el or is a child of el
6839 * @param {String/HTMLElement/Element} el
6840 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6843 within : function(el, related){
6844 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6845 return t && Roo.fly(el).contains(t);
6848 getPoint : function(){
6849 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6853 return new Roo.EventObjectImpl();
6858 * Ext JS Library 1.1.1
6859 * Copyright(c) 2006-2007, Ext JS, LLC.
6861 * Originally Released Under LGPL - original licence link has changed is not relivant.
6864 * <script type="text/javascript">
6868 // was in Composite Element!??!?!
6871 var D = Roo.lib.Dom;
6872 var E = Roo.lib.Event;
6873 var A = Roo.lib.Anim;
6875 // local style camelizing for speed
6877 var camelRe = /(-[a-z])/gi;
6878 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6879 var view = document.defaultView;
6882 * @class Roo.Element
6883 * Represents an Element in the DOM.<br><br>
6886 var el = Roo.get("my-div");
6889 var el = getEl("my-div");
6891 // or with a DOM element
6892 var el = Roo.get(myDivElement);
6894 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6895 * each call instead of constructing a new one.<br><br>
6896 * <b>Animations</b><br />
6897 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6898 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6900 Option Default Description
6901 --------- -------- ---------------------------------------------
6902 duration .35 The duration of the animation in seconds
6903 easing easeOut The YUI easing method
6904 callback none A function to execute when the anim completes
6905 scope this The scope (this) of the callback function
6907 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6908 * manipulate the animation. Here's an example:
6910 var el = Roo.get("my-div");
6915 // default animation
6916 el.setWidth(100, true);
6918 // animation with some options set
6925 // using the "anim" property to get the Anim object
6931 el.setWidth(100, opt);
6933 if(opt.anim.isAnimated()){
6937 * <b> Composite (Collections of) Elements</b><br />
6938 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6939 * @constructor Create a new Element directly.
6940 * @param {String/HTMLElement} element
6941 * @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).
6943 Roo.Element = function(element, forceNew){
6944 var dom = typeof element == "string" ?
6945 document.getElementById(element) : element;
6946 if(!dom){ // invalid id/element
6950 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6951 return Roo.Element.cache[id];
6961 * The DOM element ID
6964 this.id = id || Roo.id(dom);
6967 var El = Roo.Element;
6971 * The element's default display mode (defaults to "")
6974 originalDisplay : "",
6978 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6983 * Sets the element's visibility mode. When setVisible() is called it
6984 * will use this to determine whether to set the visibility or the display property.
6985 * @param visMode Element.VISIBILITY or Element.DISPLAY
6986 * @return {Roo.Element} this
6988 setVisibilityMode : function(visMode){
6989 this.visibilityMode = visMode;
6993 * Convenience method for setVisibilityMode(Element.DISPLAY)
6994 * @param {String} display (optional) What to set display to when visible
6995 * @return {Roo.Element} this
6997 enableDisplayMode : function(display){
6998 this.setVisibilityMode(El.DISPLAY);
6999 if(typeof display != "undefined") this.originalDisplay = display;
7004 * 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)
7005 * @param {String} selector The simple selector to test
7006 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7007 search as a number or element (defaults to 10 || document.body)
7008 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7009 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7011 findParent : function(simpleSelector, maxDepth, returnEl){
7012 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7013 maxDepth = maxDepth || 50;
7014 if(typeof maxDepth != "number"){
7015 stopEl = Roo.getDom(maxDepth);
7018 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7019 if(dq.is(p, simpleSelector)){
7020 return returnEl ? Roo.get(p) : p;
7030 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7031 * @param {String} selector The simple selector to test
7032 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7033 search as a number or element (defaults to 10 || document.body)
7034 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7035 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7037 findParentNode : function(simpleSelector, maxDepth, returnEl){
7038 var p = Roo.fly(this.dom.parentNode, '_internal');
7039 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7043 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7044 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7045 * @param {String} selector The simple selector to test
7046 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7047 search as a number or element (defaults to 10 || document.body)
7048 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7050 up : function(simpleSelector, maxDepth){
7051 return this.findParentNode(simpleSelector, maxDepth, true);
7057 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7058 * @param {String} selector The simple selector to test
7059 * @return {Boolean} True if this element matches the selector, else false
7061 is : function(simpleSelector){
7062 return Roo.DomQuery.is(this.dom, simpleSelector);
7066 * Perform animation on this element.
7067 * @param {Object} args The YUI animation control args
7068 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7069 * @param {Function} onComplete (optional) Function to call when animation completes
7070 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7071 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7072 * @return {Roo.Element} this
7074 animate : function(args, duration, onComplete, easing, animType){
7075 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7080 * @private Internal animation call
7082 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7083 animType = animType || 'run';
7085 var anim = Roo.lib.Anim[animType](
7087 (opt.duration || defaultDur) || .35,
7088 (opt.easing || defaultEase) || 'easeOut',
7090 Roo.callback(cb, this);
7091 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7099 // private legacy anim prep
7100 preanim : function(a, i){
7101 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7105 * Removes worthless text nodes
7106 * @param {Boolean} forceReclean (optional) By default the element
7107 * keeps track if it has been cleaned already so
7108 * you can call this over and over. However, if you update the element and
7109 * need to force a reclean, you can pass true.
7111 clean : function(forceReclean){
7112 if(this.isCleaned && forceReclean !== true){
7116 var d = this.dom, n = d.firstChild, ni = -1;
7118 var nx = n.nextSibling;
7119 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7126 this.isCleaned = true;
7131 calcOffsetsTo : function(el){
7134 var restorePos = false;
7135 if(el.getStyle('position') == 'static'){
7136 el.position('relative');
7141 while(op && op != d && op.tagName != 'HTML'){
7144 op = op.offsetParent;
7147 el.position('static');
7153 * Scrolls this element into view within the passed container.
7154 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7155 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7156 * @return {Roo.Element} this
7158 scrollIntoView : function(container, hscroll){
7159 var c = Roo.getDom(container) || document.body;
7162 var o = this.calcOffsetsTo(c),
7165 b = t+el.offsetHeight,
7166 r = l+el.offsetWidth;
7168 var ch = c.clientHeight;
7169 var ct = parseInt(c.scrollTop, 10);
7170 var cl = parseInt(c.scrollLeft, 10);
7172 var cr = cl + c.clientWidth;
7180 if(hscroll !== false){
7184 c.scrollLeft = r-c.clientWidth;
7191 scrollChildIntoView : function(child, hscroll){
7192 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7196 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7197 * the new height may not be available immediately.
7198 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7199 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7200 * @param {Function} onComplete (optional) Function to call when animation completes
7201 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7202 * @return {Roo.Element} this
7204 autoHeight : function(animate, duration, onComplete, easing){
7205 var oldHeight = this.getHeight();
7207 this.setHeight(1); // force clipping
7208 setTimeout(function(){
7209 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7211 this.setHeight(height);
7213 if(typeof onComplete == "function"){
7217 this.setHeight(oldHeight); // restore original height
7218 this.setHeight(height, animate, duration, function(){
7220 if(typeof onComplete == "function") onComplete();
7221 }.createDelegate(this), easing);
7223 }.createDelegate(this), 0);
7228 * Returns true if this element is an ancestor of the passed element
7229 * @param {HTMLElement/String} el The element to check
7230 * @return {Boolean} True if this element is an ancestor of el, else false
7232 contains : function(el){
7233 if(!el){return false;}
7234 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7238 * Checks whether the element is currently visible using both visibility and display properties.
7239 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7240 * @return {Boolean} True if the element is currently visible, else false
7242 isVisible : function(deep) {
7243 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7244 if(deep !== true || !vis){
7247 var p = this.dom.parentNode;
7248 while(p && p.tagName.toLowerCase() != "body"){
7249 if(!Roo.fly(p, '_isVisible').isVisible()){
7258 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7259 * @param {String} selector The CSS selector
7260 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7261 * @return {CompositeElement/CompositeElementLite} The composite element
7263 select : function(selector, unique){
7264 return El.select(selector, unique, this.dom);
7268 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7269 * @param {String} selector The CSS selector
7270 * @return {Array} An array of the matched nodes
7272 query : function(selector, unique){
7273 return Roo.DomQuery.select(selector, this.dom);
7277 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7278 * @param {String} selector The CSS selector
7279 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7280 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7282 child : function(selector, returnDom){
7283 var n = Roo.DomQuery.selectNode(selector, this.dom);
7284 return returnDom ? n : Roo.get(n);
7288 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7289 * @param {String} selector The CSS selector
7290 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7291 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7293 down : function(selector, returnDom){
7294 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7295 return returnDom ? n : Roo.get(n);
7299 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7300 * @param {String} group The group the DD object is member of
7301 * @param {Object} config The DD config object
7302 * @param {Object} overrides An object containing methods to override/implement on the DD object
7303 * @return {Roo.dd.DD} The DD object
7305 initDD : function(group, config, overrides){
7306 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7307 return Roo.apply(dd, overrides);
7311 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7312 * @param {String} group The group the DDProxy object is member of
7313 * @param {Object} config The DDProxy config object
7314 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7315 * @return {Roo.dd.DDProxy} The DDProxy object
7317 initDDProxy : function(group, config, overrides){
7318 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7319 return Roo.apply(dd, overrides);
7323 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7324 * @param {String} group The group the DDTarget object is member of
7325 * @param {Object} config The DDTarget config object
7326 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7327 * @return {Roo.dd.DDTarget} The DDTarget object
7329 initDDTarget : function(group, config, overrides){
7330 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7331 return Roo.apply(dd, overrides);
7335 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7336 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7337 * @param {Boolean} visible Whether the element is visible
7338 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7339 * @return {Roo.Element} this
7341 setVisible : function(visible, animate){
7343 if(this.visibilityMode == El.DISPLAY){
7344 this.setDisplayed(visible);
7347 this.dom.style.visibility = visible ? "visible" : "hidden";
7350 // closure for composites
7352 var visMode = this.visibilityMode;
7354 this.setOpacity(.01);
7355 this.setVisible(true);
7357 this.anim({opacity: { to: (visible?1:0) }},
7358 this.preanim(arguments, 1),
7359 null, .35, 'easeIn', function(){
7361 if(visMode == El.DISPLAY){
7362 dom.style.display = "none";
7364 dom.style.visibility = "hidden";
7366 Roo.get(dom).setOpacity(1);
7374 * Returns true if display is not "none"
7377 isDisplayed : function() {
7378 return this.getStyle("display") != "none";
7382 * Toggles the element's visibility or display, depending on visibility mode.
7383 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7384 * @return {Roo.Element} this
7386 toggle : function(animate){
7387 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7392 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7393 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7394 * @return {Roo.Element} this
7396 setDisplayed : function(value) {
7397 if(typeof value == "boolean"){
7398 value = value ? this.originalDisplay : "none";
7400 this.setStyle("display", value);
7405 * Tries to focus the element. Any exceptions are caught and ignored.
7406 * @return {Roo.Element} this
7408 focus : function() {
7416 * Tries to blur the element. Any exceptions are caught and ignored.
7417 * @return {Roo.Element} this
7427 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7428 * @param {String/Array} className The CSS class to add, or an array of classes
7429 * @return {Roo.Element} this
7431 addClass : function(className){
7432 if(className instanceof Array){
7433 for(var i = 0, len = className.length; i < len; i++) {
7434 this.addClass(className[i]);
7437 if(className && !this.hasClass(className)){
7438 this.dom.className = this.dom.className + " " + className;
7445 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7446 * @param {String/Array} className The CSS class to add, or an array of classes
7447 * @return {Roo.Element} this
7449 radioClass : function(className){
7450 var siblings = this.dom.parentNode.childNodes;
7451 for(var i = 0; i < siblings.length; i++) {
7452 var s = siblings[i];
7453 if(s.nodeType == 1){
7454 Roo.get(s).removeClass(className);
7457 this.addClass(className);
7462 * Removes one or more CSS classes from the element.
7463 * @param {String/Array} className The CSS class to remove, or an array of classes
7464 * @return {Roo.Element} this
7466 removeClass : function(className){
7467 if(!className || !this.dom.className){
7470 if(className instanceof Array){
7471 for(var i = 0, len = className.length; i < len; i++) {
7472 this.removeClass(className[i]);
7475 if(this.hasClass(className)){
7476 var re = this.classReCache[className];
7478 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7479 this.classReCache[className] = re;
7481 this.dom.className =
7482 this.dom.className.replace(re, " ");
7492 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7493 * @param {String} className The CSS class to toggle
7494 * @return {Roo.Element} this
7496 toggleClass : function(className){
7497 if(this.hasClass(className)){
7498 this.removeClass(className);
7500 this.addClass(className);
7506 * Checks if the specified CSS class exists on this element's DOM node.
7507 * @param {String} className The CSS class to check for
7508 * @return {Boolean} True if the class exists, else false
7510 hasClass : function(className){
7511 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7515 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7516 * @param {String} oldClassName The CSS class to replace
7517 * @param {String} newClassName The replacement CSS class
7518 * @return {Roo.Element} this
7520 replaceClass : function(oldClassName, newClassName){
7521 this.removeClass(oldClassName);
7522 this.addClass(newClassName);
7527 * Returns an object with properties matching the styles requested.
7528 * For example, el.getStyles('color', 'font-size', 'width') might return
7529 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7530 * @param {String} style1 A style name
7531 * @param {String} style2 A style name
7532 * @param {String} etc.
7533 * @return {Object} The style object
7535 getStyles : function(){
7536 var a = arguments, len = a.length, r = {};
7537 for(var i = 0; i < len; i++){
7538 r[a[i]] = this.getStyle(a[i]);
7544 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7545 * @param {String} property The style property whose value is returned.
7546 * @return {String} The current value of the style property for this element.
7548 getStyle : function(){
7549 return view && view.getComputedStyle ?
7551 var el = this.dom, v, cs, camel;
7552 if(prop == 'float'){
7555 if(el.style && (v = el.style[prop])){
7558 if(cs = view.getComputedStyle(el, "")){
7559 if(!(camel = propCache[prop])){
7560 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7567 var el = this.dom, v, cs, camel;
7568 if(prop == 'opacity'){
7569 if(typeof el.style.filter == 'string'){
7570 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7572 var fv = parseFloat(m[1]);
7574 return fv ? fv / 100 : 0;
7579 }else if(prop == 'float'){
7580 prop = "styleFloat";
7582 if(!(camel = propCache[prop])){
7583 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7585 if(v = el.style[camel]){
7588 if(cs = el.currentStyle){
7596 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7597 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7598 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7599 * @return {Roo.Element} this
7601 setStyle : function(prop, value){
7602 if(typeof prop == "string"){
7604 if (prop == 'float') {
7605 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7610 if(!(camel = propCache[prop])){
7611 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7614 if(camel == 'opacity') {
7615 this.setOpacity(value);
7617 this.dom.style[camel] = value;
7620 for(var style in prop){
7621 if(typeof prop[style] != "function"){
7622 this.setStyle(style, prop[style]);
7630 * More flexible version of {@link #setStyle} for setting style properties.
7631 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7632 * a function which returns such a specification.
7633 * @return {Roo.Element} this
7635 applyStyles : function(style){
7636 Roo.DomHelper.applyStyles(this.dom, style);
7641 * 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).
7642 * @return {Number} The X position of the element
7645 return D.getX(this.dom);
7649 * 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).
7650 * @return {Number} The Y position of the element
7653 return D.getY(this.dom);
7657 * 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).
7658 * @return {Array} The XY position of the element
7661 return D.getXY(this.dom);
7665 * 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).
7666 * @param {Number} The X position of the element
7667 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7668 * @return {Roo.Element} this
7670 setX : function(x, animate){
7672 D.setX(this.dom, x);
7674 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7680 * 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).
7681 * @param {Number} The Y position of the element
7682 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7683 * @return {Roo.Element} this
7685 setY : function(y, animate){
7687 D.setY(this.dom, y);
7689 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7695 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7696 * @param {String} left The left CSS property value
7697 * @return {Roo.Element} this
7699 setLeft : function(left){
7700 this.setStyle("left", this.addUnits(left));
7705 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7706 * @param {String} top The top CSS property value
7707 * @return {Roo.Element} this
7709 setTop : function(top){
7710 this.setStyle("top", this.addUnits(top));
7715 * Sets the element's CSS right style.
7716 * @param {String} right The right CSS property value
7717 * @return {Roo.Element} this
7719 setRight : function(right){
7720 this.setStyle("right", this.addUnits(right));
7725 * Sets the element's CSS bottom style.
7726 * @param {String} bottom The bottom CSS property value
7727 * @return {Roo.Element} this
7729 setBottom : function(bottom){
7730 this.setStyle("bottom", this.addUnits(bottom));
7735 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7736 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7737 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7738 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7739 * @return {Roo.Element} this
7741 setXY : function(pos, animate){
7743 D.setXY(this.dom, pos);
7745 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7751 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7752 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7753 * @param {Number} x X value for new position (coordinates are page-based)
7754 * @param {Number} y Y value for new position (coordinates are page-based)
7755 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7756 * @return {Roo.Element} this
7758 setLocation : function(x, y, animate){
7759 this.setXY([x, y], this.preanim(arguments, 2));
7764 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7765 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7766 * @param {Number} x X value for new position (coordinates are page-based)
7767 * @param {Number} y Y value for new position (coordinates are page-based)
7768 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7769 * @return {Roo.Element} this
7771 moveTo : function(x, y, animate){
7772 this.setXY([x, y], this.preanim(arguments, 2));
7777 * Returns the region of the given element.
7778 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7779 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7781 getRegion : function(){
7782 return D.getRegion(this.dom);
7786 * Returns the offset height of the element
7787 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7788 * @return {Number} The element's height
7790 getHeight : function(contentHeight){
7791 var h = this.dom.offsetHeight || 0;
7792 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7796 * Returns the offset width of the element
7797 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7798 * @return {Number} The element's width
7800 getWidth : function(contentWidth){
7801 var w = this.dom.offsetWidth || 0;
7802 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7806 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7807 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7808 * if a height has not been set using CSS.
7811 getComputedHeight : function(){
7812 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7814 h = parseInt(this.getStyle('height'), 10) || 0;
7815 if(!this.isBorderBox()){
7816 h += this.getFrameWidth('tb');
7823 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7824 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7825 * if a width has not been set using CSS.
7828 getComputedWidth : function(){
7829 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7831 w = parseInt(this.getStyle('width'), 10) || 0;
7832 if(!this.isBorderBox()){
7833 w += this.getFrameWidth('lr');
7840 * Returns the size of the element.
7841 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7842 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7844 getSize : function(contentSize){
7845 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7849 * Returns the width and height of the viewport.
7850 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7852 getViewSize : function(){
7853 var d = this.dom, doc = document, aw = 0, ah = 0;
7854 if(d == doc || d == doc.body){
7855 return {width : D.getViewWidth(), height: D.getViewHeight()};
7858 width : d.clientWidth,
7859 height: d.clientHeight
7865 * Returns the value of the "value" attribute
7866 * @param {Boolean} asNumber true to parse the value as a number
7867 * @return {String/Number}
7869 getValue : function(asNumber){
7870 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7874 adjustWidth : function(width){
7875 if(typeof width == "number"){
7876 if(this.autoBoxAdjust && !this.isBorderBox()){
7877 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7887 adjustHeight : function(height){
7888 if(typeof height == "number"){
7889 if(this.autoBoxAdjust && !this.isBorderBox()){
7890 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7900 * Set the width of the element
7901 * @param {Number} width The new width
7902 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7903 * @return {Roo.Element} this
7905 setWidth : function(width, animate){
7906 width = this.adjustWidth(width);
7908 this.dom.style.width = this.addUnits(width);
7910 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7916 * Set the height of the element
7917 * @param {Number} height The new height
7918 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7919 * @return {Roo.Element} this
7921 setHeight : function(height, animate){
7922 height = this.adjustHeight(height);
7924 this.dom.style.height = this.addUnits(height);
7926 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7932 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7933 * @param {Number} width The new width
7934 * @param {Number} height The new height
7935 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7936 * @return {Roo.Element} this
7938 setSize : function(width, height, animate){
7939 if(typeof width == "object"){ // in case of object from getSize()
7940 height = width.height; width = width.width;
7942 width = this.adjustWidth(width); height = this.adjustHeight(height);
7944 this.dom.style.width = this.addUnits(width);
7945 this.dom.style.height = this.addUnits(height);
7947 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7953 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7954 * @param {Number} x X value for new position (coordinates are page-based)
7955 * @param {Number} y Y value for new position (coordinates are page-based)
7956 * @param {Number} width The new width
7957 * @param {Number} height The new height
7958 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7959 * @return {Roo.Element} this
7961 setBounds : function(x, y, width, height, animate){
7963 this.setSize(width, height);
7964 this.setLocation(x, y);
7966 width = this.adjustWidth(width); height = this.adjustHeight(height);
7967 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7968 this.preanim(arguments, 4), 'motion');
7974 * 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.
7975 * @param {Roo.lib.Region} region The region to fill
7976 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7977 * @return {Roo.Element} this
7979 setRegion : function(region, animate){
7980 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7985 * Appends an event handler
7987 * @param {String} eventName The type of event to append
7988 * @param {Function} fn The method the event invokes
7989 * @param {Object} scope (optional) The scope (this object) of the fn
7990 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7992 addListener : function(eventName, fn, scope, options){
7994 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7999 * Removes an event handler from this element
8000 * @param {String} eventName the type of event to remove
8001 * @param {Function} fn the method the event invokes
8002 * @return {Roo.Element} this
8004 removeListener : function(eventName, fn){
8005 Roo.EventManager.removeListener(this.dom, eventName, fn);
8010 * Removes all previous added listeners from this element
8011 * @return {Roo.Element} this
8013 removeAllListeners : function(){
8014 E.purgeElement(this.dom);
8018 relayEvent : function(eventName, observable){
8019 this.on(eventName, function(e){
8020 observable.fireEvent(eventName, e);
8025 * Set the opacity of the element
8026 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8027 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8028 * @return {Roo.Element} this
8030 setOpacity : function(opacity, animate){
8032 var s = this.dom.style;
8035 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8036 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8038 s.opacity = opacity;
8041 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8047 * Gets the left X coordinate
8048 * @param {Boolean} local True to get the local css position instead of page coordinate
8051 getLeft : function(local){
8055 return parseInt(this.getStyle("left"), 10) || 0;
8060 * Gets the right X coordinate of the element (element X position + element width)
8061 * @param {Boolean} local True to get the local css position instead of page coordinate
8064 getRight : function(local){
8066 return this.getX() + this.getWidth();
8068 return (this.getLeft(true) + this.getWidth()) || 0;
8073 * Gets the top Y coordinate
8074 * @param {Boolean} local True to get the local css position instead of page coordinate
8077 getTop : function(local) {
8081 return parseInt(this.getStyle("top"), 10) || 0;
8086 * Gets the bottom Y coordinate of the element (element Y position + element height)
8087 * @param {Boolean} local True to get the local css position instead of page coordinate
8090 getBottom : function(local){
8092 return this.getY() + this.getHeight();
8094 return (this.getTop(true) + this.getHeight()) || 0;
8099 * Initializes positioning on this element. If a desired position is not passed, it will make the
8100 * the element positioned relative IF it is not already positioned.
8101 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8102 * @param {Number} zIndex (optional) The zIndex to apply
8103 * @param {Number} x (optional) Set the page X position
8104 * @param {Number} y (optional) Set the page Y position
8106 position : function(pos, zIndex, x, y){
8108 if(this.getStyle('position') == 'static'){
8109 this.setStyle('position', 'relative');
8112 this.setStyle("position", pos);
8115 this.setStyle("z-index", zIndex);
8117 if(x !== undefined && y !== undefined){
8119 }else if(x !== undefined){
8121 }else if(y !== undefined){
8127 * Clear positioning back to the default when the document was loaded
8128 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8129 * @return {Roo.Element} this
8131 clearPositioning : function(value){
8139 "position" : "static"
8145 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8146 * snapshot before performing an update and then restoring the element.
8149 getPositioning : function(){
8150 var l = this.getStyle("left");
8151 var t = this.getStyle("top");
8153 "position" : this.getStyle("position"),
8155 "right" : l ? "" : this.getStyle("right"),
8157 "bottom" : t ? "" : this.getStyle("bottom"),
8158 "z-index" : this.getStyle("z-index")
8163 * Gets the width of the border(s) for the specified side(s)
8164 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8165 * passing lr would get the border (l)eft width + the border (r)ight width.
8166 * @return {Number} The width of the sides passed added together
8168 getBorderWidth : function(side){
8169 return this.addStyles(side, El.borders);
8173 * Gets the width of the padding(s) for the specified side(s)
8174 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8175 * passing lr would get the padding (l)eft + the padding (r)ight.
8176 * @return {Number} The padding of the sides passed added together
8178 getPadding : function(side){
8179 return this.addStyles(side, El.paddings);
8183 * Set positioning with an object returned by getPositioning().
8184 * @param {Object} posCfg
8185 * @return {Roo.Element} this
8187 setPositioning : function(pc){
8188 this.applyStyles(pc);
8189 if(pc.right == "auto"){
8190 this.dom.style.right = "";
8192 if(pc.bottom == "auto"){
8193 this.dom.style.bottom = "";
8199 fixDisplay : function(){
8200 if(this.getStyle("display") == "none"){
8201 this.setStyle("visibility", "hidden");
8202 this.setStyle("display", this.originalDisplay); // first try reverting to default
8203 if(this.getStyle("display") == "none"){ // if that fails, default to block
8204 this.setStyle("display", "block");
8210 * Quick set left and top adding default units
8211 * @param {String} left The left CSS property value
8212 * @param {String} top The top CSS property value
8213 * @return {Roo.Element} this
8215 setLeftTop : function(left, top){
8216 this.dom.style.left = this.addUnits(left);
8217 this.dom.style.top = this.addUnits(top);
8222 * Move this element relative to its current position.
8223 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8224 * @param {Number} distance How far to move the element in pixels
8225 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8226 * @return {Roo.Element} this
8228 move : function(direction, distance, animate){
8229 var xy = this.getXY();
8230 direction = direction.toLowerCase();
8234 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8238 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8243 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8248 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8255 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8256 * @return {Roo.Element} this
8259 if(!this.isClipped){
8260 this.isClipped = true;
8261 this.originalClip = {
8262 "o": this.getStyle("overflow"),
8263 "x": this.getStyle("overflow-x"),
8264 "y": this.getStyle("overflow-y")
8266 this.setStyle("overflow", "hidden");
8267 this.setStyle("overflow-x", "hidden");
8268 this.setStyle("overflow-y", "hidden");
8274 * Return clipping (overflow) to original clipping before clip() was called
8275 * @return {Roo.Element} this
8277 unclip : function(){
8279 this.isClipped = false;
8280 var o = this.originalClip;
8281 if(o.o){this.setStyle("overflow", o.o);}
8282 if(o.x){this.setStyle("overflow-x", o.x);}
8283 if(o.y){this.setStyle("overflow-y", o.y);}
8290 * Gets the x,y coordinates specified by the anchor position on the element.
8291 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8292 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8293 * {width: (target width), height: (target height)} (defaults to the element's current size)
8294 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8295 * @return {Array} [x, y] An array containing the element's x and y coordinates
8297 getAnchorXY : function(anchor, local, s){
8298 //Passing a different size is useful for pre-calculating anchors,
8299 //especially for anchored animations that change the el size.
8301 var w, h, vp = false;
8304 if(d == document.body || d == document){
8306 w = D.getViewWidth(); h = D.getViewHeight();
8308 w = this.getWidth(); h = this.getHeight();
8311 w = s.width; h = s.height;
8313 var x = 0, y = 0, r = Math.round;
8314 switch((anchor || "tl").toLowerCase()){
8356 var sc = this.getScroll();
8357 return [x + sc.left, y + sc.top];
8359 //Add the element's offset xy
8360 var o = this.getXY();
8361 return [x+o[0], y+o[1]];
8365 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8366 * supported position values.
8367 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8368 * @param {String} position The position to align to.
8369 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8370 * @return {Array} [x, y]
8372 getAlignToXY : function(el, p, o){
8376 throw "Element.alignTo with an element that doesn't exist";
8378 var c = false; //constrain to viewport
8379 var p1 = "", p2 = "";
8386 }else if(p.indexOf("-") == -1){
8389 p = p.toLowerCase();
8390 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8392 throw "Element.alignTo with an invalid alignment " + p;
8394 p1 = m[1]; p2 = m[2]; c = !!m[3];
8396 //Subtract the aligned el's internal xy from the target's offset xy
8397 //plus custom offset to get the aligned el's new offset xy
8398 var a1 = this.getAnchorXY(p1, true);
8399 var a2 = el.getAnchorXY(p2, false);
8400 var x = a2[0] - a1[0] + o[0];
8401 var y = a2[1] - a1[1] + o[1];
8403 //constrain the aligned el to viewport if necessary
8404 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8405 // 5px of margin for ie
8406 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8408 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8409 //perpendicular to the vp border, allow the aligned el to slide on that border,
8410 //otherwise swap the aligned el to the opposite border of the target.
8411 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8412 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8413 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8414 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8417 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8418 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8420 if((x+w) > dw + scrollX){
8421 x = swapX ? r.left-w : dw+scrollX-w;
8424 x = swapX ? r.right : scrollX;
8426 if((y+h) > dh + scrollY){
8427 y = swapY ? r.top-h : dh+scrollY-h;
8430 y = swapY ? r.bottom : scrollY;
8437 getConstrainToXY : function(){
8438 var os = {top:0, left:0, bottom:0, right: 0};
8440 return function(el, local, offsets, proposedXY){
8442 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8444 var vw, vh, vx = 0, vy = 0;
8445 if(el.dom == document.body || el.dom == document){
8446 vw = Roo.lib.Dom.getViewWidth();
8447 vh = Roo.lib.Dom.getViewHeight();
8449 vw = el.dom.clientWidth;
8450 vh = el.dom.clientHeight;
8452 var vxy = el.getXY();
8458 var s = el.getScroll();
8460 vx += offsets.left + s.left;
8461 vy += offsets.top + s.top;
8463 vw -= offsets.right;
8464 vh -= offsets.bottom;
8469 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8470 var x = xy[0], y = xy[1];
8471 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8473 // only move it if it needs it
8476 // first validate right/bottom
8485 // then make sure top/left isn't negative
8494 return moved ? [x, y] : false;
8499 adjustForConstraints : function(xy, parent, offsets){
8500 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8504 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8505 * document it aligns it to the viewport.
8506 * The position parameter is optional, and can be specified in any one of the following formats:
8508 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8509 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8510 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8511 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8512 * <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
8513 * element's anchor point, and the second value is used as the target's anchor point.</li>
8515 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8516 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8517 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8518 * that specified in order to enforce the viewport constraints.
8519 * Following are all of the supported anchor positions:
8522 ----- -----------------------------
8523 tl The top left corner (default)
8524 t The center of the top edge
8525 tr The top right corner
8526 l The center of the left edge
8527 c In the center of the element
8528 r The center of the right edge
8529 bl The bottom left corner
8530 b The center of the bottom edge
8531 br The bottom right corner
8535 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8536 el.alignTo("other-el");
8538 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8539 el.alignTo("other-el", "tr?");
8541 // align the bottom right corner of el with the center left edge of other-el
8542 el.alignTo("other-el", "br-l?");
8544 // align the center of el with the bottom left corner of other-el and
8545 // adjust the x position by -6 pixels (and the y position by 0)
8546 el.alignTo("other-el", "c-bl", [-6, 0]);
8548 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8549 * @param {String} position The position to align to.
8550 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8551 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8552 * @return {Roo.Element} this
8554 alignTo : function(element, position, offsets, animate){
8555 var xy = this.getAlignToXY(element, position, offsets);
8556 this.setXY(xy, this.preanim(arguments, 3));
8561 * Anchors an element to another element and realigns it when the window is resized.
8562 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8563 * @param {String} position The position to align to.
8564 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8565 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8566 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8567 * is a number, it is used as the buffer delay (defaults to 50ms).
8568 * @param {Function} callback The function to call after the animation finishes
8569 * @return {Roo.Element} this
8571 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8572 var action = function(){
8573 this.alignTo(el, alignment, offsets, animate);
8574 Roo.callback(callback, this);
8576 Roo.EventManager.onWindowResize(action, this);
8577 var tm = typeof monitorScroll;
8578 if(tm != 'undefined'){
8579 Roo.EventManager.on(window, 'scroll', action, this,
8580 {buffer: tm == 'number' ? monitorScroll : 50});
8582 action.call(this); // align immediately
8586 * Clears any opacity settings from this element. Required in some cases for IE.
8587 * @return {Roo.Element} this
8589 clearOpacity : function(){
8590 if (window.ActiveXObject) {
8591 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8592 this.dom.style.filter = "";
8595 this.dom.style.opacity = "";
8596 this.dom.style["-moz-opacity"] = "";
8597 this.dom.style["-khtml-opacity"] = "";
8603 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8604 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8605 * @return {Roo.Element} this
8607 hide : function(animate){
8608 this.setVisible(false, this.preanim(arguments, 0));
8613 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8614 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8615 * @return {Roo.Element} this
8617 show : function(animate){
8618 this.setVisible(true, this.preanim(arguments, 0));
8623 * @private Test if size has a unit, otherwise appends the default
8625 addUnits : function(size){
8626 return Roo.Element.addUnits(size, this.defaultUnit);
8630 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8631 * @return {Roo.Element} this
8633 beginMeasure : function(){
8635 if(el.offsetWidth || el.offsetHeight){
8636 return this; // offsets work already
8639 var p = this.dom, b = document.body; // start with this element
8640 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8641 var pe = Roo.get(p);
8642 if(pe.getStyle('display') == 'none'){
8643 changed.push({el: p, visibility: pe.getStyle("visibility")});
8644 p.style.visibility = "hidden";
8645 p.style.display = "block";
8649 this._measureChanged = changed;
8655 * Restores displays to before beginMeasure was called
8656 * @return {Roo.Element} this
8658 endMeasure : function(){
8659 var changed = this._measureChanged;
8661 for(var i = 0, len = changed.length; i < len; i++) {
8663 r.el.style.visibility = r.visibility;
8664 r.el.style.display = "none";
8666 this._measureChanged = null;
8672 * Update the innerHTML of this element, optionally searching for and processing scripts
8673 * @param {String} html The new HTML
8674 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8675 * @param {Function} callback For async script loading you can be noticed when the update completes
8676 * @return {Roo.Element} this
8678 update : function(html, loadScripts, callback){
8679 if(typeof html == "undefined"){
8682 if(loadScripts !== true){
8683 this.dom.innerHTML = html;
8684 if(typeof callback == "function"){
8692 html += '<span id="' + id + '"></span>';
8694 E.onAvailable(id, function(){
8695 var hd = document.getElementsByTagName("head")[0];
8696 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8697 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8698 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8701 while(match = re.exec(html)){
8702 var attrs = match[1];
8703 var srcMatch = attrs ? attrs.match(srcRe) : false;
8704 if(srcMatch && srcMatch[2]){
8705 var s = document.createElement("script");
8706 s.src = srcMatch[2];
8707 var typeMatch = attrs.match(typeRe);
8708 if(typeMatch && typeMatch[2]){
8709 s.type = typeMatch[2];
8712 }else if(match[2] && match[2].length > 0){
8713 if(window.execScript) {
8714 window.execScript(match[2]);
8722 window.eval(match[2]);
8726 var el = document.getElementById(id);
8727 if(el){el.parentNode.removeChild(el);}
8728 if(typeof callback == "function"){
8732 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8737 * Direct access to the UpdateManager update() method (takes the same parameters).
8738 * @param {String/Function} url The url for this request or a function to call to get the url
8739 * @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}
8740 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8741 * @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.
8742 * @return {Roo.Element} this
8745 var um = this.getUpdateManager();
8746 um.update.apply(um, arguments);
8751 * Gets this element's UpdateManager
8752 * @return {Roo.UpdateManager} The UpdateManager
8754 getUpdateManager : function(){
8755 if(!this.updateManager){
8756 this.updateManager = new Roo.UpdateManager(this);
8758 return this.updateManager;
8762 * Disables text selection for this element (normalized across browsers)
8763 * @return {Roo.Element} this
8765 unselectable : function(){
8766 this.dom.unselectable = "on";
8767 this.swallowEvent("selectstart", true);
8768 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8769 this.addClass("x-unselectable");
8774 * Calculates the x, y to center this element on the screen
8775 * @return {Array} The x, y values [x, y]
8777 getCenterXY : function(){
8778 return this.getAlignToXY(document, 'c-c');
8782 * Centers the Element in either the viewport, or another Element.
8783 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8785 center : function(centerIn){
8786 this.alignTo(centerIn || document, 'c-c');
8791 * Tests various css rules/browsers to determine if this element uses a border box
8794 isBorderBox : function(){
8795 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8799 * Return a box {x, y, width, height} that can be used to set another elements
8800 * size/location to match this element.
8801 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8802 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8803 * @return {Object} box An object in the format {x, y, width, height}
8805 getBox : function(contentBox, local){
8810 var left = parseInt(this.getStyle("left"), 10) || 0;
8811 var top = parseInt(this.getStyle("top"), 10) || 0;
8814 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8816 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8818 var l = this.getBorderWidth("l")+this.getPadding("l");
8819 var r = this.getBorderWidth("r")+this.getPadding("r");
8820 var t = this.getBorderWidth("t")+this.getPadding("t");
8821 var b = this.getBorderWidth("b")+this.getPadding("b");
8822 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)};
8824 bx.right = bx.x + bx.width;
8825 bx.bottom = bx.y + bx.height;
8830 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8831 for more information about the sides.
8832 * @param {String} sides
8835 getFrameWidth : function(sides, onlyContentBox){
8836 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8840 * 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.
8841 * @param {Object} box The box to fill {x, y, width, height}
8842 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8843 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8844 * @return {Roo.Element} this
8846 setBox : function(box, adjust, animate){
8847 var w = box.width, h = box.height;
8848 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8849 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8850 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8852 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8857 * Forces the browser to repaint this element
8858 * @return {Roo.Element} this
8860 repaint : function(){
8862 this.addClass("x-repaint");
8863 setTimeout(function(){
8864 Roo.get(dom).removeClass("x-repaint");
8870 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8871 * then it returns the calculated width of the sides (see getPadding)
8872 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8873 * @return {Object/Number}
8875 getMargins : function(side){
8878 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8879 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8880 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8881 right: parseInt(this.getStyle("margin-right"), 10) || 0
8884 return this.addStyles(side, El.margins);
8889 addStyles : function(sides, styles){
8891 for(var i = 0, len = sides.length; i < len; i++){
8892 v = this.getStyle(styles[sides.charAt(i)]);
8894 w = parseInt(v, 10);
8902 * Creates a proxy element of this element
8903 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8904 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8905 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8906 * @return {Roo.Element} The new proxy element
8908 createProxy : function(config, renderTo, matchBox){
8910 renderTo = Roo.getDom(renderTo);
8912 renderTo = document.body;
8914 config = typeof config == "object" ?
8915 config : {tag : "div", cls: config};
8916 var proxy = Roo.DomHelper.append(renderTo, config, true);
8918 proxy.setBox(this.getBox());
8924 * Puts a mask over this element to disable user interaction. Requires core.css.
8925 * This method can only be applied to elements which accept child nodes.
8926 * @param {String} msg (optional) A message to display in the mask
8927 * @param {String} msgCls (optional) A css class to apply to the msg element
8928 * @return {Element} The mask element
8930 mask : function(msg, msgCls)
8932 if(this.getStyle("position") == "static"){
8933 this.setStyle("position", "relative");
8936 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8938 this.addClass("x-masked");
8939 this._mask.setDisplayed(true);
8944 while (dom && dom.style) {
8945 if (!isNaN(parseInt(dom.style.zIndex))) {
8946 z = Math.max(z, parseInt(dom.style.zIndex));
8948 dom = dom.parentNode;
8950 // if we are masking the body - then it hides everything..
8951 if (this.dom == document.body) {
8953 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8954 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8957 if(typeof msg == 'string'){
8959 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8961 var mm = this._maskMsg;
8962 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8963 mm.dom.firstChild.innerHTML = msg;
8964 mm.setDisplayed(true);
8966 mm.setStyle('z-index', z + 102);
8968 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8969 this._mask.setHeight(this.getHeight());
8971 this._mask.setStyle('z-index', z + 100);
8977 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8978 * it is cached for reuse.
8980 unmask : function(removeEl){
8982 if(removeEl === true){
8983 this._mask.remove();
8986 this._maskMsg.remove();
8987 delete this._maskMsg;
8990 this._mask.setDisplayed(false);
8992 this._maskMsg.setDisplayed(false);
8996 this.removeClass("x-masked");
9000 * Returns true if this element is masked
9003 isMasked : function(){
9004 return this._mask && this._mask.isVisible();
9008 * Creates an iframe shim for this element to keep selects and other windowed objects from
9010 * @return {Roo.Element} The new shim element
9012 createShim : function(){
9013 var el = document.createElement('iframe');
9014 el.frameBorder = 'no';
9015 el.className = 'roo-shim';
9016 if(Roo.isIE && Roo.isSecure){
9017 el.src = Roo.SSL_SECURE_URL;
9019 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9020 shim.autoBoxAdjust = false;
9025 * Removes this element from the DOM and deletes it from the cache
9027 remove : function(){
9028 if(this.dom.parentNode){
9029 this.dom.parentNode.removeChild(this.dom);
9031 delete El.cache[this.dom.id];
9035 * Sets up event handlers to add and remove a css class when the mouse is over this element
9036 * @param {String} className
9037 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9038 * mouseout events for children elements
9039 * @return {Roo.Element} this
9041 addClassOnOver : function(className, preventFlicker){
9042 this.on("mouseover", function(){
9043 Roo.fly(this, '_internal').addClass(className);
9045 var removeFn = function(e){
9046 if(preventFlicker !== true || !e.within(this, true)){
9047 Roo.fly(this, '_internal').removeClass(className);
9050 this.on("mouseout", removeFn, this.dom);
9055 * Sets up event handlers to add and remove a css class when this element has the focus
9056 * @param {String} className
9057 * @return {Roo.Element} this
9059 addClassOnFocus : function(className){
9060 this.on("focus", function(){
9061 Roo.fly(this, '_internal').addClass(className);
9063 this.on("blur", function(){
9064 Roo.fly(this, '_internal').removeClass(className);
9069 * 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)
9070 * @param {String} className
9071 * @return {Roo.Element} this
9073 addClassOnClick : function(className){
9075 this.on("mousedown", function(){
9076 Roo.fly(dom, '_internal').addClass(className);
9077 var d = Roo.get(document);
9078 var fn = function(){
9079 Roo.fly(dom, '_internal').removeClass(className);
9080 d.removeListener("mouseup", fn);
9082 d.on("mouseup", fn);
9088 * Stops the specified event from bubbling and optionally prevents the default action
9089 * @param {String} eventName
9090 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9091 * @return {Roo.Element} this
9093 swallowEvent : function(eventName, preventDefault){
9094 var fn = function(e){
9095 e.stopPropagation();
9100 if(eventName instanceof Array){
9101 for(var i = 0, len = eventName.length; i < len; i++){
9102 this.on(eventName[i], fn);
9106 this.on(eventName, fn);
9113 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9116 * Sizes this element to its parent element's dimensions performing
9117 * neccessary box adjustments.
9118 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9119 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9120 * @return {Roo.Element} this
9122 fitToParent : function(monitorResize, targetParent) {
9123 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9124 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9125 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9128 var p = Roo.get(targetParent || this.dom.parentNode);
9129 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9130 if (monitorResize === true) {
9131 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9132 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9138 * Gets the next sibling, skipping text nodes
9139 * @return {HTMLElement} The next sibling or null
9141 getNextSibling : function(){
9142 var n = this.dom.nextSibling;
9143 while(n && n.nodeType != 1){
9150 * Gets the previous sibling, skipping text nodes
9151 * @return {HTMLElement} The previous sibling or null
9153 getPrevSibling : function(){
9154 var n = this.dom.previousSibling;
9155 while(n && n.nodeType != 1){
9156 n = n.previousSibling;
9163 * Appends the passed element(s) to this element
9164 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9165 * @return {Roo.Element} this
9167 appendChild: function(el){
9174 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9175 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9176 * automatically generated with the specified attributes.
9177 * @param {HTMLElement} insertBefore (optional) a child element of this element
9178 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9179 * @return {Roo.Element} The new child element
9181 createChild: function(config, insertBefore, returnDom){
9182 config = config || {tag:'div'};
9184 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9186 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9190 * Appends this element to the passed element
9191 * @param {String/HTMLElement/Element} el The new parent element
9192 * @return {Roo.Element} this
9194 appendTo: function(el){
9195 el = Roo.getDom(el);
9196 el.appendChild(this.dom);
9201 * Inserts this element before the passed element in the DOM
9202 * @param {String/HTMLElement/Element} el The element to insert before
9203 * @return {Roo.Element} this
9205 insertBefore: function(el){
9206 el = Roo.getDom(el);
9207 el.parentNode.insertBefore(this.dom, el);
9212 * Inserts this element after the passed element in the DOM
9213 * @param {String/HTMLElement/Element} el The element to insert after
9214 * @return {Roo.Element} this
9216 insertAfter: function(el){
9217 el = Roo.getDom(el);
9218 el.parentNode.insertBefore(this.dom, el.nextSibling);
9223 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9224 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9225 * @return {Roo.Element} The new child
9227 insertFirst: function(el, returnDom){
9229 if(typeof el == 'object' && !el.nodeType){ // dh config
9230 return this.createChild(el, this.dom.firstChild, returnDom);
9232 el = Roo.getDom(el);
9233 this.dom.insertBefore(el, this.dom.firstChild);
9234 return !returnDom ? Roo.get(el) : el;
9239 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9240 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9241 * @param {String} where (optional) 'before' or 'after' defaults to before
9242 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9243 * @return {Roo.Element} the inserted Element
9245 insertSibling: function(el, where, returnDom){
9246 where = where ? where.toLowerCase() : 'before';
9248 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9250 if(typeof el == 'object' && !el.nodeType){ // dh config
9251 if(where == 'after' && !this.dom.nextSibling){
9252 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9254 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9258 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9259 where == 'before' ? this.dom : this.dom.nextSibling);
9268 * Creates and wraps this element with another element
9269 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9270 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9271 * @return {HTMLElement/Element} The newly created wrapper element
9273 wrap: function(config, returnDom){
9275 config = {tag: "div"};
9277 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9278 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9283 * Replaces the passed element with this element
9284 * @param {String/HTMLElement/Element} el The element to replace
9285 * @return {Roo.Element} this
9287 replace: function(el){
9289 this.insertBefore(el);
9295 * Inserts an html fragment into this element
9296 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9297 * @param {String} html The HTML fragment
9298 * @param {Boolean} returnEl True to return an Roo.Element
9299 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9301 insertHtml : function(where, html, returnEl){
9302 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9303 return returnEl ? Roo.get(el) : el;
9307 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9308 * @param {Object} o The object with the attributes
9309 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9310 * @return {Roo.Element} this
9312 set : function(o, useSet){
9314 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9316 if(attr == "style" || typeof o[attr] == "function") continue;
9318 el.className = o["cls"];
9320 if(useSet) el.setAttribute(attr, o[attr]);
9321 else el[attr] = o[attr];
9325 Roo.DomHelper.applyStyles(el, o.style);
9331 * Convenience method for constructing a KeyMap
9332 * @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:
9333 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9334 * @param {Function} fn The function to call
9335 * @param {Object} scope (optional) The scope of the function
9336 * @return {Roo.KeyMap} The KeyMap created
9338 addKeyListener : function(key, fn, scope){
9340 if(typeof key != "object" || key instanceof Array){
9356 return new Roo.KeyMap(this, config);
9360 * Creates a KeyMap for this element
9361 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9362 * @return {Roo.KeyMap} The KeyMap created
9364 addKeyMap : function(config){
9365 return new Roo.KeyMap(this, config);
9369 * Returns true if this element is scrollable.
9372 isScrollable : function(){
9374 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9378 * 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().
9379 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9380 * @param {Number} value The new scroll value
9381 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9382 * @return {Element} this
9385 scrollTo : function(side, value, animate){
9386 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9388 this.dom[prop] = value;
9390 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9391 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9397 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9398 * within this element's scrollable range.
9399 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9400 * @param {Number} distance How far to scroll the element in pixels
9401 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9402 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9403 * was scrolled as far as it could go.
9405 scroll : function(direction, distance, animate){
9406 if(!this.isScrollable()){
9410 var l = el.scrollLeft, t = el.scrollTop;
9411 var w = el.scrollWidth, h = el.scrollHeight;
9412 var cw = el.clientWidth, ch = el.clientHeight;
9413 direction = direction.toLowerCase();
9414 var scrolled = false;
9415 var a = this.preanim(arguments, 2);
9420 var v = Math.min(l + distance, w-cw);
9421 this.scrollTo("left", v, a);
9428 var v = Math.max(l - distance, 0);
9429 this.scrollTo("left", v, a);
9437 var v = Math.max(t - distance, 0);
9438 this.scrollTo("top", v, a);
9446 var v = Math.min(t + distance, h-ch);
9447 this.scrollTo("top", v, a);
9456 * Translates the passed page coordinates into left/top css values for this element
9457 * @param {Number/Array} x The page x or an array containing [x, y]
9458 * @param {Number} y The page y
9459 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9461 translatePoints : function(x, y){
9462 if(typeof x == 'object' || x instanceof Array){
9465 var p = this.getStyle('position');
9466 var o = this.getXY();
9468 var l = parseInt(this.getStyle('left'), 10);
9469 var t = parseInt(this.getStyle('top'), 10);
9472 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9475 t = (p == "relative") ? 0 : this.dom.offsetTop;
9478 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9482 * Returns the current scroll position of the element.
9483 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9485 getScroll : function(){
9486 var d = this.dom, doc = document;
9487 if(d == doc || d == doc.body){
9488 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9489 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9490 return {left: l, top: t};
9492 return {left: d.scrollLeft, top: d.scrollTop};
9497 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9498 * are convert to standard 6 digit hex color.
9499 * @param {String} attr The css attribute
9500 * @param {String} defaultValue The default value to use when a valid color isn't found
9501 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9504 getColor : function(attr, defaultValue, prefix){
9505 var v = this.getStyle(attr);
9506 if(!v || v == "transparent" || v == "inherit") {
9507 return defaultValue;
9509 var color = typeof prefix == "undefined" ? "#" : prefix;
9510 if(v.substr(0, 4) == "rgb("){
9511 var rvs = v.slice(4, v.length -1).split(",");
9512 for(var i = 0; i < 3; i++){
9513 var h = parseInt(rvs[i]).toString(16);
9520 if(v.substr(0, 1) == "#"){
9522 for(var i = 1; i < 4; i++){
9523 var c = v.charAt(i);
9526 }else if(v.length == 7){
9527 color += v.substr(1);
9531 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9535 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9536 * gradient background, rounded corners and a 4-way shadow.
9537 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9538 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9539 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9540 * @return {Roo.Element} this
9542 boxWrap : function(cls){
9543 cls = cls || 'x-box';
9544 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9545 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9550 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9551 * @param {String} namespace The namespace in which to look for the attribute
9552 * @param {String} name The attribute name
9553 * @return {String} The attribute value
9555 getAttributeNS : Roo.isIE ? function(ns, name){
9557 var type = typeof d[ns+":"+name];
9558 if(type != 'undefined' && type != 'unknown'){
9559 return d[ns+":"+name];
9562 } : function(ns, name){
9564 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9569 * Sets or Returns the value the dom attribute value
9570 * @param {String} name The attribute name
9571 * @param {String} value (optional) The value to set the attribute to
9572 * @return {String} The attribute value
9574 attr : function(name){
9575 if (arguments.length > 1) {
9576 this.dom.setAttribute(name, arguments[1]);
9577 return arguments[1];
9579 if (!this.dom.hasAttribute(name)) {
9582 return this.dom.getAttribute(name);
9589 var ep = El.prototype;
9592 * Appends an event handler (Shorthand for addListener)
9593 * @param {String} eventName The type of event to append
9594 * @param {Function} fn The method the event invokes
9595 * @param {Object} scope (optional) The scope (this object) of the fn
9596 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9599 ep.on = ep.addListener;
9601 ep.mon = ep.addListener;
9604 * Removes an event handler from this element (shorthand for removeListener)
9605 * @param {String} eventName the type of event to remove
9606 * @param {Function} fn the method the event invokes
9607 * @return {Roo.Element} this
9610 ep.un = ep.removeListener;
9613 * true to automatically adjust width and height settings for box-model issues (default to true)
9615 ep.autoBoxAdjust = true;
9618 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9621 El.addUnits = function(v, defaultUnit){
9622 if(v === "" || v == "auto"){
9625 if(v === undefined){
9628 if(typeof v == "number" || !El.unitPattern.test(v)){
9629 return v + (defaultUnit || 'px');
9634 // special markup used throughout Roo when box wrapping elements
9635 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>';
9637 * Visibility mode constant - Use visibility to hide element
9643 * Visibility mode constant - Use display to hide element
9649 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9650 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9651 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9663 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9664 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9665 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9666 * @return {Element} The Element object
9669 El.get = function(el){
9671 if(!el){ return null; }
9672 if(typeof el == "string"){ // element id
9673 if(!(elm = document.getElementById(el))){
9676 if(ex = El.cache[el]){
9679 ex = El.cache[el] = new El(elm);
9682 }else if(el.tagName){ // dom element
9686 if(ex = El.cache[id]){
9689 ex = El.cache[id] = new El(el);
9692 }else if(el instanceof El){
9694 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9695 // catch case where it hasn't been appended
9696 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9699 }else if(el.isComposite){
9701 }else if(el instanceof Array){
9702 return El.select(el);
9703 }else if(el == document){
9704 // create a bogus element object representing the document object
9706 var f = function(){};
9707 f.prototype = El.prototype;
9709 docEl.dom = document;
9717 El.uncache = function(el){
9718 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9720 delete El.cache[a[i].id || a[i]];
9726 // Garbage collection - uncache elements/purge listeners on orphaned elements
9727 // so we don't hold a reference and cause the browser to retain them
9728 El.garbageCollect = function(){
9729 if(!Roo.enableGarbageCollector){
9730 clearInterval(El.collectorThread);
9733 for(var eid in El.cache){
9734 var el = El.cache[eid], d = el.dom;
9735 // -------------------------------------------------------
9736 // Determining what is garbage:
9737 // -------------------------------------------------------
9739 // dom node is null, definitely garbage
9740 // -------------------------------------------------------
9742 // no parentNode == direct orphan, definitely garbage
9743 // -------------------------------------------------------
9744 // !d.offsetParent && !document.getElementById(eid)
9745 // display none elements have no offsetParent so we will
9746 // also try to look it up by it's id. However, check
9747 // offsetParent first so we don't do unneeded lookups.
9748 // This enables collection of elements that are not orphans
9749 // directly, but somewhere up the line they have an orphan
9751 // -------------------------------------------------------
9752 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9753 delete El.cache[eid];
9754 if(d && Roo.enableListenerCollection){
9760 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9764 El.Flyweight = function(dom){
9767 El.Flyweight.prototype = El.prototype;
9769 El._flyweights = {};
9771 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9772 * the dom node can be overwritten by other code.
9773 * @param {String/HTMLElement} el The dom node or id
9774 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9775 * prevent conflicts (e.g. internally Roo uses "_internal")
9777 * @return {Element} The shared Element object
9779 El.fly = function(el, named){
9780 named = named || '_global';
9781 el = Roo.getDom(el);
9785 if(!El._flyweights[named]){
9786 El._flyweights[named] = new El.Flyweight();
9788 El._flyweights[named].dom = el;
9789 return El._flyweights[named];
9793 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9794 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9795 * Shorthand of {@link Roo.Element#get}
9796 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9797 * @return {Element} The Element object
9803 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9804 * the dom node can be overwritten by other code.
9805 * Shorthand of {@link Roo.Element#fly}
9806 * @param {String/HTMLElement} el The dom node or id
9807 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9808 * prevent conflicts (e.g. internally Roo uses "_internal")
9810 * @return {Element} The shared Element object
9816 // speedy lookup for elements never to box adjust
9817 var noBoxAdjust = Roo.isStrict ? {
9820 input:1, select:1, textarea:1
9822 if(Roo.isIE || Roo.isGecko){
9823 noBoxAdjust['button'] = 1;
9827 Roo.EventManager.on(window, 'unload', function(){
9829 delete El._flyweights;
9837 Roo.Element.selectorFunction = Roo.DomQuery.select;
9840 Roo.Element.select = function(selector, unique, root){
9842 if(typeof selector == "string"){
9843 els = Roo.Element.selectorFunction(selector, root);
9844 }else if(selector.length !== undefined){
9847 throw "Invalid selector";
9849 if(unique === true){
9850 return new Roo.CompositeElement(els);
9852 return new Roo.CompositeElementLite(els);
9856 * Selects elements based on the passed CSS selector to enable working on them as 1.
9857 * @param {String/Array} selector The CSS selector or an array of elements
9858 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9859 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9860 * @return {CompositeElementLite/CompositeElement}
9864 Roo.select = Roo.Element.select;
9881 * Ext JS Library 1.1.1
9882 * Copyright(c) 2006-2007, Ext JS, LLC.
9884 * Originally Released Under LGPL - original licence link has changed is not relivant.
9887 * <script type="text/javascript">
9892 //Notifies Element that fx methods are available
9893 Roo.enableFx = true;
9897 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9898 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9899 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9900 * Element effects to work.</p><br/>
9902 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9903 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9904 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9905 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9906 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9907 * expected results and should be done with care.</p><br/>
9909 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9910 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9913 ----- -----------------------------
9914 tl The top left corner
9915 t The center of the top edge
9916 tr The top right corner
9917 l The center of the left edge
9918 r The center of the right edge
9919 bl The bottom left corner
9920 b The center of the bottom edge
9921 br The bottom right corner
9923 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9924 * below are common options that can be passed to any Fx method.</b>
9925 * @cfg {Function} callback A function called when the effect is finished
9926 * @cfg {Object} scope The scope of the effect function
9927 * @cfg {String} easing A valid Easing value for the effect
9928 * @cfg {String} afterCls A css class to apply after the effect
9929 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9930 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9931 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9932 * effects that end with the element being visually hidden, ignored otherwise)
9933 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9934 * a function which returns such a specification that will be applied to the Element after the effect finishes
9935 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9936 * @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
9937 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9941 * Slides the element into view. An anchor point can be optionally passed to set the point of
9942 * origin for the slide effect. This function automatically handles wrapping the element with
9943 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9946 // default: slide the element in from the top
9949 // custom: slide the element in from the right with a 2-second duration
9950 el.slideIn('r', { duration: 2 });
9952 // common config options shown with default values
9958 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9959 * @param {Object} options (optional) Object literal with any of the Fx config options
9960 * @return {Roo.Element} The Element
9962 slideIn : function(anchor, o){
9963 var el = this.getFxEl();
9966 el.queueFx(o, function(){
9968 anchor = anchor || "t";
9970 // fix display to visibility
9973 // restore values after effect
9974 var r = this.getFxRestore();
9975 var b = this.getBox();
9976 // fixed size for slide
9980 var wrap = this.fxWrap(r.pos, o, "hidden");
9982 var st = this.dom.style;
9983 st.visibility = "visible";
9984 st.position = "absolute";
9986 // clear out temp styles after slide and unwrap
9987 var after = function(){
9988 el.fxUnwrap(wrap, r.pos, o);
9990 st.height = r.height;
9993 // time to calc the positions
9994 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9996 switch(anchor.toLowerCase()){
9998 wrap.setSize(b.width, 0);
9999 st.left = st.bottom = "0";
10003 wrap.setSize(0, b.height);
10004 st.right = st.top = "0";
10008 wrap.setSize(0, b.height);
10009 wrap.setX(b.right);
10010 st.left = st.top = "0";
10011 a = {width: bw, points: pt};
10014 wrap.setSize(b.width, 0);
10015 wrap.setY(b.bottom);
10016 st.left = st.top = "0";
10017 a = {height: bh, points: pt};
10020 wrap.setSize(0, 0);
10021 st.right = st.bottom = "0";
10022 a = {width: bw, height: bh};
10025 wrap.setSize(0, 0);
10026 wrap.setY(b.y+b.height);
10027 st.right = st.top = "0";
10028 a = {width: bw, height: bh, points: pt};
10031 wrap.setSize(0, 0);
10032 wrap.setXY([b.right, b.bottom]);
10033 st.left = st.top = "0";
10034 a = {width: bw, height: bh, points: pt};
10037 wrap.setSize(0, 0);
10038 wrap.setX(b.x+b.width);
10039 st.left = st.bottom = "0";
10040 a = {width: bw, height: bh, points: pt};
10043 this.dom.style.visibility = "visible";
10046 arguments.callee.anim = wrap.fxanim(a,
10056 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10057 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10058 * 'hidden') but block elements will still take up space in the document. The element must be removed
10059 * from the DOM using the 'remove' config option if desired. This function automatically handles
10060 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10063 // default: slide the element out to the top
10066 // custom: slide the element out to the right with a 2-second duration
10067 el.slideOut('r', { duration: 2 });
10069 // common config options shown with default values
10077 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10078 * @param {Object} options (optional) Object literal with any of the Fx config options
10079 * @return {Roo.Element} The Element
10081 slideOut : function(anchor, o){
10082 var el = this.getFxEl();
10085 el.queueFx(o, function(){
10087 anchor = anchor || "t";
10089 // restore values after effect
10090 var r = this.getFxRestore();
10092 var b = this.getBox();
10093 // fixed size for slide
10097 var wrap = this.fxWrap(r.pos, o, "visible");
10099 var st = this.dom.style;
10100 st.visibility = "visible";
10101 st.position = "absolute";
10105 var after = function(){
10107 el.setDisplayed(false);
10112 el.fxUnwrap(wrap, r.pos, o);
10114 st.width = r.width;
10115 st.height = r.height;
10120 var a, zero = {to: 0};
10121 switch(anchor.toLowerCase()){
10123 st.left = st.bottom = "0";
10124 a = {height: zero};
10127 st.right = st.top = "0";
10131 st.left = st.top = "0";
10132 a = {width: zero, points: {to:[b.right, b.y]}};
10135 st.left = st.top = "0";
10136 a = {height: zero, points: {to:[b.x, b.bottom]}};
10139 st.right = st.bottom = "0";
10140 a = {width: zero, height: zero};
10143 st.right = st.top = "0";
10144 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10147 st.left = st.top = "0";
10148 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10151 st.left = st.bottom = "0";
10152 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10156 arguments.callee.anim = wrap.fxanim(a,
10166 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10167 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10168 * The element must be removed from the DOM using the 'remove' config option if desired.
10174 // common config options shown with default values
10182 * @param {Object} options (optional) Object literal with any of the Fx config options
10183 * @return {Roo.Element} The Element
10185 puff : function(o){
10186 var el = this.getFxEl();
10189 el.queueFx(o, function(){
10190 this.clearOpacity();
10193 // restore values after effect
10194 var r = this.getFxRestore();
10195 var st = this.dom.style;
10197 var after = function(){
10199 el.setDisplayed(false);
10206 el.setPositioning(r.pos);
10207 st.width = r.width;
10208 st.height = r.height;
10213 var width = this.getWidth();
10214 var height = this.getHeight();
10216 arguments.callee.anim = this.fxanim({
10217 width : {to: this.adjustWidth(width * 2)},
10218 height : {to: this.adjustHeight(height * 2)},
10219 points : {by: [-(width * .5), -(height * .5)]},
10221 fontSize: {to:200, unit: "%"}
10232 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10233 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10234 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10240 // all config options shown with default values
10248 * @param {Object} options (optional) Object literal with any of the Fx config options
10249 * @return {Roo.Element} The Element
10251 switchOff : function(o){
10252 var el = this.getFxEl();
10255 el.queueFx(o, function(){
10256 this.clearOpacity();
10259 // restore values after effect
10260 var r = this.getFxRestore();
10261 var st = this.dom.style;
10263 var after = function(){
10265 el.setDisplayed(false);
10271 el.setPositioning(r.pos);
10272 st.width = r.width;
10273 st.height = r.height;
10278 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10279 this.clearOpacity();
10283 points:{by:[0, this.getHeight() * .5]}
10284 }, o, 'motion', 0.3, 'easeIn', after);
10285 }).defer(100, this);
10292 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10293 * changed using the "attr" config option) and then fading back to the original color. If no original
10294 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10297 // default: highlight background to yellow
10300 // custom: highlight foreground text to blue for 2 seconds
10301 el.highlight("0000ff", { attr: 'color', duration: 2 });
10303 // common config options shown with default values
10304 el.highlight("ffff9c", {
10305 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10306 endColor: (current color) or "ffffff",
10311 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10312 * @param {Object} options (optional) Object literal with any of the Fx config options
10313 * @return {Roo.Element} The Element
10315 highlight : function(color, o){
10316 var el = this.getFxEl();
10319 el.queueFx(o, function(){
10320 color = color || "ffff9c";
10321 attr = o.attr || "backgroundColor";
10323 this.clearOpacity();
10326 var origColor = this.getColor(attr);
10327 var restoreColor = this.dom.style[attr];
10328 endColor = (o.endColor || origColor) || "ffffff";
10330 var after = function(){
10331 el.dom.style[attr] = restoreColor;
10336 a[attr] = {from: color, to: endColor};
10337 arguments.callee.anim = this.fxanim(a,
10347 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10350 // default: a single light blue ripple
10353 // custom: 3 red ripples lasting 3 seconds total
10354 el.frame("ff0000", 3, { duration: 3 });
10356 // common config options shown with default values
10357 el.frame("C3DAF9", 1, {
10358 duration: 1 //duration of entire animation (not each individual ripple)
10359 // Note: Easing is not configurable and will be ignored if included
10362 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10363 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10364 * @param {Object} options (optional) Object literal with any of the Fx config options
10365 * @return {Roo.Element} The Element
10367 frame : function(color, count, o){
10368 var el = this.getFxEl();
10371 el.queueFx(o, function(){
10372 color = color || "#C3DAF9";
10373 if(color.length == 6){
10374 color = "#" + color;
10376 count = count || 1;
10377 duration = o.duration || 1;
10380 var b = this.getBox();
10381 var animFn = function(){
10382 var proxy = this.createProxy({
10385 visbility:"hidden",
10386 position:"absolute",
10387 "z-index":"35000", // yee haw
10388 border:"0px solid " + color
10391 var scale = Roo.isBorderBox ? 2 : 1;
10393 top:{from:b.y, to:b.y - 20},
10394 left:{from:b.x, to:b.x - 20},
10395 borderWidth:{from:0, to:10},
10396 opacity:{from:1, to:0},
10397 height:{from:b.height, to:(b.height + (20*scale))},
10398 width:{from:b.width, to:(b.width + (20*scale))}
10399 }, duration, function(){
10403 animFn.defer((duration/2)*1000, this);
10414 * Creates a pause before any subsequent queued effects begin. If there are
10415 * no effects queued after the pause it will have no effect.
10420 * @param {Number} seconds The length of time to pause (in seconds)
10421 * @return {Roo.Element} The Element
10423 pause : function(seconds){
10424 var el = this.getFxEl();
10427 el.queueFx(o, function(){
10428 setTimeout(function(){
10430 }, seconds * 1000);
10436 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10437 * using the "endOpacity" config option.
10440 // default: fade in from opacity 0 to 100%
10443 // custom: fade in from opacity 0 to 75% over 2 seconds
10444 el.fadeIn({ endOpacity: .75, duration: 2});
10446 // common config options shown with default values
10448 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10453 * @param {Object} options (optional) Object literal with any of the Fx config options
10454 * @return {Roo.Element} The Element
10456 fadeIn : function(o){
10457 var el = this.getFxEl();
10459 el.queueFx(o, function(){
10460 this.setOpacity(0);
10462 this.dom.style.visibility = 'visible';
10463 var to = o.endOpacity || 1;
10464 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10465 o, null, .5, "easeOut", function(){
10467 this.clearOpacity();
10476 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10477 * using the "endOpacity" config option.
10480 // default: fade out from the element's current opacity to 0
10483 // custom: fade out from the element's current opacity to 25% over 2 seconds
10484 el.fadeOut({ endOpacity: .25, duration: 2});
10486 // common config options shown with default values
10488 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10495 * @param {Object} options (optional) Object literal with any of the Fx config options
10496 * @return {Roo.Element} The Element
10498 fadeOut : function(o){
10499 var el = this.getFxEl();
10501 el.queueFx(o, function(){
10502 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10503 o, null, .5, "easeOut", function(){
10504 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10505 this.dom.style.display = "none";
10507 this.dom.style.visibility = "hidden";
10509 this.clearOpacity();
10517 * Animates the transition of an element's dimensions from a starting height/width
10518 * to an ending height/width.
10521 // change height and width to 100x100 pixels
10522 el.scale(100, 100);
10524 // common config options shown with default values. The height and width will default to
10525 // the element's existing values if passed as null.
10528 [element's height], {
10533 * @param {Number} width The new width (pass undefined to keep the original width)
10534 * @param {Number} height The new height (pass undefined to keep the original height)
10535 * @param {Object} options (optional) Object literal with any of the Fx config options
10536 * @return {Roo.Element} The Element
10538 scale : function(w, h, o){
10539 this.shift(Roo.apply({}, o, {
10547 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10548 * Any of these properties not specified in the config object will not be changed. This effect
10549 * requires that at least one new dimension, position or opacity setting must be passed in on
10550 * the config object in order for the function to have any effect.
10553 // slide the element horizontally to x position 200 while changing the height and opacity
10554 el.shift({ x: 200, height: 50, opacity: .8 });
10556 // common config options shown with default values.
10558 width: [element's width],
10559 height: [element's height],
10560 x: [element's x position],
10561 y: [element's y position],
10562 opacity: [element's opacity],
10567 * @param {Object} options Object literal with any of the Fx config options
10568 * @return {Roo.Element} The Element
10570 shift : function(o){
10571 var el = this.getFxEl();
10573 el.queueFx(o, function(){
10574 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10575 if(w !== undefined){
10576 a.width = {to: this.adjustWidth(w)};
10578 if(h !== undefined){
10579 a.height = {to: this.adjustHeight(h)};
10581 if(x !== undefined || y !== undefined){
10583 x !== undefined ? x : this.getX(),
10584 y !== undefined ? y : this.getY()
10587 if(op !== undefined){
10588 a.opacity = {to: op};
10590 if(o.xy !== undefined){
10591 a.points = {to: o.xy};
10593 arguments.callee.anim = this.fxanim(a,
10594 o, 'motion', .35, "easeOut", function(){
10602 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10603 * ending point of the effect.
10606 // default: slide the element downward while fading out
10609 // custom: slide the element out to the right with a 2-second duration
10610 el.ghost('r', { duration: 2 });
10612 // common config options shown with default values
10620 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10621 * @param {Object} options (optional) Object literal with any of the Fx config options
10622 * @return {Roo.Element} The Element
10624 ghost : function(anchor, o){
10625 var el = this.getFxEl();
10628 el.queueFx(o, function(){
10629 anchor = anchor || "b";
10631 // restore values after effect
10632 var r = this.getFxRestore();
10633 var w = this.getWidth(),
10634 h = this.getHeight();
10636 var st = this.dom.style;
10638 var after = function(){
10640 el.setDisplayed(false);
10646 el.setPositioning(r.pos);
10647 st.width = r.width;
10648 st.height = r.height;
10653 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10654 switch(anchor.toLowerCase()){
10681 arguments.callee.anim = this.fxanim(a,
10691 * Ensures that all effects queued after syncFx is called on the element are
10692 * run concurrently. This is the opposite of {@link #sequenceFx}.
10693 * @return {Roo.Element} The Element
10695 syncFx : function(){
10696 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10705 * Ensures that all effects queued after sequenceFx is called on the element are
10706 * run in sequence. This is the opposite of {@link #syncFx}.
10707 * @return {Roo.Element} The Element
10709 sequenceFx : function(){
10710 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10712 concurrent : false,
10719 nextFx : function(){
10720 var ef = this.fxQueue[0];
10727 * Returns true if the element has any effects actively running or queued, else returns false.
10728 * @return {Boolean} True if element has active effects, else false
10730 hasActiveFx : function(){
10731 return this.fxQueue && this.fxQueue[0];
10735 * Stops any running effects and clears the element's internal effects queue if it contains
10736 * any additional effects that haven't started yet.
10737 * @return {Roo.Element} The Element
10739 stopFx : function(){
10740 if(this.hasActiveFx()){
10741 var cur = this.fxQueue[0];
10742 if(cur && cur.anim && cur.anim.isAnimated()){
10743 this.fxQueue = [cur]; // clear out others
10744 cur.anim.stop(true);
10751 beforeFx : function(o){
10752 if(this.hasActiveFx() && !o.concurrent){
10763 * Returns true if the element is currently blocking so that no other effect can be queued
10764 * until this effect is finished, else returns false if blocking is not set. This is commonly
10765 * used to ensure that an effect initiated by a user action runs to completion prior to the
10766 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10767 * @return {Boolean} True if blocking, else false
10769 hasFxBlock : function(){
10770 var q = this.fxQueue;
10771 return q && q[0] && q[0].block;
10775 queueFx : function(o, fn){
10779 if(!this.hasFxBlock()){
10780 Roo.applyIf(o, this.fxDefaults);
10782 var run = this.beforeFx(o);
10783 fn.block = o.block;
10784 this.fxQueue.push(fn);
10796 fxWrap : function(pos, o, vis){
10798 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10801 wrapXY = this.getXY();
10803 var div = document.createElement("div");
10804 div.style.visibility = vis;
10805 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10806 wrap.setPositioning(pos);
10807 if(wrap.getStyle("position") == "static"){
10808 wrap.position("relative");
10810 this.clearPositioning('auto');
10812 wrap.dom.appendChild(this.dom);
10814 wrap.setXY(wrapXY);
10821 fxUnwrap : function(wrap, pos, o){
10822 this.clearPositioning();
10823 this.setPositioning(pos);
10825 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10831 getFxRestore : function(){
10832 var st = this.dom.style;
10833 return {pos: this.getPositioning(), width: st.width, height : st.height};
10837 afterFx : function(o){
10839 this.applyStyles(o.afterStyle);
10842 this.addClass(o.afterCls);
10844 if(o.remove === true){
10847 Roo.callback(o.callback, o.scope, [this]);
10849 this.fxQueue.shift();
10855 getFxEl : function(){ // support for composite element fx
10856 return Roo.get(this.dom);
10860 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10861 animType = animType || 'run';
10863 var anim = Roo.lib.Anim[animType](
10865 (opt.duration || defaultDur) || .35,
10866 (opt.easing || defaultEase) || 'easeOut',
10868 Roo.callback(cb, this);
10877 // backwords compat
10878 Roo.Fx.resize = Roo.Fx.scale;
10880 //When included, Roo.Fx is automatically applied to Element so that all basic
10881 //effects are available directly via the Element API
10882 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10884 * Ext JS Library 1.1.1
10885 * Copyright(c) 2006-2007, Ext JS, LLC.
10887 * Originally Released Under LGPL - original licence link has changed is not relivant.
10890 * <script type="text/javascript">
10895 * @class Roo.CompositeElement
10896 * Standard composite class. Creates a Roo.Element for every element in the collection.
10898 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10899 * actions will be performed on all the elements in this collection.</b>
10901 * All methods return <i>this</i> and can be chained.
10903 var els = Roo.select("#some-el div.some-class", true);
10904 // or select directly from an existing element
10905 var el = Roo.get('some-el');
10906 el.select('div.some-class', true);
10908 els.setWidth(100); // all elements become 100 width
10909 els.hide(true); // all elements fade out and hide
10911 els.setWidth(100).hide(true);
10914 Roo.CompositeElement = function(els){
10915 this.elements = [];
10916 this.addElements(els);
10918 Roo.CompositeElement.prototype = {
10920 addElements : function(els){
10921 if(!els) return this;
10922 if(typeof els == "string"){
10923 els = Roo.Element.selectorFunction(els);
10925 var yels = this.elements;
10926 var index = yels.length-1;
10927 for(var i = 0, len = els.length; i < len; i++) {
10928 yels[++index] = Roo.get(els[i]);
10934 * Clears this composite and adds the elements returned by the passed selector.
10935 * @param {String/Array} els A string CSS selector, an array of elements or an element
10936 * @return {CompositeElement} this
10938 fill : function(els){
10939 this.elements = [];
10945 * Filters this composite to only elements that match the passed selector.
10946 * @param {String} selector A string CSS selector
10947 * @return {CompositeElement} this
10949 filter : function(selector){
10951 this.each(function(el){
10952 if(el.is(selector)){
10953 els[els.length] = el.dom;
10960 invoke : function(fn, args){
10961 var els = this.elements;
10962 for(var i = 0, len = els.length; i < len; i++) {
10963 Roo.Element.prototype[fn].apply(els[i], args);
10968 * Adds elements to this composite.
10969 * @param {String/Array} els A string CSS selector, an array of elements or an element
10970 * @return {CompositeElement} this
10972 add : function(els){
10973 if(typeof els == "string"){
10974 this.addElements(Roo.Element.selectorFunction(els));
10975 }else if(els.length !== undefined){
10976 this.addElements(els);
10978 this.addElements([els]);
10983 * Calls the passed function passing (el, this, index) for each element in this composite.
10984 * @param {Function} fn The function to call
10985 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10986 * @return {CompositeElement} this
10988 each : function(fn, scope){
10989 var els = this.elements;
10990 for(var i = 0, len = els.length; i < len; i++){
10991 if(fn.call(scope || els[i], els[i], this, i) === false) {
10999 * Returns the Element object at the specified index
11000 * @param {Number} index
11001 * @return {Roo.Element}
11003 item : function(index){
11004 return this.elements[index] || null;
11008 * Returns the first Element
11009 * @return {Roo.Element}
11011 first : function(){
11012 return this.item(0);
11016 * Returns the last Element
11017 * @return {Roo.Element}
11020 return this.item(this.elements.length-1);
11024 * Returns the number of elements in this composite
11027 getCount : function(){
11028 return this.elements.length;
11032 * Returns true if this composite contains the passed element
11035 contains : function(el){
11036 return this.indexOf(el) !== -1;
11040 * Returns true if this composite contains the passed element
11043 indexOf : function(el){
11044 return this.elements.indexOf(Roo.get(el));
11049 * Removes the specified element(s).
11050 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11051 * or an array of any of those.
11052 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11053 * @return {CompositeElement} this
11055 removeElement : function(el, removeDom){
11056 if(el instanceof Array){
11057 for(var i = 0, len = el.length; i < len; i++){
11058 this.removeElement(el[i]);
11062 var index = typeof el == 'number' ? el : this.indexOf(el);
11065 var d = this.elements[index];
11069 d.parentNode.removeChild(d);
11072 this.elements.splice(index, 1);
11078 * Replaces the specified element with the passed element.
11079 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11081 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11082 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11083 * @return {CompositeElement} this
11085 replaceElement : function(el, replacement, domReplace){
11086 var index = typeof el == 'number' ? el : this.indexOf(el);
11089 this.elements[index].replaceWith(replacement);
11091 this.elements.splice(index, 1, Roo.get(replacement))
11098 * Removes all elements.
11100 clear : function(){
11101 this.elements = [];
11105 Roo.CompositeElement.createCall = function(proto, fnName){
11106 if(!proto[fnName]){
11107 proto[fnName] = function(){
11108 return this.invoke(fnName, arguments);
11112 for(var fnName in Roo.Element.prototype){
11113 if(typeof Roo.Element.prototype[fnName] == "function"){
11114 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11120 * Ext JS Library 1.1.1
11121 * Copyright(c) 2006-2007, Ext JS, LLC.
11123 * Originally Released Under LGPL - original licence link has changed is not relivant.
11126 * <script type="text/javascript">
11130 * @class Roo.CompositeElementLite
11131 * @extends Roo.CompositeElement
11132 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11134 var els = Roo.select("#some-el div.some-class");
11135 // or select directly from an existing element
11136 var el = Roo.get('some-el');
11137 el.select('div.some-class');
11139 els.setWidth(100); // all elements become 100 width
11140 els.hide(true); // all elements fade out and hide
11142 els.setWidth(100).hide(true);
11143 </code></pre><br><br>
11144 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11145 * actions will be performed on all the elements in this collection.</b>
11147 Roo.CompositeElementLite = function(els){
11148 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11149 this.el = new Roo.Element.Flyweight();
11151 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11152 addElements : function(els){
11154 if(els instanceof Array){
11155 this.elements = this.elements.concat(els);
11157 var yels = this.elements;
11158 var index = yels.length-1;
11159 for(var i = 0, len = els.length; i < len; i++) {
11160 yels[++index] = els[i];
11166 invoke : function(fn, args){
11167 var els = this.elements;
11169 for(var i = 0, len = els.length; i < len; i++) {
11171 Roo.Element.prototype[fn].apply(el, args);
11176 * Returns a flyweight Element of the dom element object at the specified index
11177 * @param {Number} index
11178 * @return {Roo.Element}
11180 item : function(index){
11181 if(!this.elements[index]){
11184 this.el.dom = this.elements[index];
11188 // fixes scope with flyweight
11189 addListener : function(eventName, handler, scope, opt){
11190 var els = this.elements;
11191 for(var i = 0, len = els.length; i < len; i++) {
11192 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11198 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11199 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11200 * a reference to the dom node, use el.dom.</b>
11201 * @param {Function} fn The function to call
11202 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11203 * @return {CompositeElement} this
11205 each : function(fn, scope){
11206 var els = this.elements;
11208 for(var i = 0, len = els.length; i < len; i++){
11210 if(fn.call(scope || el, el, this, i) === false){
11217 indexOf : function(el){
11218 return this.elements.indexOf(Roo.getDom(el));
11221 replaceElement : function(el, replacement, domReplace){
11222 var index = typeof el == 'number' ? el : this.indexOf(el);
11224 replacement = Roo.getDom(replacement);
11226 var d = this.elements[index];
11227 d.parentNode.insertBefore(replacement, d);
11228 d.parentNode.removeChild(d);
11230 this.elements.splice(index, 1, replacement);
11235 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11239 * Ext JS Library 1.1.1
11240 * Copyright(c) 2006-2007, Ext JS, LLC.
11242 * Originally Released Under LGPL - original licence link has changed is not relivant.
11245 * <script type="text/javascript">
11251 * @class Roo.data.Connection
11252 * @extends Roo.util.Observable
11253 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11254 * either to a configured URL, or to a URL specified at request time.<br><br>
11256 * Requests made by this class are asynchronous, and will return immediately. No data from
11257 * the server will be available to the statement immediately following the {@link #request} call.
11258 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11260 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11261 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11262 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11263 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11264 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11265 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11266 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11267 * standard DOM methods.
11269 * @param {Object} config a configuration object.
11271 Roo.data.Connection = function(config){
11272 Roo.apply(this, config);
11275 * @event beforerequest
11276 * Fires before a network request is made to retrieve a data object.
11277 * @param {Connection} conn This Connection object.
11278 * @param {Object} options The options config object passed to the {@link #request} method.
11280 "beforerequest" : true,
11282 * @event requestcomplete
11283 * Fires if the request was successfully completed.
11284 * @param {Connection} conn This Connection object.
11285 * @param {Object} response The XHR object containing the response data.
11286 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11287 * @param {Object} options The options config object passed to the {@link #request} method.
11289 "requestcomplete" : true,
11291 * @event requestexception
11292 * Fires if an error HTTP status was returned from the server.
11293 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11294 * @param {Connection} conn This Connection object.
11295 * @param {Object} response The XHR object containing the response data.
11296 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11297 * @param {Object} options The options config object passed to the {@link #request} method.
11299 "requestexception" : true
11301 Roo.data.Connection.superclass.constructor.call(this);
11304 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11306 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11309 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11310 * extra parameters to each request made by this object. (defaults to undefined)
11313 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11314 * to each request made by this object. (defaults to undefined)
11317 * @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)
11320 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11324 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11330 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11333 disableCaching: true,
11336 * Sends an HTTP request to a remote server.
11337 * @param {Object} options An object which may contain the following properties:<ul>
11338 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11339 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11340 * request, a url encoded string or a function to call to get either.</li>
11341 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11342 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11343 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11344 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11345 * <li>options {Object} The parameter to the request call.</li>
11346 * <li>success {Boolean} True if the request succeeded.</li>
11347 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11349 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11350 * The callback is passed the following parameters:<ul>
11351 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11352 * <li>options {Object} The parameter to the request call.</li>
11354 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11355 * The callback is passed the following parameters:<ul>
11356 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11357 * <li>options {Object} The parameter to the request call.</li>
11359 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11360 * for the callback function. Defaults to the browser window.</li>
11361 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11362 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11363 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11364 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11365 * params for the post data. Any params will be appended to the URL.</li>
11366 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11368 * @return {Number} transactionId
11370 request : function(o){
11371 if(this.fireEvent("beforerequest", this, o) !== false){
11374 if(typeof p == "function"){
11375 p = p.call(o.scope||window, o);
11377 if(typeof p == "object"){
11378 p = Roo.urlEncode(o.params);
11380 if(this.extraParams){
11381 var extras = Roo.urlEncode(this.extraParams);
11382 p = p ? (p + '&' + extras) : extras;
11385 var url = o.url || this.url;
11386 if(typeof url == 'function'){
11387 url = url.call(o.scope||window, o);
11391 var form = Roo.getDom(o.form);
11392 url = url || form.action;
11394 var enctype = form.getAttribute("enctype");
11395 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11396 return this.doFormUpload(o, p, url);
11398 var f = Roo.lib.Ajax.serializeForm(form);
11399 p = p ? (p + '&' + f) : f;
11402 var hs = o.headers;
11403 if(this.defaultHeaders){
11404 hs = Roo.apply(hs || {}, this.defaultHeaders);
11411 success: this.handleResponse,
11412 failure: this.handleFailure,
11414 argument: {options: o},
11415 timeout : o.timeout || this.timeout
11418 var method = o.method||this.method||(p ? "POST" : "GET");
11420 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11421 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11424 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11428 }else if(this.autoAbort !== false){
11432 if((method == 'GET' && p) || o.xmlData){
11433 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11436 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11437 return this.transId;
11439 Roo.callback(o.callback, o.scope, [o, null, null]);
11445 * Determine whether this object has a request outstanding.
11446 * @param {Number} transactionId (Optional) defaults to the last transaction
11447 * @return {Boolean} True if there is an outstanding request.
11449 isLoading : function(transId){
11451 return Roo.lib.Ajax.isCallInProgress(transId);
11453 return this.transId ? true : false;
11458 * Aborts any outstanding request.
11459 * @param {Number} transactionId (Optional) defaults to the last transaction
11461 abort : function(transId){
11462 if(transId || this.isLoading()){
11463 Roo.lib.Ajax.abort(transId || this.transId);
11468 handleResponse : function(response){
11469 this.transId = false;
11470 var options = response.argument.options;
11471 response.argument = options ? options.argument : null;
11472 this.fireEvent("requestcomplete", this, response, options);
11473 Roo.callback(options.success, options.scope, [response, options]);
11474 Roo.callback(options.callback, options.scope, [options, true, response]);
11478 handleFailure : function(response, e){
11479 this.transId = false;
11480 var options = response.argument.options;
11481 response.argument = options ? options.argument : null;
11482 this.fireEvent("requestexception", this, response, options, e);
11483 Roo.callback(options.failure, options.scope, [response, options]);
11484 Roo.callback(options.callback, options.scope, [options, false, response]);
11488 doFormUpload : function(o, ps, url){
11490 var frame = document.createElement('iframe');
11493 frame.className = 'x-hidden';
11495 frame.src = Roo.SSL_SECURE_URL;
11497 document.body.appendChild(frame);
11500 document.frames[id].name = id;
11503 var form = Roo.getDom(o.form);
11505 form.method = 'POST';
11506 form.enctype = form.encoding = 'multipart/form-data';
11512 if(ps){ // add dynamic params
11514 ps = Roo.urlDecode(ps, false);
11516 if(ps.hasOwnProperty(k)){
11517 hd = document.createElement('input');
11518 hd.type = 'hidden';
11521 form.appendChild(hd);
11528 var r = { // bogus response object
11533 r.argument = o ? o.argument : null;
11538 doc = frame.contentWindow.document;
11540 doc = (frame.contentDocument || window.frames[id].document);
11542 if(doc && doc.body){
11543 r.responseText = doc.body.innerHTML;
11545 if(doc && doc.XMLDocument){
11546 r.responseXML = doc.XMLDocument;
11548 r.responseXML = doc;
11555 Roo.EventManager.removeListener(frame, 'load', cb, this);
11557 this.fireEvent("requestcomplete", this, r, o);
11558 Roo.callback(o.success, o.scope, [r, o]);
11559 Roo.callback(o.callback, o.scope, [o, true, r]);
11561 setTimeout(function(){document.body.removeChild(frame);}, 100);
11564 Roo.EventManager.on(frame, 'load', cb, this);
11567 if(hiddens){ // remove dynamic params
11568 for(var i = 0, len = hiddens.length; i < len; i++){
11569 form.removeChild(hiddens[i]);
11576 * Ext JS Library 1.1.1
11577 * Copyright(c) 2006-2007, Ext JS, LLC.
11579 * Originally Released Under LGPL - original licence link has changed is not relivant.
11582 * <script type="text/javascript">
11586 * Global Ajax request class.
11589 * @extends Roo.data.Connection
11592 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11593 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11594 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11595 * @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)
11596 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11597 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11598 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11600 Roo.Ajax = new Roo.data.Connection({
11609 * Serialize the passed form into a url encoded string
11611 * @param {String/HTMLElement} form
11614 serializeForm : function(form){
11615 return Roo.lib.Ajax.serializeForm(form);
11619 * Ext JS Library 1.1.1
11620 * Copyright(c) 2006-2007, Ext JS, LLC.
11622 * Originally Released Under LGPL - original licence link has changed is not relivant.
11625 * <script type="text/javascript">
11630 * @class Roo.UpdateManager
11631 * @extends Roo.util.Observable
11632 * Provides AJAX-style update for Element object.<br><br>
11635 * // Get it from a Roo.Element object
11636 * var el = Roo.get("foo");
11637 * var mgr = el.getUpdateManager();
11638 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11640 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11642 * // or directly (returns the same UpdateManager instance)
11643 * var mgr = new Roo.UpdateManager("myElementId");
11644 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11645 * mgr.on("update", myFcnNeedsToKnow);
11647 // short handed call directly from the element object
11648 Roo.get("foo").load({
11652 text: "Loading Foo..."
11656 * Create new UpdateManager directly.
11657 * @param {String/HTMLElement/Roo.Element} el The element to update
11658 * @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).
11660 Roo.UpdateManager = function(el, forceNew){
11662 if(!forceNew && el.updateManager){
11663 return el.updateManager;
11666 * The Element object
11667 * @type Roo.Element
11671 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11674 this.defaultUrl = null;
11678 * @event beforeupdate
11679 * Fired before an update is made, return false from your handler and the update is cancelled.
11680 * @param {Roo.Element} el
11681 * @param {String/Object/Function} url
11682 * @param {String/Object} params
11684 "beforeupdate": true,
11687 * Fired after successful update is made.
11688 * @param {Roo.Element} el
11689 * @param {Object} oResponseObject The response Object
11694 * Fired on update failure.
11695 * @param {Roo.Element} el
11696 * @param {Object} oResponseObject The response Object
11700 var d = Roo.UpdateManager.defaults;
11702 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11705 this.sslBlankUrl = d.sslBlankUrl;
11707 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11710 this.disableCaching = d.disableCaching;
11712 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11715 this.indicatorText = d.indicatorText;
11717 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11720 this.showLoadIndicator = d.showLoadIndicator;
11722 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11725 this.timeout = d.timeout;
11728 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11731 this.loadScripts = d.loadScripts;
11734 * Transaction object of current executing transaction
11736 this.transaction = null;
11741 this.autoRefreshProcId = null;
11743 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11746 this.refreshDelegate = this.refresh.createDelegate(this);
11748 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11751 this.updateDelegate = this.update.createDelegate(this);
11753 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11756 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11760 this.successDelegate = this.processSuccess.createDelegate(this);
11764 this.failureDelegate = this.processFailure.createDelegate(this);
11766 if(!this.renderer){
11768 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11770 this.renderer = new Roo.UpdateManager.BasicRenderer();
11773 Roo.UpdateManager.superclass.constructor.call(this);
11776 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11778 * Get the Element this UpdateManager is bound to
11779 * @return {Roo.Element} The element
11781 getEl : function(){
11785 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11786 * @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:
11789 url: "your-url.php",<br/>
11790 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11791 callback: yourFunction,<br/>
11792 scope: yourObject, //(optional scope) <br/>
11793 discardUrl: false, <br/>
11794 nocache: false,<br/>
11795 text: "Loading...",<br/>
11797 scripts: false<br/>
11800 * The only required property is url. The optional properties nocache, text and scripts
11801 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11802 * @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}
11803 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11804 * @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.
11806 update : function(url, params, callback, discardUrl){
11807 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11808 var method = this.method,
11810 if(typeof url == "object"){ // must be config object
11813 params = params || cfg.params;
11814 callback = callback || cfg.callback;
11815 discardUrl = discardUrl || cfg.discardUrl;
11816 if(callback && cfg.scope){
11817 callback = callback.createDelegate(cfg.scope);
11819 if(typeof cfg.method != "undefined"){method = cfg.method;};
11820 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11821 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11822 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11823 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11825 this.showLoading();
11827 this.defaultUrl = url;
11829 if(typeof url == "function"){
11830 url = url.call(this);
11833 method = method || (params ? "POST" : "GET");
11834 if(method == "GET"){
11835 url = this.prepareUrl(url);
11838 var o = Roo.apply(cfg ||{}, {
11841 success: this.successDelegate,
11842 failure: this.failureDelegate,
11843 callback: undefined,
11844 timeout: (this.timeout*1000),
11845 argument: {"url": url, "form": null, "callback": callback, "params": params}
11847 Roo.log("updated manager called with timeout of " + o.timeout);
11848 this.transaction = Roo.Ajax.request(o);
11853 * 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.
11854 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11855 * @param {String/HTMLElement} form The form Id or form element
11856 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11857 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11858 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11860 formUpdate : function(form, url, reset, callback){
11861 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11862 if(typeof url == "function"){
11863 url = url.call(this);
11865 form = Roo.getDom(form);
11866 this.transaction = Roo.Ajax.request({
11869 success: this.successDelegate,
11870 failure: this.failureDelegate,
11871 timeout: (this.timeout*1000),
11872 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11874 this.showLoading.defer(1, this);
11879 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11880 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11882 refresh : function(callback){
11883 if(this.defaultUrl == null){
11886 this.update(this.defaultUrl, null, callback, true);
11890 * Set this element to auto refresh.
11891 * @param {Number} interval How often to update (in seconds).
11892 * @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)
11893 * @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}
11894 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11895 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11897 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11899 this.update(url || this.defaultUrl, params, callback, true);
11901 if(this.autoRefreshProcId){
11902 clearInterval(this.autoRefreshProcId);
11904 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11908 * Stop auto refresh on this element.
11910 stopAutoRefresh : function(){
11911 if(this.autoRefreshProcId){
11912 clearInterval(this.autoRefreshProcId);
11913 delete this.autoRefreshProcId;
11917 isAutoRefreshing : function(){
11918 return this.autoRefreshProcId ? true : false;
11921 * Called to update the element to "Loading" state. Override to perform custom action.
11923 showLoading : function(){
11924 if(this.showLoadIndicator){
11925 this.el.update(this.indicatorText);
11930 * Adds unique parameter to query string if disableCaching = true
11933 prepareUrl : function(url){
11934 if(this.disableCaching){
11935 var append = "_dc=" + (new Date().getTime());
11936 if(url.indexOf("?") !== -1){
11937 url += "&" + append;
11939 url += "?" + append;
11948 processSuccess : function(response){
11949 this.transaction = null;
11950 if(response.argument.form && response.argument.reset){
11951 try{ // put in try/catch since some older FF releases had problems with this
11952 response.argument.form.reset();
11955 if(this.loadScripts){
11956 this.renderer.render(this.el, response, this,
11957 this.updateComplete.createDelegate(this, [response]));
11959 this.renderer.render(this.el, response, this);
11960 this.updateComplete(response);
11964 updateComplete : function(response){
11965 this.fireEvent("update", this.el, response);
11966 if(typeof response.argument.callback == "function"){
11967 response.argument.callback(this.el, true, response);
11974 processFailure : function(response){
11975 this.transaction = null;
11976 this.fireEvent("failure", this.el, response);
11977 if(typeof response.argument.callback == "function"){
11978 response.argument.callback(this.el, false, response);
11983 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11984 * @param {Object} renderer The object implementing the render() method
11986 setRenderer : function(renderer){
11987 this.renderer = renderer;
11990 getRenderer : function(){
11991 return this.renderer;
11995 * Set the defaultUrl used for updates
11996 * @param {String/Function} defaultUrl The url or a function to call to get the url
11998 setDefaultUrl : function(defaultUrl){
11999 this.defaultUrl = defaultUrl;
12003 * Aborts the executing transaction
12005 abort : function(){
12006 if(this.transaction){
12007 Roo.Ajax.abort(this.transaction);
12012 * Returns true if an update is in progress
12013 * @return {Boolean}
12015 isUpdating : function(){
12016 if(this.transaction){
12017 return Roo.Ajax.isLoading(this.transaction);
12024 * @class Roo.UpdateManager.defaults
12025 * @static (not really - but it helps the doc tool)
12026 * The defaults collection enables customizing the default properties of UpdateManager
12028 Roo.UpdateManager.defaults = {
12030 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12036 * True to process scripts by default (Defaults to false).
12039 loadScripts : false,
12042 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12045 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12047 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12050 disableCaching : false,
12052 * Whether to show indicatorText when loading (Defaults to true).
12055 showLoadIndicator : true,
12057 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12060 indicatorText : '<div class="loading-indicator">Loading...</div>'
12064 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12066 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12067 * @param {String/HTMLElement/Roo.Element} el The element to update
12068 * @param {String} url The url
12069 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12070 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12073 * @member Roo.UpdateManager
12075 Roo.UpdateManager.updateElement = function(el, url, params, options){
12076 var um = Roo.get(el, true).getUpdateManager();
12077 Roo.apply(um, options);
12078 um.update(url, params, options ? options.callback : null);
12080 // alias for backwards compat
12081 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12083 * @class Roo.UpdateManager.BasicRenderer
12084 * Default Content renderer. Updates the elements innerHTML with the responseText.
12086 Roo.UpdateManager.BasicRenderer = function(){};
12088 Roo.UpdateManager.BasicRenderer.prototype = {
12090 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12091 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12092 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12093 * @param {Roo.Element} el The element being rendered
12094 * @param {Object} response The YUI Connect response object
12095 * @param {UpdateManager} updateManager The calling update manager
12096 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12098 render : function(el, response, updateManager, callback){
12099 el.update(response.responseText, updateManager.loadScripts, callback);
12105 * (c)) Alan Knowles
12111 * @class Roo.DomTemplate
12112 * @extends Roo.Template
12113 * An effort at a dom based template engine..
12115 * Similar to XTemplate, except it uses dom parsing to create the template..
12117 * Supported features:
12122 {a_variable} - output encoded.
12123 {a_variable.format:("Y-m-d")} - call a method on the variable
12124 {a_variable:raw} - unencoded output
12125 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12126 {a_variable:this.method_on_template(...)} - call a method on the template object.
12131 <div roo-for="a_variable or condition.."></div>
12132 <div roo-if="a_variable or condition"></div>
12133 <div roo-exec="some javascript"></div>
12134 <div roo-name="named_template"></div>
12139 Roo.DomTemplate = function()
12141 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12148 Roo.extend(Roo.DomTemplate, Roo.Template, {
12150 * id counter for sub templates.
12154 * flag to indicate if dom parser is inside a pre,
12155 * it will strip whitespace if not.
12160 * The various sub templates
12168 * basic tag replacing syntax
12171 * // you can fake an object call by doing this
12175 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12176 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12178 iterChild : function (node, method) {
12180 var oldPre = this.inPre;
12181 if (node.tagName == 'PRE') {
12184 for( var i = 0; i < node.childNodes.length; i++) {
12185 method.call(this, node.childNodes[i]);
12187 this.inPre = oldPre;
12193 * compile the template
12195 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12198 compile: function()
12202 // covert the html into DOM...
12206 doc = document.implementation.createHTMLDocument("");
12207 doc.documentElement.innerHTML = this.html ;
12208 div = doc.documentElement;
12210 // old IE... - nasty -- it causes all sorts of issues.. with
12211 // images getting pulled from server..
12212 div = document.createElement('div');
12213 div.innerHTML = this.html;
12215 //doc.documentElement.innerHTML = htmlBody
12221 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12223 var tpls = this.tpls;
12225 // create a top level template from the snippet..
12227 //Roo.log(div.innerHTML);
12234 body : div.innerHTML,
12247 Roo.each(tpls, function(tp){
12248 this.compileTpl(tp);
12249 this.tpls[tp.id] = tp;
12252 this.master = tpls[0];
12258 compileNode : function(node, istop) {
12263 // skip anything not a tag..
12264 if (node.nodeType != 1) {
12265 if (node.nodeType == 3 && !this.inPre) {
12266 // reduce white space..
12267 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12290 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12291 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12292 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12293 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12299 // just itterate children..
12300 this.iterChild(node,this.compileNode);
12303 tpl.uid = this.id++;
12304 tpl.value = node.getAttribute('roo-' + tpl.attr);
12305 node.removeAttribute('roo-'+ tpl.attr);
12306 if (tpl.attr != 'name') {
12307 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12308 node.parentNode.replaceChild(placeholder, node);
12311 var placeholder = document.createElement('span');
12312 placeholder.className = 'roo-tpl-' + tpl.value;
12313 node.parentNode.replaceChild(placeholder, node);
12316 // parent now sees '{domtplXXXX}
12317 this.iterChild(node,this.compileNode);
12319 // we should now have node body...
12320 var div = document.createElement('div');
12321 div.appendChild(node);
12323 // this has the unfortunate side effect of converting tagged attributes
12324 // eg. href="{...}" into %7C...%7D
12325 // this has been fixed by searching for those combo's although it's a bit hacky..
12328 tpl.body = div.innerHTML;
12335 switch (tpl.value) {
12336 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12337 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12338 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12343 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12347 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12351 tpl.id = tpl.value; // replace non characters???
12357 this.tpls.push(tpl);
12367 * Compile a segment of the template into a 'sub-template'
12373 compileTpl : function(tpl)
12375 var fm = Roo.util.Format;
12376 var useF = this.disableFormats !== true;
12378 var sep = Roo.isGecko ? "+\n" : ",\n";
12380 var undef = function(str) {
12381 Roo.debug && Roo.log("Property not found :" + str);
12385 //Roo.log(tpl.body);
12389 var fn = function(m, lbrace, name, format, args)
12392 //Roo.log(arguments);
12393 args = args ? args.replace(/\\'/g,"'") : args;
12394 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12395 if (typeof(format) == 'undefined') {
12396 format = 'htmlEncode';
12398 if (format == 'raw' ) {
12402 if(name.substr(0, 6) == 'domtpl'){
12403 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12406 // build an array of options to determine if value is undefined..
12408 // basically get 'xxxx.yyyy' then do
12409 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12410 // (function () { Roo.log("Property not found"); return ''; })() :
12415 Roo.each(name.split('.'), function(st) {
12416 lookfor += (lookfor.length ? '.': '') + st;
12417 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12420 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12423 if(format && useF){
12425 args = args ? ',' + args : "";
12427 if(format.substr(0, 5) != "this."){
12428 format = "fm." + format + '(';
12430 format = 'this.call("'+ format.substr(5) + '", ';
12434 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12437 if (args && args.length) {
12438 // called with xxyx.yuu:(test,test)
12440 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12442 // raw.. - :raw modifier..
12443 return "'"+ sep + udef_st + name + ")"+sep+"'";
12447 // branched to use + in gecko and [].join() in others
12449 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12450 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12453 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12454 body.push(tpl.body.replace(/(\r\n|\n)/g,
12455 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12456 body.push("'].join('');};};");
12457 body = body.join('');
12460 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12462 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12469 * same as applyTemplate, except it's done to one of the subTemplates
12470 * when using named templates, you can do:
12472 * var str = pl.applySubTemplate('your-name', values);
12475 * @param {Number} id of the template
12476 * @param {Object} values to apply to template
12477 * @param {Object} parent (normaly the instance of this object)
12479 applySubTemplate : function(id, values, parent)
12483 var t = this.tpls[id];
12487 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12488 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12492 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12499 if(t.execCall && t.execCall.call(this, values, parent)){
12503 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12509 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12510 parent = t.target ? values : parent;
12511 if(t.forCall && vs instanceof Array){
12513 for(var i = 0, len = vs.length; i < len; i++){
12515 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12517 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12519 //Roo.log(t.compiled);
12523 return buf.join('');
12526 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12531 return t.compiled.call(this, vs, parent);
12533 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12535 //Roo.log(t.compiled);
12543 applyTemplate : function(values){
12544 return this.master.compiled.call(this, values, {});
12545 //var s = this.subs;
12548 apply : function(){
12549 return this.applyTemplate.apply(this, arguments);
12554 Roo.DomTemplate.from = function(el){
12555 el = Roo.getDom(el);
12556 return new Roo.Domtemplate(el.value || el.innerHTML);
12559 * Ext JS Library 1.1.1
12560 * Copyright(c) 2006-2007, Ext JS, LLC.
12562 * Originally Released Under LGPL - original licence link has changed is not relivant.
12565 * <script type="text/javascript">
12569 * @class Roo.util.DelayedTask
12570 * Provides a convenient method of performing setTimeout where a new
12571 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12572 * You can use this class to buffer
12573 * the keypress events for a certain number of milliseconds, and perform only if they stop
12574 * for that amount of time.
12575 * @constructor The parameters to this constructor serve as defaults and are not required.
12576 * @param {Function} fn (optional) The default function to timeout
12577 * @param {Object} scope (optional) The default scope of that timeout
12578 * @param {Array} args (optional) The default Array of arguments
12580 Roo.util.DelayedTask = function(fn, scope, args){
12581 var id = null, d, t;
12583 var call = function(){
12584 var now = new Date().getTime();
12588 fn.apply(scope, args || []);
12592 * Cancels any pending timeout and queues a new one
12593 * @param {Number} delay The milliseconds to delay
12594 * @param {Function} newFn (optional) Overrides function passed to constructor
12595 * @param {Object} newScope (optional) Overrides scope passed to constructor
12596 * @param {Array} newArgs (optional) Overrides args passed to constructor
12598 this.delay = function(delay, newFn, newScope, newArgs){
12599 if(id && delay != d){
12603 t = new Date().getTime();
12605 scope = newScope || scope;
12606 args = newArgs || args;
12608 id = setInterval(call, d);
12613 * Cancel the last queued timeout
12615 this.cancel = function(){
12623 * Ext JS Library 1.1.1
12624 * Copyright(c) 2006-2007, Ext JS, LLC.
12626 * Originally Released Under LGPL - original licence link has changed is not relivant.
12629 * <script type="text/javascript">
12633 Roo.util.TaskRunner = function(interval){
12634 interval = interval || 10;
12635 var tasks = [], removeQueue = [];
12637 var running = false;
12639 var stopThread = function(){
12645 var startThread = function(){
12648 id = setInterval(runTasks, interval);
12652 var removeTask = function(task){
12653 removeQueue.push(task);
12659 var runTasks = function(){
12660 if(removeQueue.length > 0){
12661 for(var i = 0, len = removeQueue.length; i < len; i++){
12662 tasks.remove(removeQueue[i]);
12665 if(tasks.length < 1){
12670 var now = new Date().getTime();
12671 for(var i = 0, len = tasks.length; i < len; ++i){
12673 var itime = now - t.taskRunTime;
12674 if(t.interval <= itime){
12675 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12676 t.taskRunTime = now;
12677 if(rt === false || t.taskRunCount === t.repeat){
12682 if(t.duration && t.duration <= (now - t.taskStartTime)){
12689 * Queues a new task.
12690 * @param {Object} task
12692 this.start = function(task){
12694 task.taskStartTime = new Date().getTime();
12695 task.taskRunTime = 0;
12696 task.taskRunCount = 0;
12701 this.stop = function(task){
12706 this.stopAll = function(){
12708 for(var i = 0, len = tasks.length; i < len; i++){
12709 if(tasks[i].onStop){
12718 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12720 * Ext JS Library 1.1.1
12721 * Copyright(c) 2006-2007, Ext JS, LLC.
12723 * Originally Released Under LGPL - original licence link has changed is not relivant.
12726 * <script type="text/javascript">
12731 * @class Roo.util.MixedCollection
12732 * @extends Roo.util.Observable
12733 * A Collection class that maintains both numeric indexes and keys and exposes events.
12735 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12736 * collection (defaults to false)
12737 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12738 * and return the key value for that item. This is used when available to look up the key on items that
12739 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12740 * equivalent to providing an implementation for the {@link #getKey} method.
12742 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12750 * Fires when the collection is cleared.
12755 * Fires when an item is added to the collection.
12756 * @param {Number} index The index at which the item was added.
12757 * @param {Object} o The item added.
12758 * @param {String} key The key associated with the added item.
12763 * Fires when an item is replaced in the collection.
12764 * @param {String} key he key associated with the new added.
12765 * @param {Object} old The item being replaced.
12766 * @param {Object} new The new item.
12771 * Fires when an item is removed from the collection.
12772 * @param {Object} o The item being removed.
12773 * @param {String} key (optional) The key associated with the removed item.
12778 this.allowFunctions = allowFunctions === true;
12780 this.getKey = keyFn;
12782 Roo.util.MixedCollection.superclass.constructor.call(this);
12785 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12786 allowFunctions : false,
12789 * Adds an item to the collection.
12790 * @param {String} key The key to associate with the item
12791 * @param {Object} o The item to add.
12792 * @return {Object} The item added.
12794 add : function(key, o){
12795 if(arguments.length == 1){
12797 key = this.getKey(o);
12799 if(typeof key == "undefined" || key === null){
12801 this.items.push(o);
12802 this.keys.push(null);
12804 var old = this.map[key];
12806 return this.replace(key, o);
12809 this.items.push(o);
12811 this.keys.push(key);
12813 this.fireEvent("add", this.length-1, o, key);
12818 * MixedCollection has a generic way to fetch keys if you implement getKey.
12821 var mc = new Roo.util.MixedCollection();
12822 mc.add(someEl.dom.id, someEl);
12823 mc.add(otherEl.dom.id, otherEl);
12827 var mc = new Roo.util.MixedCollection();
12828 mc.getKey = function(el){
12834 // or via the constructor
12835 var mc = new Roo.util.MixedCollection(false, function(el){
12841 * @param o {Object} The item for which to find the key.
12842 * @return {Object} The key for the passed item.
12844 getKey : function(o){
12849 * Replaces an item in the collection.
12850 * @param {String} key The key associated with the item to replace, or the item to replace.
12851 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12852 * @return {Object} The new item.
12854 replace : function(key, o){
12855 if(arguments.length == 1){
12857 key = this.getKey(o);
12859 var old = this.item(key);
12860 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12861 return this.add(key, o);
12863 var index = this.indexOfKey(key);
12864 this.items[index] = o;
12866 this.fireEvent("replace", key, old, o);
12871 * Adds all elements of an Array or an Object to the collection.
12872 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12873 * an Array of values, each of which are added to the collection.
12875 addAll : function(objs){
12876 if(arguments.length > 1 || objs instanceof Array){
12877 var args = arguments.length > 1 ? arguments : objs;
12878 for(var i = 0, len = args.length; i < len; i++){
12882 for(var key in objs){
12883 if(this.allowFunctions || typeof objs[key] != "function"){
12884 this.add(key, objs[key]);
12891 * Executes the specified function once for every item in the collection, passing each
12892 * item as the first and only parameter. returning false from the function will stop the iteration.
12893 * @param {Function} fn The function to execute for each item.
12894 * @param {Object} scope (optional) The scope in which to execute the function.
12896 each : function(fn, scope){
12897 var items = [].concat(this.items); // each safe for removal
12898 for(var i = 0, len = items.length; i < len; i++){
12899 if(fn.call(scope || items[i], items[i], i, len) === false){
12906 * Executes the specified function once for every key in the collection, passing each
12907 * key, and its associated item as the first two parameters.
12908 * @param {Function} fn The function to execute for each item.
12909 * @param {Object} scope (optional) The scope in which to execute the function.
12911 eachKey : function(fn, scope){
12912 for(var i = 0, len = this.keys.length; i < len; i++){
12913 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12918 * Returns the first item in the collection which elicits a true return value from the
12919 * passed selection function.
12920 * @param {Function} fn The selection function to execute for each item.
12921 * @param {Object} scope (optional) The scope in which to execute the function.
12922 * @return {Object} The first item in the collection which returned true from the selection function.
12924 find : function(fn, scope){
12925 for(var i = 0, len = this.items.length; i < len; i++){
12926 if(fn.call(scope || window, this.items[i], this.keys[i])){
12927 return this.items[i];
12934 * Inserts an item at the specified index in the collection.
12935 * @param {Number} index The index to insert the item at.
12936 * @param {String} key The key to associate with the new item, or the item itself.
12937 * @param {Object} o (optional) If the second parameter was a key, the new item.
12938 * @return {Object} The item inserted.
12940 insert : function(index, key, o){
12941 if(arguments.length == 2){
12943 key = this.getKey(o);
12945 if(index >= this.length){
12946 return this.add(key, o);
12949 this.items.splice(index, 0, o);
12950 if(typeof key != "undefined" && key != null){
12953 this.keys.splice(index, 0, key);
12954 this.fireEvent("add", index, o, key);
12959 * Removed an item from the collection.
12960 * @param {Object} o The item to remove.
12961 * @return {Object} The item removed.
12963 remove : function(o){
12964 return this.removeAt(this.indexOf(o));
12968 * Remove an item from a specified index in the collection.
12969 * @param {Number} index The index within the collection of the item to remove.
12971 removeAt : function(index){
12972 if(index < this.length && index >= 0){
12974 var o = this.items[index];
12975 this.items.splice(index, 1);
12976 var key = this.keys[index];
12977 if(typeof key != "undefined"){
12978 delete this.map[key];
12980 this.keys.splice(index, 1);
12981 this.fireEvent("remove", o, key);
12986 * Removed an item associated with the passed key fom the collection.
12987 * @param {String} key The key of the item to remove.
12989 removeKey : function(key){
12990 return this.removeAt(this.indexOfKey(key));
12994 * Returns the number of items in the collection.
12995 * @return {Number} the number of items in the collection.
12997 getCount : function(){
12998 return this.length;
13002 * Returns index within the collection of the passed Object.
13003 * @param {Object} o The item to find the index of.
13004 * @return {Number} index of the item.
13006 indexOf : function(o){
13007 if(!this.items.indexOf){
13008 for(var i = 0, len = this.items.length; i < len; i++){
13009 if(this.items[i] == o) return i;
13013 return this.items.indexOf(o);
13018 * Returns index within the collection of the passed key.
13019 * @param {String} key The key to find the index of.
13020 * @return {Number} index of the key.
13022 indexOfKey : function(key){
13023 if(!this.keys.indexOf){
13024 for(var i = 0, len = this.keys.length; i < len; i++){
13025 if(this.keys[i] == key) return i;
13029 return this.keys.indexOf(key);
13034 * Returns the item associated with the passed key OR index. Key has priority over index.
13035 * @param {String/Number} key The key or index of the item.
13036 * @return {Object} The item associated with the passed key.
13038 item : function(key){
13039 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13040 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13044 * Returns the item at the specified index.
13045 * @param {Number} index The index of the item.
13048 itemAt : function(index){
13049 return this.items[index];
13053 * Returns the item associated with the passed key.
13054 * @param {String/Number} key The key of the item.
13055 * @return {Object} The item associated with the passed key.
13057 key : function(key){
13058 return this.map[key];
13062 * Returns true if the collection contains the passed Object as an item.
13063 * @param {Object} o The Object to look for in the collection.
13064 * @return {Boolean} True if the collection contains the Object as an item.
13066 contains : function(o){
13067 return this.indexOf(o) != -1;
13071 * Returns true if the collection contains the passed Object as a key.
13072 * @param {String} key The key to look for in the collection.
13073 * @return {Boolean} True if the collection contains the Object as a key.
13075 containsKey : function(key){
13076 return typeof this.map[key] != "undefined";
13080 * Removes all items from the collection.
13082 clear : function(){
13087 this.fireEvent("clear");
13091 * Returns the first item in the collection.
13092 * @return {Object} the first item in the collection..
13094 first : function(){
13095 return this.items[0];
13099 * Returns the last item in the collection.
13100 * @return {Object} the last item in the collection..
13103 return this.items[this.length-1];
13106 _sort : function(property, dir, fn){
13107 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13108 fn = fn || function(a, b){
13111 var c = [], k = this.keys, items = this.items;
13112 for(var i = 0, len = items.length; i < len; i++){
13113 c[c.length] = {key: k[i], value: items[i], index: i};
13115 c.sort(function(a, b){
13116 var v = fn(a[property], b[property]) * dsc;
13118 v = (a.index < b.index ? -1 : 1);
13122 for(var i = 0, len = c.length; i < len; i++){
13123 items[i] = c[i].value;
13126 this.fireEvent("sort", this);
13130 * Sorts this collection with the passed comparison function
13131 * @param {String} direction (optional) "ASC" or "DESC"
13132 * @param {Function} fn (optional) comparison function
13134 sort : function(dir, fn){
13135 this._sort("value", dir, fn);
13139 * Sorts this collection by keys
13140 * @param {String} direction (optional) "ASC" or "DESC"
13141 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13143 keySort : function(dir, fn){
13144 this._sort("key", dir, fn || function(a, b){
13145 return String(a).toUpperCase()-String(b).toUpperCase();
13150 * Returns a range of items in this collection
13151 * @param {Number} startIndex (optional) defaults to 0
13152 * @param {Number} endIndex (optional) default to the last item
13153 * @return {Array} An array of items
13155 getRange : function(start, end){
13156 var items = this.items;
13157 if(items.length < 1){
13160 start = start || 0;
13161 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13164 for(var i = start; i <= end; i++) {
13165 r[r.length] = items[i];
13168 for(var i = start; i >= end; i--) {
13169 r[r.length] = items[i];
13176 * Filter the <i>objects</i> in this collection by a specific property.
13177 * Returns a new collection that has been filtered.
13178 * @param {String} property A property on your objects
13179 * @param {String/RegExp} value Either string that the property values
13180 * should start with or a RegExp to test against the property
13181 * @return {MixedCollection} The new filtered collection
13183 filter : function(property, value){
13184 if(!value.exec){ // not a regex
13185 value = String(value);
13186 if(value.length == 0){
13187 return this.clone();
13189 value = new RegExp("^" + Roo.escapeRe(value), "i");
13191 return this.filterBy(function(o){
13192 return o && value.test(o[property]);
13197 * Filter by a function. * Returns a new collection that has been filtered.
13198 * The passed function will be called with each
13199 * object in the collection. If the function returns true, the value is included
13200 * otherwise it is filtered.
13201 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13202 * @param {Object} scope (optional) The scope of the function (defaults to this)
13203 * @return {MixedCollection} The new filtered collection
13205 filterBy : function(fn, scope){
13206 var r = new Roo.util.MixedCollection();
13207 r.getKey = this.getKey;
13208 var k = this.keys, it = this.items;
13209 for(var i = 0, len = it.length; i < len; i++){
13210 if(fn.call(scope||this, it[i], k[i])){
13211 r.add(k[i], it[i]);
13218 * Creates a duplicate of this collection
13219 * @return {MixedCollection}
13221 clone : function(){
13222 var r = new Roo.util.MixedCollection();
13223 var k = this.keys, it = this.items;
13224 for(var i = 0, len = it.length; i < len; i++){
13225 r.add(k[i], it[i]);
13227 r.getKey = this.getKey;
13232 * Returns the item associated with the passed key or index.
13234 * @param {String/Number} key The key or index of the item.
13235 * @return {Object} The item associated with the passed key.
13237 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13239 * Ext JS Library 1.1.1
13240 * Copyright(c) 2006-2007, Ext JS, LLC.
13242 * Originally Released Under LGPL - original licence link has changed is not relivant.
13245 * <script type="text/javascript">
13248 * @class Roo.util.JSON
13249 * Modified version of Douglas Crockford"s json.js that doesn"t
13250 * mess with the Object prototype
13251 * http://www.json.org/js.html
13254 Roo.util.JSON = new (function(){
13255 var useHasOwn = {}.hasOwnProperty ? true : false;
13257 // crashes Safari in some instances
13258 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13260 var pad = function(n) {
13261 return n < 10 ? "0" + n : n;
13274 var encodeString = function(s){
13275 if (/["\\\x00-\x1f]/.test(s)) {
13276 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13281 c = b.charCodeAt();
13283 Math.floor(c / 16).toString(16) +
13284 (c % 16).toString(16);
13287 return '"' + s + '"';
13290 var encodeArray = function(o){
13291 var a = ["["], b, i, l = o.length, v;
13292 for (i = 0; i < l; i += 1) {
13294 switch (typeof v) {
13303 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13311 var encodeDate = function(o){
13312 return '"' + o.getFullYear() + "-" +
13313 pad(o.getMonth() + 1) + "-" +
13314 pad(o.getDate()) + "T" +
13315 pad(o.getHours()) + ":" +
13316 pad(o.getMinutes()) + ":" +
13317 pad(o.getSeconds()) + '"';
13321 * Encodes an Object, Array or other value
13322 * @param {Mixed} o The variable to encode
13323 * @return {String} The JSON string
13325 this.encode = function(o)
13327 // should this be extended to fully wrap stringify..
13329 if(typeof o == "undefined" || o === null){
13331 }else if(o instanceof Array){
13332 return encodeArray(o);
13333 }else if(o instanceof Date){
13334 return encodeDate(o);
13335 }else if(typeof o == "string"){
13336 return encodeString(o);
13337 }else if(typeof o == "number"){
13338 return isFinite(o) ? String(o) : "null";
13339 }else if(typeof o == "boolean"){
13342 var a = ["{"], b, i, v;
13344 if(!useHasOwn || o.hasOwnProperty(i)) {
13346 switch (typeof v) {
13355 a.push(this.encode(i), ":",
13356 v === null ? "null" : this.encode(v));
13367 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13368 * @param {String} json The JSON string
13369 * @return {Object} The resulting object
13371 this.decode = function(json){
13373 return /** eval:var:json */ eval("(" + json + ')');
13377 * Shorthand for {@link Roo.util.JSON#encode}
13378 * @member Roo encode
13380 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13382 * Shorthand for {@link Roo.util.JSON#decode}
13383 * @member Roo decode
13385 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13388 * Ext JS Library 1.1.1
13389 * Copyright(c) 2006-2007, Ext JS, LLC.
13391 * Originally Released Under LGPL - original licence link has changed is not relivant.
13394 * <script type="text/javascript">
13398 * @class Roo.util.Format
13399 * Reusable data formatting functions
13402 Roo.util.Format = function(){
13403 var trimRe = /^\s+|\s+$/g;
13406 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13407 * @param {String} value The string to truncate
13408 * @param {Number} length The maximum length to allow before truncating
13409 * @return {String} The converted text
13411 ellipsis : function(value, len){
13412 if(value && value.length > len){
13413 return value.substr(0, len-3)+"...";
13419 * Checks a reference and converts it to empty string if it is undefined
13420 * @param {Mixed} value Reference to check
13421 * @return {Mixed} Empty string if converted, otherwise the original value
13423 undef : function(value){
13424 return typeof value != "undefined" ? value : "";
13428 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13429 * @param {String} value The string to encode
13430 * @return {String} The encoded text
13432 htmlEncode : function(value){
13433 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13437 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13438 * @param {String} value The string to decode
13439 * @return {String} The decoded text
13441 htmlDecode : function(value){
13442 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13446 * Trims any whitespace from either side of a string
13447 * @param {String} value The text to trim
13448 * @return {String} The trimmed text
13450 trim : function(value){
13451 return String(value).replace(trimRe, "");
13455 * Returns a substring from within an original string
13456 * @param {String} value The original text
13457 * @param {Number} start The start index of the substring
13458 * @param {Number} length The length of the substring
13459 * @return {String} The substring
13461 substr : function(value, start, length){
13462 return String(value).substr(start, length);
13466 * Converts a string to all lower case letters
13467 * @param {String} value The text to convert
13468 * @return {String} The converted text
13470 lowercase : function(value){
13471 return String(value).toLowerCase();
13475 * Converts a string to all upper case letters
13476 * @param {String} value The text to convert
13477 * @return {String} The converted text
13479 uppercase : function(value){
13480 return String(value).toUpperCase();
13484 * Converts the first character only of a string to upper case
13485 * @param {String} value The text to convert
13486 * @return {String} The converted text
13488 capitalize : function(value){
13489 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13493 call : function(value, fn){
13494 if(arguments.length > 2){
13495 var args = Array.prototype.slice.call(arguments, 2);
13496 args.unshift(value);
13498 return /** eval:var:value */ eval(fn).apply(window, args);
13500 /** eval:var:value */
13501 return /** eval:var:value */ eval(fn).call(window, value);
13507 * safer version of Math.toFixed..??/
13508 * @param {Number/String} value The numeric value to format
13509 * @param {Number/String} value Decimal places
13510 * @return {String} The formatted currency string
13512 toFixed : function(v, n)
13514 // why not use to fixed - precision is buggered???
13516 return Math.round(v-0);
13518 var fact = Math.pow(10,n+1);
13519 v = (Math.round((v-0)*fact))/fact;
13520 var z = (''+fact).substring(2);
13521 if (v == Math.floor(v)) {
13522 return Math.floor(v) + '.' + z;
13525 // now just padd decimals..
13526 var ps = String(v).split('.');
13527 var fd = (ps[1] + z);
13528 var r = fd.substring(0,n);
13529 var rm = fd.substring(n);
13531 return ps[0] + '.' + r;
13533 r*=1; // turn it into a number;
13535 if (String(r).length != n) {
13538 r = String(r).substring(1); // chop the end off.
13541 return ps[0] + '.' + r;
13546 * Format a number as US currency
13547 * @param {Number/String} value The numeric value to format
13548 * @return {String} The formatted currency string
13550 usMoney : function(v){
13551 return '$' + Roo.util.Format.number(v);
13556 * eventually this should probably emulate php's number_format
13557 * @param {Number/String} value The numeric value to format
13558 * @param {Number} decimals number of decimal places
13559 * @return {String} The formatted currency string
13561 number : function(v,decimals)
13563 // multiply and round.
13564 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13565 var mul = Math.pow(10, decimals);
13566 var zero = String(mul).substring(1);
13567 v = (Math.round((v-0)*mul))/mul;
13569 // if it's '0' number.. then
13571 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13573 var ps = v.split('.');
13577 var r = /(\d+)(\d{3})/;
13579 while (r.test(whole)) {
13580 whole = whole.replace(r, '$1' + ',' + '$2');
13586 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13587 // does not have decimals
13588 (decimals ? ('.' + zero) : '');
13591 return whole + sub ;
13595 * Parse a value into a formatted date using the specified format pattern.
13596 * @param {Mixed} value The value to format
13597 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13598 * @return {String} The formatted date string
13600 date : function(v, format){
13604 if(!(v instanceof Date)){
13605 v = new Date(Date.parse(v));
13607 return v.dateFormat(format || "m/d/Y");
13611 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13612 * @param {String} format Any valid date format string
13613 * @return {Function} The date formatting function
13615 dateRenderer : function(format){
13616 return function(v){
13617 return Roo.util.Format.date(v, format);
13622 stripTagsRE : /<\/?[^>]+>/gi,
13625 * Strips all HTML tags
13626 * @param {Mixed} value The text from which to strip tags
13627 * @return {String} The stripped text
13629 stripTags : function(v){
13630 return !v ? v : String(v).replace(this.stripTagsRE, "");
13635 * Ext JS Library 1.1.1
13636 * Copyright(c) 2006-2007, Ext JS, LLC.
13638 * Originally Released Under LGPL - original licence link has changed is not relivant.
13641 * <script type="text/javascript">
13648 * @class Roo.MasterTemplate
13649 * @extends Roo.Template
13650 * Provides a template that can have child templates. The syntax is:
13652 var t = new Roo.MasterTemplate(
13653 '<select name="{name}">',
13654 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13657 t.add('options', {value: 'foo', text: 'bar'});
13658 // or you can add multiple child elements in one shot
13659 t.addAll('options', [
13660 {value: 'foo', text: 'bar'},
13661 {value: 'foo2', text: 'bar2'},
13662 {value: 'foo3', text: 'bar3'}
13664 // then append, applying the master template values
13665 t.append('my-form', {name: 'my-select'});
13667 * A name attribute for the child template is not required if you have only one child
13668 * template or you want to refer to them by index.
13670 Roo.MasterTemplate = function(){
13671 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13672 this.originalHtml = this.html;
13674 var m, re = this.subTemplateRe;
13677 while(m = re.exec(this.html)){
13678 var name = m[1], content = m[2];
13683 tpl : new Roo.Template(content)
13686 st[name] = st[subIndex];
13688 st[subIndex].tpl.compile();
13689 st[subIndex].tpl.call = this.call.createDelegate(this);
13692 this.subCount = subIndex;
13695 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13697 * The regular expression used to match sub templates
13701 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13704 * Applies the passed values to a child template.
13705 * @param {String/Number} name (optional) The name or index of the child template
13706 * @param {Array/Object} values The values to be applied to the template
13707 * @return {MasterTemplate} this
13709 add : function(name, values){
13710 if(arguments.length == 1){
13711 values = arguments[0];
13714 var s = this.subs[name];
13715 s.buffer[s.buffer.length] = s.tpl.apply(values);
13720 * Applies all the passed values to a child template.
13721 * @param {String/Number} name (optional) The name or index of the child template
13722 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13723 * @param {Boolean} reset (optional) True to reset the template first
13724 * @return {MasterTemplate} this
13726 fill : function(name, values, reset){
13728 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13736 for(var i = 0, len = values.length; i < len; i++){
13737 this.add(name, values[i]);
13743 * Resets the template for reuse
13744 * @return {MasterTemplate} this
13746 reset : function(){
13748 for(var i = 0; i < this.subCount; i++){
13754 applyTemplate : function(values){
13756 var replaceIndex = -1;
13757 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13758 return s[++replaceIndex].buffer.join("");
13760 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13763 apply : function(){
13764 return this.applyTemplate.apply(this, arguments);
13767 compile : function(){return this;}
13771 * Alias for fill().
13774 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13776 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13777 * var tpl = Roo.MasterTemplate.from('element-id');
13778 * @param {String/HTMLElement} el
13779 * @param {Object} config
13782 Roo.MasterTemplate.from = function(el, config){
13783 el = Roo.getDom(el);
13784 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13787 * Ext JS Library 1.1.1
13788 * Copyright(c) 2006-2007, Ext JS, LLC.
13790 * Originally Released Under LGPL - original licence link has changed is not relivant.
13793 * <script type="text/javascript">
13798 * @class Roo.util.CSS
13799 * Utility class for manipulating CSS rules
13802 Roo.util.CSS = function(){
13804 var doc = document;
13806 var camelRe = /(-[a-z])/gi;
13807 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13811 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13812 * tag and appended to the HEAD of the document.
13813 * @param {String|Object} cssText The text containing the css rules
13814 * @param {String} id An id to add to the stylesheet for later removal
13815 * @return {StyleSheet}
13817 createStyleSheet : function(cssText, id){
13819 var head = doc.getElementsByTagName("head")[0];
13820 var nrules = doc.createElement("style");
13821 nrules.setAttribute("type", "text/css");
13823 nrules.setAttribute("id", id);
13825 if (typeof(cssText) != 'string') {
13826 // support object maps..
13827 // not sure if this a good idea..
13828 // perhaps it should be merged with the general css handling
13829 // and handle js style props.
13830 var cssTextNew = [];
13831 for(var n in cssText) {
13833 for(var k in cssText[n]) {
13834 citems.push( k + ' : ' +cssText[n][k] + ';' );
13836 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13839 cssText = cssTextNew.join("\n");
13845 head.appendChild(nrules);
13846 ss = nrules.styleSheet;
13847 ss.cssText = cssText;
13850 nrules.appendChild(doc.createTextNode(cssText));
13852 nrules.cssText = cssText;
13854 head.appendChild(nrules);
13855 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13857 this.cacheStyleSheet(ss);
13862 * Removes a style or link tag by id
13863 * @param {String} id The id of the tag
13865 removeStyleSheet : function(id){
13866 var existing = doc.getElementById(id);
13868 existing.parentNode.removeChild(existing);
13873 * Dynamically swaps an existing stylesheet reference for a new one
13874 * @param {String} id The id of an existing link tag to remove
13875 * @param {String} url The href of the new stylesheet to include
13877 swapStyleSheet : function(id, url){
13878 this.removeStyleSheet(id);
13879 var ss = doc.createElement("link");
13880 ss.setAttribute("rel", "stylesheet");
13881 ss.setAttribute("type", "text/css");
13882 ss.setAttribute("id", id);
13883 ss.setAttribute("href", url);
13884 doc.getElementsByTagName("head")[0].appendChild(ss);
13888 * Refresh the rule cache if you have dynamically added stylesheets
13889 * @return {Object} An object (hash) of rules indexed by selector
13891 refreshCache : function(){
13892 return this.getRules(true);
13896 cacheStyleSheet : function(stylesheet){
13900 try{// try catch for cross domain access issue
13901 var ssRules = stylesheet.cssRules || stylesheet.rules;
13902 for(var j = ssRules.length-1; j >= 0; --j){
13903 rules[ssRules[j].selectorText] = ssRules[j];
13909 * Gets all css rules for the document
13910 * @param {Boolean} refreshCache true to refresh the internal cache
13911 * @return {Object} An object (hash) of rules indexed by selector
13913 getRules : function(refreshCache){
13914 if(rules == null || refreshCache){
13916 var ds = doc.styleSheets;
13917 for(var i =0, len = ds.length; i < len; i++){
13919 this.cacheStyleSheet(ds[i]);
13927 * Gets an an individual CSS rule by selector(s)
13928 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13929 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13930 * @return {CSSRule} The CSS rule or null if one is not found
13932 getRule : function(selector, refreshCache){
13933 var rs = this.getRules(refreshCache);
13934 if(!(selector instanceof Array)){
13935 return rs[selector];
13937 for(var i = 0; i < selector.length; i++){
13938 if(rs[selector[i]]){
13939 return rs[selector[i]];
13947 * Updates a rule property
13948 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13949 * @param {String} property The css property
13950 * @param {String} value The new value for the property
13951 * @return {Boolean} true If a rule was found and updated
13953 updateRule : function(selector, property, value){
13954 if(!(selector instanceof Array)){
13955 var rule = this.getRule(selector);
13957 rule.style[property.replace(camelRe, camelFn)] = value;
13961 for(var i = 0; i < selector.length; i++){
13962 if(this.updateRule(selector[i], property, value)){
13972 * Ext JS Library 1.1.1
13973 * Copyright(c) 2006-2007, Ext JS, LLC.
13975 * Originally Released Under LGPL - original licence link has changed is not relivant.
13978 * <script type="text/javascript">
13984 * @class Roo.util.ClickRepeater
13985 * @extends Roo.util.Observable
13987 * A wrapper class which can be applied to any element. Fires a "click" event while the
13988 * mouse is pressed. The interval between firings may be specified in the config but
13989 * defaults to 10 milliseconds.
13991 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13993 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13994 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13995 * Similar to an autorepeat key delay.
13996 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13997 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13998 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13999 * "interval" and "delay" are ignored. "immediate" is honored.
14000 * @cfg {Boolean} preventDefault True to prevent the default click event
14001 * @cfg {Boolean} stopDefault True to stop the default click event
14004 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14005 * 2007-02-02 jvs Renamed to ClickRepeater
14006 * 2007-02-03 jvs Modifications for FF Mac and Safari
14009 * @param {String/HTMLElement/Element} el The element to listen on
14010 * @param {Object} config
14012 Roo.util.ClickRepeater = function(el, config)
14014 this.el = Roo.get(el);
14015 this.el.unselectable();
14017 Roo.apply(this, config);
14022 * Fires when the mouse button is depressed.
14023 * @param {Roo.util.ClickRepeater} this
14025 "mousedown" : true,
14028 * Fires on a specified interval during the time the element is pressed.
14029 * @param {Roo.util.ClickRepeater} this
14034 * Fires when the mouse key is released.
14035 * @param {Roo.util.ClickRepeater} this
14040 this.el.on("mousedown", this.handleMouseDown, this);
14041 if(this.preventDefault || this.stopDefault){
14042 this.el.on("click", function(e){
14043 if(this.preventDefault){
14044 e.preventDefault();
14046 if(this.stopDefault){
14052 // allow inline handler
14054 this.on("click", this.handler, this.scope || this);
14057 Roo.util.ClickRepeater.superclass.constructor.call(this);
14060 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14063 preventDefault : true,
14064 stopDefault : false,
14068 handleMouseDown : function(){
14069 clearTimeout(this.timer);
14071 if(this.pressClass){
14072 this.el.addClass(this.pressClass);
14074 this.mousedownTime = new Date();
14076 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14077 this.el.on("mouseout", this.handleMouseOut, this);
14079 this.fireEvent("mousedown", this);
14080 this.fireEvent("click", this);
14082 this.timer = this.click.defer(this.delay || this.interval, this);
14086 click : function(){
14087 this.fireEvent("click", this);
14088 this.timer = this.click.defer(this.getInterval(), this);
14092 getInterval: function(){
14093 if(!this.accelerate){
14094 return this.interval;
14096 var pressTime = this.mousedownTime.getElapsed();
14097 if(pressTime < 500){
14099 }else if(pressTime < 1700){
14101 }else if(pressTime < 2600){
14103 }else if(pressTime < 3500){
14105 }else if(pressTime < 4400){
14107 }else if(pressTime < 5300){
14109 }else if(pressTime < 6200){
14117 handleMouseOut : function(){
14118 clearTimeout(this.timer);
14119 if(this.pressClass){
14120 this.el.removeClass(this.pressClass);
14122 this.el.on("mouseover", this.handleMouseReturn, this);
14126 handleMouseReturn : function(){
14127 this.el.un("mouseover", this.handleMouseReturn);
14128 if(this.pressClass){
14129 this.el.addClass(this.pressClass);
14135 handleMouseUp : function(){
14136 clearTimeout(this.timer);
14137 this.el.un("mouseover", this.handleMouseReturn);
14138 this.el.un("mouseout", this.handleMouseOut);
14139 Roo.get(document).un("mouseup", this.handleMouseUp);
14140 this.el.removeClass(this.pressClass);
14141 this.fireEvent("mouseup", this);
14145 * Ext JS Library 1.1.1
14146 * Copyright(c) 2006-2007, Ext JS, LLC.
14148 * Originally Released Under LGPL - original licence link has changed is not relivant.
14151 * <script type="text/javascript">
14156 * @class Roo.KeyNav
14157 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14158 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14159 * way to implement custom navigation schemes for any UI component.</p>
14160 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14161 * pageUp, pageDown, del, home, end. Usage:</p>
14163 var nav = new Roo.KeyNav("my-element", {
14164 "left" : function(e){
14165 this.moveLeft(e.ctrlKey);
14167 "right" : function(e){
14168 this.moveRight(e.ctrlKey);
14170 "enter" : function(e){
14177 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14178 * @param {Object} config The config
14180 Roo.KeyNav = function(el, config){
14181 this.el = Roo.get(el);
14182 Roo.apply(this, config);
14183 if(!this.disabled){
14184 this.disabled = true;
14189 Roo.KeyNav.prototype = {
14191 * @cfg {Boolean} disabled
14192 * True to disable this KeyNav instance (defaults to false)
14196 * @cfg {String} defaultEventAction
14197 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14198 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14199 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14201 defaultEventAction: "stopEvent",
14203 * @cfg {Boolean} forceKeyDown
14204 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14205 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14206 * handle keydown instead of keypress.
14208 forceKeyDown : false,
14211 prepareEvent : function(e){
14212 var k = e.getKey();
14213 var h = this.keyToHandler[k];
14214 //if(h && this[h]){
14215 // e.stopPropagation();
14217 if(Roo.isSafari && h && k >= 37 && k <= 40){
14223 relay : function(e){
14224 var k = e.getKey();
14225 var h = this.keyToHandler[k];
14227 if(this.doRelay(e, this[h], h) !== true){
14228 e[this.defaultEventAction]();
14234 doRelay : function(e, h, hname){
14235 return h.call(this.scope || this, e);
14238 // possible handlers
14252 // quick lookup hash
14269 * Enable this KeyNav
14271 enable: function(){
14273 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14274 // the EventObject will normalize Safari automatically
14275 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14276 this.el.on("keydown", this.relay, this);
14278 this.el.on("keydown", this.prepareEvent, this);
14279 this.el.on("keypress", this.relay, this);
14281 this.disabled = false;
14286 * Disable this KeyNav
14288 disable: function(){
14289 if(!this.disabled){
14290 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14291 this.el.un("keydown", this.relay);
14293 this.el.un("keydown", this.prepareEvent);
14294 this.el.un("keypress", this.relay);
14296 this.disabled = true;
14301 * Ext JS Library 1.1.1
14302 * Copyright(c) 2006-2007, Ext JS, LLC.
14304 * Originally Released Under LGPL - original licence link has changed is not relivant.
14307 * <script type="text/javascript">
14312 * @class Roo.KeyMap
14313 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14314 * The constructor accepts the same config object as defined by {@link #addBinding}.
14315 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14316 * combination it will call the function with this signature (if the match is a multi-key
14317 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14318 * A KeyMap can also handle a string representation of keys.<br />
14321 // map one key by key code
14322 var map = new Roo.KeyMap("my-element", {
14323 key: 13, // or Roo.EventObject.ENTER
14328 // map multiple keys to one action by string
14329 var map = new Roo.KeyMap("my-element", {
14335 // map multiple keys to multiple actions by strings and array of codes
14336 var map = new Roo.KeyMap("my-element", [
14339 fn: function(){ alert("Return was pressed"); }
14342 fn: function(){ alert('a, b or c was pressed'); }
14347 fn: function(){ alert('Control + shift + tab was pressed.'); }
14351 * <b>Note: A KeyMap starts enabled</b>
14353 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14354 * @param {Object} config The config (see {@link #addBinding})
14355 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14357 Roo.KeyMap = function(el, config, eventName){
14358 this.el = Roo.get(el);
14359 this.eventName = eventName || "keydown";
14360 this.bindings = [];
14362 this.addBinding(config);
14367 Roo.KeyMap.prototype = {
14369 * True to stop the event from bubbling and prevent the default browser action if the
14370 * key was handled by the KeyMap (defaults to false)
14376 * Add a new binding to this KeyMap. The following config object properties are supported:
14378 Property Type Description
14379 ---------- --------------- ----------------------------------------------------------------------
14380 key String/Array A single keycode or an array of keycodes to handle
14381 shift Boolean True to handle key only when shift is pressed (defaults to false)
14382 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14383 alt Boolean True to handle key only when alt is pressed (defaults to false)
14384 fn Function The function to call when KeyMap finds the expected key combination
14385 scope Object The scope of the callback function
14391 var map = new Roo.KeyMap(document, {
14392 key: Roo.EventObject.ENTER,
14397 //Add a new binding to the existing KeyMap later
14405 * @param {Object/Array} config A single KeyMap config or an array of configs
14407 addBinding : function(config){
14408 if(config instanceof Array){
14409 for(var i = 0, len = config.length; i < len; i++){
14410 this.addBinding(config[i]);
14414 var keyCode = config.key,
14415 shift = config.shift,
14416 ctrl = config.ctrl,
14419 scope = config.scope;
14420 if(typeof keyCode == "string"){
14422 var keyString = keyCode.toUpperCase();
14423 for(var j = 0, len = keyString.length; j < len; j++){
14424 ks.push(keyString.charCodeAt(j));
14428 var keyArray = keyCode instanceof Array;
14429 var handler = function(e){
14430 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14431 var k = e.getKey();
14433 for(var i = 0, len = keyCode.length; i < len; i++){
14434 if(keyCode[i] == k){
14435 if(this.stopEvent){
14438 fn.call(scope || window, k, e);
14444 if(this.stopEvent){
14447 fn.call(scope || window, k, e);
14452 this.bindings.push(handler);
14456 * Shorthand for adding a single key listener
14457 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14458 * following options:
14459 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14460 * @param {Function} fn The function to call
14461 * @param {Object} scope (optional) The scope of the function
14463 on : function(key, fn, scope){
14464 var keyCode, shift, ctrl, alt;
14465 if(typeof key == "object" && !(key instanceof Array)){
14484 handleKeyDown : function(e){
14485 if(this.enabled){ //just in case
14486 var b = this.bindings;
14487 for(var i = 0, len = b.length; i < len; i++){
14488 b[i].call(this, e);
14494 * Returns true if this KeyMap is enabled
14495 * @return {Boolean}
14497 isEnabled : function(){
14498 return this.enabled;
14502 * Enables this KeyMap
14504 enable: function(){
14506 this.el.on(this.eventName, this.handleKeyDown, this);
14507 this.enabled = true;
14512 * Disable this KeyMap
14514 disable: function(){
14516 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14517 this.enabled = false;
14522 * Ext JS Library 1.1.1
14523 * Copyright(c) 2006-2007, Ext JS, LLC.
14525 * Originally Released Under LGPL - original licence link has changed is not relivant.
14528 * <script type="text/javascript">
14533 * @class Roo.util.TextMetrics
14534 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14535 * wide, in pixels, a given block of text will be.
14538 Roo.util.TextMetrics = function(){
14542 * Measures the size of the specified text
14543 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14544 * that can affect the size of the rendered text
14545 * @param {String} text The text to measure
14546 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14547 * in order to accurately measure the text height
14548 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14550 measure : function(el, text, fixedWidth){
14552 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14555 shared.setFixedWidth(fixedWidth || 'auto');
14556 return shared.getSize(text);
14560 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14561 * the overhead of multiple calls to initialize the style properties on each measurement.
14562 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14563 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14564 * in order to accurately measure the text height
14565 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14567 createInstance : function(el, fixedWidth){
14568 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14575 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14576 var ml = new Roo.Element(document.createElement('div'));
14577 document.body.appendChild(ml.dom);
14578 ml.position('absolute');
14579 ml.setLeftTop(-1000, -1000);
14583 ml.setWidth(fixedWidth);
14588 * Returns the size of the specified text based on the internal element's style and width properties
14589 * @memberOf Roo.util.TextMetrics.Instance#
14590 * @param {String} text The text to measure
14591 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14593 getSize : function(text){
14595 var s = ml.getSize();
14601 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14602 * that can affect the size of the rendered text
14603 * @memberOf Roo.util.TextMetrics.Instance#
14604 * @param {String/HTMLElement} el The element, dom node or id
14606 bind : function(el){
14608 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14613 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14614 * to set a fixed width in order to accurately measure the text height.
14615 * @memberOf Roo.util.TextMetrics.Instance#
14616 * @param {Number} width The width to set on the element
14618 setFixedWidth : function(width){
14619 ml.setWidth(width);
14623 * Returns the measured width of the specified text
14624 * @memberOf Roo.util.TextMetrics.Instance#
14625 * @param {String} text The text to measure
14626 * @return {Number} width The width in pixels
14628 getWidth : function(text){
14629 ml.dom.style.width = 'auto';
14630 return this.getSize(text).width;
14634 * Returns the measured height of the specified text. For multiline text, be sure to call
14635 * {@link #setFixedWidth} if necessary.
14636 * @memberOf Roo.util.TextMetrics.Instance#
14637 * @param {String} text The text to measure
14638 * @return {Number} height The height in pixels
14640 getHeight : function(text){
14641 return this.getSize(text).height;
14645 instance.bind(bindTo);
14650 // backwards compat
14651 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14653 * Ext JS Library 1.1.1
14654 * Copyright(c) 2006-2007, Ext JS, LLC.
14656 * Originally Released Under LGPL - original licence link has changed is not relivant.
14659 * <script type="text/javascript">
14663 * @class Roo.state.Provider
14664 * Abstract base class for state provider implementations. This class provides methods
14665 * for encoding and decoding <b>typed</b> variables including dates and defines the
14666 * Provider interface.
14668 Roo.state.Provider = function(){
14670 * @event statechange
14671 * Fires when a state change occurs.
14672 * @param {Provider} this This state provider
14673 * @param {String} key The state key which was changed
14674 * @param {String} value The encoded value for the state
14677 "statechange": true
14680 Roo.state.Provider.superclass.constructor.call(this);
14682 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14684 * Returns the current value for a key
14685 * @param {String} name The key name
14686 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14687 * @return {Mixed} The state data
14689 get : function(name, defaultValue){
14690 return typeof this.state[name] == "undefined" ?
14691 defaultValue : this.state[name];
14695 * Clears a value from the state
14696 * @param {String} name The key name
14698 clear : function(name){
14699 delete this.state[name];
14700 this.fireEvent("statechange", this, name, null);
14704 * Sets the value for a key
14705 * @param {String} name The key name
14706 * @param {Mixed} value The value to set
14708 set : function(name, value){
14709 this.state[name] = value;
14710 this.fireEvent("statechange", this, name, value);
14714 * Decodes a string previously encoded with {@link #encodeValue}.
14715 * @param {String} value The value to decode
14716 * @return {Mixed} The decoded value
14718 decodeValue : function(cookie){
14719 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14720 var matches = re.exec(unescape(cookie));
14721 if(!matches || !matches[1]) return; // non state cookie
14722 var type = matches[1];
14723 var v = matches[2];
14726 return parseFloat(v);
14728 return new Date(Date.parse(v));
14733 var values = v.split("^");
14734 for(var i = 0, len = values.length; i < len; i++){
14735 all.push(this.decodeValue(values[i]));
14740 var values = v.split("^");
14741 for(var i = 0, len = values.length; i < len; i++){
14742 var kv = values[i].split("=");
14743 all[kv[0]] = this.decodeValue(kv[1]);
14752 * Encodes a value including type information. Decode with {@link #decodeValue}.
14753 * @param {Mixed} value The value to encode
14754 * @return {String} The encoded value
14756 encodeValue : function(v){
14758 if(typeof v == "number"){
14760 }else if(typeof v == "boolean"){
14761 enc = "b:" + (v ? "1" : "0");
14762 }else if(v instanceof Date){
14763 enc = "d:" + v.toGMTString();
14764 }else if(v instanceof Array){
14766 for(var i = 0, len = v.length; i < len; i++){
14767 flat += this.encodeValue(v[i]);
14768 if(i != len-1) flat += "^";
14771 }else if(typeof v == "object"){
14774 if(typeof v[key] != "function"){
14775 flat += key + "=" + this.encodeValue(v[key]) + "^";
14778 enc = "o:" + flat.substring(0, flat.length-1);
14782 return escape(enc);
14788 * Ext JS Library 1.1.1
14789 * Copyright(c) 2006-2007, Ext JS, LLC.
14791 * Originally Released Under LGPL - original licence link has changed is not relivant.
14794 * <script type="text/javascript">
14797 * @class Roo.state.Manager
14798 * This is the global state manager. By default all components that are "state aware" check this class
14799 * for state information if you don't pass them a custom state provider. In order for this class
14800 * to be useful, it must be initialized with a provider when your application initializes.
14802 // in your initialization function
14804 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14806 // supposed you have a {@link Roo.BorderLayout}
14807 var layout = new Roo.BorderLayout(...);
14808 layout.restoreState();
14809 // or a {Roo.BasicDialog}
14810 var dialog = new Roo.BasicDialog(...);
14811 dialog.restoreState();
14815 Roo.state.Manager = function(){
14816 var provider = new Roo.state.Provider();
14820 * Configures the default state provider for your application
14821 * @param {Provider} stateProvider The state provider to set
14823 setProvider : function(stateProvider){
14824 provider = stateProvider;
14828 * Returns the current value for a key
14829 * @param {String} name The key name
14830 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14831 * @return {Mixed} The state data
14833 get : function(key, defaultValue){
14834 return provider.get(key, defaultValue);
14838 * Sets the value for a key
14839 * @param {String} name The key name
14840 * @param {Mixed} value The state data
14842 set : function(key, value){
14843 provider.set(key, value);
14847 * Clears a value from the state
14848 * @param {String} name The key name
14850 clear : function(key){
14851 provider.clear(key);
14855 * Gets the currently configured state provider
14856 * @return {Provider} The state provider
14858 getProvider : function(){
14865 * Ext JS Library 1.1.1
14866 * Copyright(c) 2006-2007, Ext JS, LLC.
14868 * Originally Released Under LGPL - original licence link has changed is not relivant.
14871 * <script type="text/javascript">
14874 * @class Roo.state.CookieProvider
14875 * @extends Roo.state.Provider
14876 * The default Provider implementation which saves state via cookies.
14879 var cp = new Roo.state.CookieProvider({
14881 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14882 domain: "roojs.com"
14884 Roo.state.Manager.setProvider(cp);
14886 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14887 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14888 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14889 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14890 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14891 * domain the page is running on including the 'www' like 'www.roojs.com')
14892 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14894 * Create a new CookieProvider
14895 * @param {Object} config The configuration object
14897 Roo.state.CookieProvider = function(config){
14898 Roo.state.CookieProvider.superclass.constructor.call(this);
14900 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14901 this.domain = null;
14902 this.secure = false;
14903 Roo.apply(this, config);
14904 this.state = this.readCookies();
14907 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14909 set : function(name, value){
14910 if(typeof value == "undefined" || value === null){
14914 this.setCookie(name, value);
14915 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14919 clear : function(name){
14920 this.clearCookie(name);
14921 Roo.state.CookieProvider.superclass.clear.call(this, name);
14925 readCookies : function(){
14927 var c = document.cookie + ";";
14928 var re = /\s?(.*?)=(.*?);/g;
14930 while((matches = re.exec(c)) != null){
14931 var name = matches[1];
14932 var value = matches[2];
14933 if(name && name.substring(0,3) == "ys-"){
14934 cookies[name.substr(3)] = this.decodeValue(value);
14941 setCookie : function(name, value){
14942 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14943 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14944 ((this.path == null) ? "" : ("; path=" + this.path)) +
14945 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14946 ((this.secure == true) ? "; secure" : "");
14950 clearCookie : function(name){
14951 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14952 ((this.path == null) ? "" : ("; path=" + this.path)) +
14953 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14954 ((this.secure == true) ? "; secure" : "");
14958 * Ext JS Library 1.1.1
14959 * Copyright(c) 2006-2007, Ext JS, LLC.
14961 * Originally Released Under LGPL - original licence link has changed is not relivant.
14964 * <script type="text/javascript">
14970 * These classes are derivatives of the similarly named classes in the YUI Library.
14971 * The original license:
14972 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14973 * Code licensed under the BSD License:
14974 * http://developer.yahoo.net/yui/license.txt
14979 var Event=Roo.EventManager;
14980 var Dom=Roo.lib.Dom;
14983 * @class Roo.dd.DragDrop
14984 * @extends Roo.util.Observable
14985 * Defines the interface and base operation of items that that can be
14986 * dragged or can be drop targets. It was designed to be extended, overriding
14987 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14988 * Up to three html elements can be associated with a DragDrop instance:
14990 * <li>linked element: the element that is passed into the constructor.
14991 * This is the element which defines the boundaries for interaction with
14992 * other DragDrop objects.</li>
14993 * <li>handle element(s): The drag operation only occurs if the element that
14994 * was clicked matches a handle element. By default this is the linked
14995 * element, but there are times that you will want only a portion of the
14996 * linked element to initiate the drag operation, and the setHandleElId()
14997 * method provides a way to define this.</li>
14998 * <li>drag element: this represents the element that would be moved along
14999 * with the cursor during a drag operation. By default, this is the linked
15000 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
15001 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
15004 * This class should not be instantiated until the onload event to ensure that
15005 * the associated elements are available.
15006 * The following would define a DragDrop obj that would interact with any
15007 * other DragDrop obj in the "group1" group:
15009 * dd = new Roo.dd.DragDrop("div1", "group1");
15011 * Since none of the event handlers have been implemented, nothing would
15012 * actually happen if you were to run the code above. Normally you would
15013 * override this class or one of the default implementations, but you can
15014 * also override the methods you want on an instance of the class...
15016 * dd.onDragDrop = function(e, id) {
15017 * alert("dd was dropped on " + id);
15021 * @param {String} id of the element that is linked to this instance
15022 * @param {String} sGroup the group of related DragDrop objects
15023 * @param {object} config an object containing configurable attributes
15024 * Valid properties for DragDrop:
15025 * padding, isTarget, maintainOffset, primaryButtonOnly
15027 Roo.dd.DragDrop = function(id, sGroup, config) {
15029 this.init(id, sGroup, config);
15034 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
15037 * The id of the element associated with this object. This is what we
15038 * refer to as the "linked element" because the size and position of
15039 * this element is used to determine when the drag and drop objects have
15047 * Configuration attributes passed into the constructor
15054 * The id of the element that will be dragged. By default this is same
15055 * as the linked element , but could be changed to another element. Ex:
15057 * @property dragElId
15064 * the id of the element that initiates the drag operation. By default
15065 * this is the linked element, but could be changed to be a child of this
15066 * element. This lets us do things like only starting the drag when the
15067 * header element within the linked html element is clicked.
15068 * @property handleElId
15075 * An associative array of HTML tags that will be ignored if clicked.
15076 * @property invalidHandleTypes
15077 * @type {string: string}
15079 invalidHandleTypes: null,
15082 * An associative array of ids for elements that will be ignored if clicked
15083 * @property invalidHandleIds
15084 * @type {string: string}
15086 invalidHandleIds: null,
15089 * An indexted array of css class names for elements that will be ignored
15091 * @property invalidHandleClasses
15094 invalidHandleClasses: null,
15097 * The linked element's absolute X position at the time the drag was
15099 * @property startPageX
15106 * The linked element's absolute X position at the time the drag was
15108 * @property startPageY
15115 * The group defines a logical collection of DragDrop objects that are
15116 * related. Instances only get events when interacting with other
15117 * DragDrop object in the same group. This lets us define multiple
15118 * groups using a single DragDrop subclass if we want.
15120 * @type {string: string}
15125 * Individual drag/drop instances can be locked. This will prevent
15126 * onmousedown start drag.
15134 * Lock this instance
15137 lock: function() { this.locked = true; },
15140 * Unlock this instace
15143 unlock: function() { this.locked = false; },
15146 * By default, all insances can be a drop target. This can be disabled by
15147 * setting isTarget to false.
15154 * The padding configured for this drag and drop object for calculating
15155 * the drop zone intersection with this object.
15162 * Cached reference to the linked element
15163 * @property _domRef
15169 * Internal typeof flag
15170 * @property __ygDragDrop
15173 __ygDragDrop: true,
15176 * Set to true when horizontal contraints are applied
15177 * @property constrainX
15184 * Set to true when vertical contraints are applied
15185 * @property constrainY
15192 * The left constraint
15200 * The right constraint
15208 * The up constraint
15217 * The down constraint
15225 * Maintain offsets when we resetconstraints. Set to true when you want
15226 * the position of the element relative to its parent to stay the same
15227 * when the page changes
15229 * @property maintainOffset
15232 maintainOffset: false,
15235 * Array of pixel locations the element will snap to if we specified a
15236 * horizontal graduation/interval. This array is generated automatically
15237 * when you define a tick interval.
15244 * Array of pixel locations the element will snap to if we specified a
15245 * vertical graduation/interval. This array is generated automatically
15246 * when you define a tick interval.
15253 * By default the drag and drop instance will only respond to the primary
15254 * button click (left button for a right-handed mouse). Set to true to
15255 * allow drag and drop to start with any mouse click that is propogated
15257 * @property primaryButtonOnly
15260 primaryButtonOnly: true,
15263 * The availabe property is false until the linked dom element is accessible.
15264 * @property available
15270 * By default, drags can only be initiated if the mousedown occurs in the
15271 * region the linked element is. This is done in part to work around a
15272 * bug in some browsers that mis-report the mousedown if the previous
15273 * mouseup happened outside of the window. This property is set to true
15274 * if outer handles are defined.
15276 * @property hasOuterHandles
15280 hasOuterHandles: false,
15283 * Code that executes immediately before the startDrag event
15284 * @method b4StartDrag
15287 b4StartDrag: function(x, y) { },
15290 * Abstract method called after a drag/drop object is clicked
15291 * and the drag or mousedown time thresholds have beeen met.
15292 * @method startDrag
15293 * @param {int} X click location
15294 * @param {int} Y click location
15296 startDrag: function(x, y) { /* override this */ },
15299 * Code that executes immediately before the onDrag event
15303 b4Drag: function(e) { },
15306 * Abstract method called during the onMouseMove event while dragging an
15309 * @param {Event} e the mousemove event
15311 onDrag: function(e) { /* override this */ },
15314 * Abstract method called when this element fist begins hovering over
15315 * another DragDrop obj
15316 * @method onDragEnter
15317 * @param {Event} e the mousemove event
15318 * @param {String|DragDrop[]} id In POINT mode, the element
15319 * id this is hovering over. In INTERSECT mode, an array of one or more
15320 * dragdrop items being hovered over.
15322 onDragEnter: function(e, id) { /* override this */ },
15325 * Code that executes immediately before the onDragOver event
15326 * @method b4DragOver
15329 b4DragOver: function(e) { },
15332 * Abstract method called when this element is hovering over another
15334 * @method onDragOver
15335 * @param {Event} e the mousemove event
15336 * @param {String|DragDrop[]} id In POINT mode, the element
15337 * id this is hovering over. In INTERSECT mode, an array of dd items
15338 * being hovered over.
15340 onDragOver: function(e, id) { /* override this */ },
15343 * Code that executes immediately before the onDragOut event
15344 * @method b4DragOut
15347 b4DragOut: function(e) { },
15350 * Abstract method called when we are no longer hovering over an element
15351 * @method onDragOut
15352 * @param {Event} e the mousemove event
15353 * @param {String|DragDrop[]} id In POINT mode, the element
15354 * id this was hovering over. In INTERSECT mode, an array of dd items
15355 * that the mouse is no longer over.
15357 onDragOut: function(e, id) { /* override this */ },
15360 * Code that executes immediately before the onDragDrop event
15361 * @method b4DragDrop
15364 b4DragDrop: function(e) { },
15367 * Abstract method called when this item is dropped on another DragDrop
15369 * @method onDragDrop
15370 * @param {Event} e the mouseup event
15371 * @param {String|DragDrop[]} id In POINT mode, the element
15372 * id this was dropped on. In INTERSECT mode, an array of dd items this
15375 onDragDrop: function(e, id) { /* override this */ },
15378 * Abstract method called when this item is dropped on an area with no
15380 * @method onInvalidDrop
15381 * @param {Event} e the mouseup event
15383 onInvalidDrop: function(e) { /* override this */ },
15386 * Code that executes immediately before the endDrag event
15387 * @method b4EndDrag
15390 b4EndDrag: function(e) { },
15393 * Fired when we are done dragging the object
15395 * @param {Event} e the mouseup event
15397 endDrag: function(e) { /* override this */ },
15400 * Code executed immediately before the onMouseDown event
15401 * @method b4MouseDown
15402 * @param {Event} e the mousedown event
15405 b4MouseDown: function(e) { },
15408 * Event handler that fires when a drag/drop obj gets a mousedown
15409 * @method onMouseDown
15410 * @param {Event} e the mousedown event
15412 onMouseDown: function(e) { /* override this */ },
15415 * Event handler that fires when a drag/drop obj gets a mouseup
15416 * @method onMouseUp
15417 * @param {Event} e the mouseup event
15419 onMouseUp: function(e) { /* override this */ },
15422 * Override the onAvailable method to do what is needed after the initial
15423 * position was determined.
15424 * @method onAvailable
15426 onAvailable: function () {
15430 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
15433 defaultPadding : {left:0, right:0, top:0, bottom:0},
15436 * Initializes the drag drop object's constraints to restrict movement to a certain element.
15440 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
15441 { dragElId: "existingProxyDiv" });
15442 dd.startDrag = function(){
15443 this.constrainTo("parent-id");
15446 * Or you can initalize it using the {@link Roo.Element} object:
15448 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
15449 startDrag : function(){
15450 this.constrainTo("parent-id");
15454 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
15455 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
15456 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
15457 * an object containing the sides to pad. For example: {right:10, bottom:10}
15458 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
15460 constrainTo : function(constrainTo, pad, inContent){
15461 if(typeof pad == "number"){
15462 pad = {left: pad, right:pad, top:pad, bottom:pad};
15464 pad = pad || this.defaultPadding;
15465 var b = Roo.get(this.getEl()).getBox();
15466 var ce = Roo.get(constrainTo);
15467 var s = ce.getScroll();
15468 var c, cd = ce.dom;
15469 if(cd == document.body){
15470 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15473 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15477 var topSpace = b.y - c.y;
15478 var leftSpace = b.x - c.x;
15480 this.resetConstraints();
15481 this.setXConstraint(leftSpace - (pad.left||0), // left
15482 c.width - leftSpace - b.width - (pad.right||0) //right
15484 this.setYConstraint(topSpace - (pad.top||0), //top
15485 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15490 * Returns a reference to the linked element
15492 * @return {HTMLElement} the html element
15494 getEl: function() {
15495 if (!this._domRef) {
15496 this._domRef = Roo.getDom(this.id);
15499 return this._domRef;
15503 * Returns a reference to the actual element to drag. By default this is
15504 * the same as the html element, but it can be assigned to another
15505 * element. An example of this can be found in Roo.dd.DDProxy
15506 * @method getDragEl
15507 * @return {HTMLElement} the html element
15509 getDragEl: function() {
15510 return Roo.getDom(this.dragElId);
15514 * Sets up the DragDrop object. Must be called in the constructor of any
15515 * Roo.dd.DragDrop subclass
15517 * @param id the id of the linked element
15518 * @param {String} sGroup the group of related items
15519 * @param {object} config configuration attributes
15521 init: function(id, sGroup, config) {
15522 this.initTarget(id, sGroup, config);
15523 if (!Roo.isTouch) {
15524 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15526 Event.on(this.id, "touchstart", this.handleMouseDown, this);
15527 // Event.on(this.id, "selectstart", Event.preventDefault);
15531 * Initializes Targeting functionality only... the object does not
15532 * get a mousedown handler.
15533 * @method initTarget
15534 * @param id the id of the linked element
15535 * @param {String} sGroup the group of related items
15536 * @param {object} config configuration attributes
15538 initTarget: function(id, sGroup, config) {
15540 // configuration attributes
15541 this.config = config || {};
15543 // create a local reference to the drag and drop manager
15544 this.DDM = Roo.dd.DDM;
15545 // initialize the groups array
15548 // assume that we have an element reference instead of an id if the
15549 // parameter is not a string
15550 if (typeof id !== "string") {
15557 // add to an interaction group
15558 this.addToGroup((sGroup) ? sGroup : "default");
15560 // We don't want to register this as the handle with the manager
15561 // so we just set the id rather than calling the setter.
15562 this.handleElId = id;
15564 // the linked element is the element that gets dragged by default
15565 this.setDragElId(id);
15567 // by default, clicked anchors will not start drag operations.
15568 this.invalidHandleTypes = { A: "A" };
15569 this.invalidHandleIds = {};
15570 this.invalidHandleClasses = [];
15572 this.applyConfig();
15574 this.handleOnAvailable();
15578 * Applies the configuration parameters that were passed into the constructor.
15579 * This is supposed to happen at each level through the inheritance chain. So
15580 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15581 * DragDrop in order to get all of the parameters that are available in
15583 * @method applyConfig
15585 applyConfig: function() {
15587 // configurable properties:
15588 // padding, isTarget, maintainOffset, primaryButtonOnly
15589 this.padding = this.config.padding || [0, 0, 0, 0];
15590 this.isTarget = (this.config.isTarget !== false);
15591 this.maintainOffset = (this.config.maintainOffset);
15592 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15597 * Executed when the linked element is available
15598 * @method handleOnAvailable
15601 handleOnAvailable: function() {
15602 this.available = true;
15603 this.resetConstraints();
15604 this.onAvailable();
15608 * Configures the padding for the target zone in px. Effectively expands
15609 * (or reduces) the virtual object size for targeting calculations.
15610 * Supports css-style shorthand; if only one parameter is passed, all sides
15611 * will have that padding, and if only two are passed, the top and bottom
15612 * will have the first param, the left and right the second.
15613 * @method setPadding
15614 * @param {int} iTop Top pad
15615 * @param {int} iRight Right pad
15616 * @param {int} iBot Bot pad
15617 * @param {int} iLeft Left pad
15619 setPadding: function(iTop, iRight, iBot, iLeft) {
15620 // this.padding = [iLeft, iRight, iTop, iBot];
15621 if (!iRight && 0 !== iRight) {
15622 this.padding = [iTop, iTop, iTop, iTop];
15623 } else if (!iBot && 0 !== iBot) {
15624 this.padding = [iTop, iRight, iTop, iRight];
15626 this.padding = [iTop, iRight, iBot, iLeft];
15631 * Stores the initial placement of the linked element.
15632 * @method setInitialPosition
15633 * @param {int} diffX the X offset, default 0
15634 * @param {int} diffY the Y offset, default 0
15636 setInitPosition: function(diffX, diffY) {
15637 var el = this.getEl();
15639 if (!this.DDM.verifyEl(el)) {
15643 var dx = diffX || 0;
15644 var dy = diffY || 0;
15646 var p = Dom.getXY( el );
15648 this.initPageX = p[0] - dx;
15649 this.initPageY = p[1] - dy;
15651 this.lastPageX = p[0];
15652 this.lastPageY = p[1];
15655 this.setStartPosition(p);
15659 * Sets the start position of the element. This is set when the obj
15660 * is initialized, the reset when a drag is started.
15661 * @method setStartPosition
15662 * @param pos current position (from previous lookup)
15665 setStartPosition: function(pos) {
15666 var p = pos || Dom.getXY( this.getEl() );
15667 this.deltaSetXY = null;
15669 this.startPageX = p[0];
15670 this.startPageY = p[1];
15674 * Add this instance to a group of related drag/drop objects. All
15675 * instances belong to at least one group, and can belong to as many
15676 * groups as needed.
15677 * @method addToGroup
15678 * @param sGroup {string} the name of the group
15680 addToGroup: function(sGroup) {
15681 this.groups[sGroup] = true;
15682 this.DDM.regDragDrop(this, sGroup);
15686 * Remove's this instance from the supplied interaction group
15687 * @method removeFromGroup
15688 * @param {string} sGroup The group to drop
15690 removeFromGroup: function(sGroup) {
15691 if (this.groups[sGroup]) {
15692 delete this.groups[sGroup];
15695 this.DDM.removeDDFromGroup(this, sGroup);
15699 * Allows you to specify that an element other than the linked element
15700 * will be moved with the cursor during a drag
15701 * @method setDragElId
15702 * @param id {string} the id of the element that will be used to initiate the drag
15704 setDragElId: function(id) {
15705 this.dragElId = id;
15709 * Allows you to specify a child of the linked element that should be
15710 * used to initiate the drag operation. An example of this would be if
15711 * you have a content div with text and links. Clicking anywhere in the
15712 * content area would normally start the drag operation. Use this method
15713 * to specify that an element inside of the content div is the element
15714 * that starts the drag operation.
15715 * @method setHandleElId
15716 * @param id {string} the id of the element that will be used to
15717 * initiate the drag.
15719 setHandleElId: function(id) {
15720 if (typeof id !== "string") {
15723 this.handleElId = id;
15724 this.DDM.regHandle(this.id, id);
15728 * Allows you to set an element outside of the linked element as a drag
15730 * @method setOuterHandleElId
15731 * @param id the id of the element that will be used to initiate the drag
15733 setOuterHandleElId: function(id) {
15734 if (typeof id !== "string") {
15737 Event.on(id, "mousedown",
15738 this.handleMouseDown, this);
15739 this.setHandleElId(id);
15741 this.hasOuterHandles = true;
15745 * Remove all drag and drop hooks for this element
15748 unreg: function() {
15749 Event.un(this.id, "mousedown",
15750 this.handleMouseDown);
15751 Event.un(this.id, "touchstart",
15752 this.handleMouseDown);
15753 this._domRef = null;
15754 this.DDM._remove(this);
15757 destroy : function(){
15762 * Returns true if this instance is locked, or the drag drop mgr is locked
15763 * (meaning that all drag/drop is disabled on the page.)
15765 * @return {boolean} true if this obj or all drag/drop is locked, else
15768 isLocked: function() {
15769 return (this.DDM.isLocked() || this.locked);
15773 * Fired when this object is clicked
15774 * @method handleMouseDown
15776 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15779 handleMouseDown: function(e, oDD){
15782 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
15783 //Roo.log('not touch/ button !=0');
15786 if (ev.browserEvent.touches && ev.browserEvent.touches.length != 1) {
15787 return; // double touch..
15791 if (this.isLocked()) {
15792 //Roo.log('locked');
15796 this.DDM.refreshCache(this.groups);
15797 Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
15798 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15799 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15800 //Roo.log('no outer handes or not over target');
15803 Roo.log('check validator');
15804 if (this.clickValidator(e)) {
15805 Roo.log('validate success');
15806 // set the initial element position
15807 this.setStartPosition();
15810 this.b4MouseDown(e);
15811 this.onMouseDown(e);
15813 this.DDM.handleMouseDown(e, this);
15815 this.DDM.stopEvent(e);
15823 clickValidator: function(e) {
15824 var target = e.getTarget();
15825 return ( this.isValidHandleChild(target) &&
15826 (this.id == this.handleElId ||
15827 this.DDM.handleWasClicked(target, this.id)) );
15831 * Allows you to specify a tag name that should not start a drag operation
15832 * when clicked. This is designed to facilitate embedding links within a
15833 * drag handle that do something other than start the drag.
15834 * @method addInvalidHandleType
15835 * @param {string} tagName the type of element to exclude
15837 addInvalidHandleType: function(tagName) {
15838 var type = tagName.toUpperCase();
15839 this.invalidHandleTypes[type] = type;
15843 * Lets you to specify an element id for a child of a drag handle
15844 * that should not initiate a drag
15845 * @method addInvalidHandleId
15846 * @param {string} id the element id of the element you wish to ignore
15848 addInvalidHandleId: function(id) {
15849 if (typeof id !== "string") {
15852 this.invalidHandleIds[id] = id;
15856 * Lets you specify a css class of elements that will not initiate a drag
15857 * @method addInvalidHandleClass
15858 * @param {string} cssClass the class of the elements you wish to ignore
15860 addInvalidHandleClass: function(cssClass) {
15861 this.invalidHandleClasses.push(cssClass);
15865 * Unsets an excluded tag name set by addInvalidHandleType
15866 * @method removeInvalidHandleType
15867 * @param {string} tagName the type of element to unexclude
15869 removeInvalidHandleType: function(tagName) {
15870 var type = tagName.toUpperCase();
15871 // this.invalidHandleTypes[type] = null;
15872 delete this.invalidHandleTypes[type];
15876 * Unsets an invalid handle id
15877 * @method removeInvalidHandleId
15878 * @param {string} id the id of the element to re-enable
15880 removeInvalidHandleId: function(id) {
15881 if (typeof id !== "string") {
15884 delete this.invalidHandleIds[id];
15888 * Unsets an invalid css class
15889 * @method removeInvalidHandleClass
15890 * @param {string} cssClass the class of the element(s) you wish to
15893 removeInvalidHandleClass: function(cssClass) {
15894 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15895 if (this.invalidHandleClasses[i] == cssClass) {
15896 delete this.invalidHandleClasses[i];
15902 * Checks the tag exclusion list to see if this click should be ignored
15903 * @method isValidHandleChild
15904 * @param {HTMLElement} node the HTMLElement to evaluate
15905 * @return {boolean} true if this is a valid tag type, false if not
15907 isValidHandleChild: function(node) {
15910 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15913 nodeName = node.nodeName.toUpperCase();
15915 nodeName = node.nodeName;
15917 valid = valid && !this.invalidHandleTypes[nodeName];
15918 valid = valid && !this.invalidHandleIds[node.id];
15920 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15921 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15930 * Create the array of horizontal tick marks if an interval was specified
15931 * in setXConstraint().
15932 * @method setXTicks
15935 setXTicks: function(iStartX, iTickSize) {
15937 this.xTickSize = iTickSize;
15941 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15943 this.xTicks[this.xTicks.length] = i;
15948 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15950 this.xTicks[this.xTicks.length] = i;
15955 this.xTicks.sort(this.DDM.numericSort) ;
15959 * Create the array of vertical tick marks if an interval was specified in
15960 * setYConstraint().
15961 * @method setYTicks
15964 setYTicks: function(iStartY, iTickSize) {
15966 this.yTickSize = iTickSize;
15970 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15972 this.yTicks[this.yTicks.length] = i;
15977 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15979 this.yTicks[this.yTicks.length] = i;
15984 this.yTicks.sort(this.DDM.numericSort) ;
15988 * By default, the element can be dragged any place on the screen. Use
15989 * this method to limit the horizontal travel of the element. Pass in
15990 * 0,0 for the parameters if you want to lock the drag to the y axis.
15991 * @method setXConstraint
15992 * @param {int} iLeft the number of pixels the element can move to the left
15993 * @param {int} iRight the number of pixels the element can move to the
15995 * @param {int} iTickSize optional parameter for specifying that the
15997 * should move iTickSize pixels at a time.
15999 setXConstraint: function(iLeft, iRight, iTickSize) {
16000 this.leftConstraint = iLeft;
16001 this.rightConstraint = iRight;
16003 this.minX = this.initPageX - iLeft;
16004 this.maxX = this.initPageX + iRight;
16005 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
16007 this.constrainX = true;
16011 * Clears any constraints applied to this instance. Also clears ticks
16012 * since they can't exist independent of a constraint at this time.
16013 * @method clearConstraints
16015 clearConstraints: function() {
16016 this.constrainX = false;
16017 this.constrainY = false;
16022 * Clears any tick interval defined for this instance
16023 * @method clearTicks
16025 clearTicks: function() {
16026 this.xTicks = null;
16027 this.yTicks = null;
16028 this.xTickSize = 0;
16029 this.yTickSize = 0;
16033 * By default, the element can be dragged any place on the screen. Set
16034 * this to limit the vertical travel of the element. Pass in 0,0 for the
16035 * parameters if you want to lock the drag to the x axis.
16036 * @method setYConstraint
16037 * @param {int} iUp the number of pixels the element can move up
16038 * @param {int} iDown the number of pixels the element can move down
16039 * @param {int} iTickSize optional parameter for specifying that the
16040 * element should move iTickSize pixels at a time.
16042 setYConstraint: function(iUp, iDown, iTickSize) {
16043 this.topConstraint = iUp;
16044 this.bottomConstraint = iDown;
16046 this.minY = this.initPageY - iUp;
16047 this.maxY = this.initPageY + iDown;
16048 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
16050 this.constrainY = true;
16055 * resetConstraints must be called if you manually reposition a dd element.
16056 * @method resetConstraints
16057 * @param {boolean} maintainOffset
16059 resetConstraints: function() {
16062 // Maintain offsets if necessary
16063 if (this.initPageX || this.initPageX === 0) {
16064 // figure out how much this thing has moved
16065 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
16066 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
16068 this.setInitPosition(dx, dy);
16070 // This is the first time we have detected the element's position
16072 this.setInitPosition();
16075 if (this.constrainX) {
16076 this.setXConstraint( this.leftConstraint,
16077 this.rightConstraint,
16081 if (this.constrainY) {
16082 this.setYConstraint( this.topConstraint,
16083 this.bottomConstraint,
16089 * Normally the drag element is moved pixel by pixel, but we can specify
16090 * that it move a number of pixels at a time. This method resolves the
16091 * location when we have it set up like this.
16093 * @param {int} val where we want to place the object
16094 * @param {int[]} tickArray sorted array of valid points
16095 * @return {int} the closest tick
16098 getTick: function(val, tickArray) {
16101 // If tick interval is not defined, it is effectively 1 pixel,
16102 // so we return the value passed to us.
16104 } else if (tickArray[0] >= val) {
16105 // The value is lower than the first tick, so we return the first
16107 return tickArray[0];
16109 for (var i=0, len=tickArray.length; i<len; ++i) {
16111 if (tickArray[next] && tickArray[next] >= val) {
16112 var diff1 = val - tickArray[i];
16113 var diff2 = tickArray[next] - val;
16114 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
16118 // The value is larger than the last tick, so we return the last
16120 return tickArray[tickArray.length - 1];
16127 * @return {string} string representation of the dd obj
16129 toString: function() {
16130 return ("DragDrop " + this.id);
16138 * Ext JS Library 1.1.1
16139 * Copyright(c) 2006-2007, Ext JS, LLC.
16141 * Originally Released Under LGPL - original licence link has changed is not relivant.
16144 * <script type="text/javascript">
16149 * The drag and drop utility provides a framework for building drag and drop
16150 * applications. In addition to enabling drag and drop for specific elements,
16151 * the drag and drop elements are tracked by the manager class, and the
16152 * interactions between the various elements are tracked during the drag and
16153 * the implementing code is notified about these important moments.
16156 // Only load the library once. Rewriting the manager class would orphan
16157 // existing drag and drop instances.
16158 if (!Roo.dd.DragDropMgr) {
16161 * @class Roo.dd.DragDropMgr
16162 * DragDropMgr is a singleton that tracks the element interaction for
16163 * all DragDrop items in the window. Generally, you will not call
16164 * this class directly, but it does have helper methods that could
16165 * be useful in your DragDrop implementations.
16168 Roo.dd.DragDropMgr = function() {
16170 var Event = Roo.EventManager;
16175 * Two dimensional Array of registered DragDrop objects. The first
16176 * dimension is the DragDrop item group, the second the DragDrop
16179 * @type {string: string}
16186 * Array of element ids defined as drag handles. Used to determine
16187 * if the element that generated the mousedown event is actually the
16188 * handle and not the html element itself.
16189 * @property handleIds
16190 * @type {string: string}
16197 * the DragDrop object that is currently being dragged
16198 * @property dragCurrent
16206 * the DragDrop object(s) that are being hovered over
16207 * @property dragOvers
16215 * the X distance between the cursor and the object being dragged
16224 * the Y distance between the cursor and the object being dragged
16233 * Flag to determine if we should prevent the default behavior of the
16234 * events we define. By default this is true, but this can be set to
16235 * false if you need the default behavior (not recommended)
16236 * @property preventDefault
16240 preventDefault: true,
16243 * Flag to determine if we should stop the propagation of the events
16244 * we generate. This is true by default but you may want to set it to
16245 * false if the html element contains other features that require the
16247 * @property stopPropagation
16251 stopPropagation: true,
16254 * Internal flag that is set to true when drag and drop has been
16256 * @property initialized
16263 * All drag and drop can be disabled.
16271 * Called the first time an element is registered.
16277 this.initialized = true;
16281 * In point mode, drag and drop interaction is defined by the
16282 * location of the cursor during the drag/drop
16290 * In intersect mode, drag and drop interactio nis defined by the
16291 * overlap of two or more drag and drop objects.
16292 * @property INTERSECT
16299 * The current drag and drop mode. Default: POINT
16307 * Runs method on all drag and drop objects
16308 * @method _execOnAll
16312 _execOnAll: function(sMethod, args) {
16313 for (var i in this.ids) {
16314 for (var j in this.ids[i]) {
16315 var oDD = this.ids[i][j];
16316 if (! this.isTypeOfDD(oDD)) {
16319 oDD[sMethod].apply(oDD, args);
16325 * Drag and drop initialization. Sets up the global event handlers
16330 _onLoad: function() {
16334 if (!Roo.isTouch) {
16335 Event.on(document, "mouseup", this.handleMouseUp, this, true);
16336 Event.on(document, "mousemove", this.handleMouseMove, this, true);
16338 Event.on(document, "touchend", this.handleMouseUp, this, true);
16339 Event.on(document, "touchmove", this.handleMouseMove, this, true);
16341 Event.on(window, "unload", this._onUnload, this, true);
16342 Event.on(window, "resize", this._onResize, this, true);
16343 // Event.on(window, "mouseout", this._test);
16348 * Reset constraints on all drag and drop objs
16349 * @method _onResize
16353 _onResize: function(e) {
16354 this._execOnAll("resetConstraints", []);
16358 * Lock all drag and drop functionality
16362 lock: function() { this.locked = true; },
16365 * Unlock all drag and drop functionality
16369 unlock: function() { this.locked = false; },
16372 * Is drag and drop locked?
16374 * @return {boolean} True if drag and drop is locked, false otherwise.
16377 isLocked: function() { return this.locked; },
16380 * Location cache that is set for all drag drop objects when a drag is
16381 * initiated, cleared when the drag is finished.
16382 * @property locationCache
16389 * Set useCache to false if you want to force object the lookup of each
16390 * drag and drop linked element constantly during a drag.
16391 * @property useCache
16398 * The number of pixels that the mouse needs to move after the
16399 * mousedown before the drag is initiated. Default=3;
16400 * @property clickPixelThresh
16404 clickPixelThresh: 3,
16407 * The number of milliseconds after the mousedown event to initiate the
16408 * drag if we don't get a mouseup event. Default=1000
16409 * @property clickTimeThresh
16413 clickTimeThresh: 350,
16416 * Flag that indicates that either the drag pixel threshold or the
16417 * mousdown time threshold has been met
16418 * @property dragThreshMet
16423 dragThreshMet: false,
16426 * Timeout used for the click time threshold
16427 * @property clickTimeout
16432 clickTimeout: null,
16435 * The X position of the mousedown event stored for later use when a
16436 * drag threshold is met.
16445 * The Y position of the mousedown event stored for later use when a
16446 * drag threshold is met.
16455 * Each DragDrop instance must be registered with the DragDropMgr.
16456 * This is executed in DragDrop.init()
16457 * @method regDragDrop
16458 * @param {DragDrop} oDD the DragDrop object to register
16459 * @param {String} sGroup the name of the group this element belongs to
16462 regDragDrop: function(oDD, sGroup) {
16463 if (!this.initialized) { this.init(); }
16465 if (!this.ids[sGroup]) {
16466 this.ids[sGroup] = {};
16468 this.ids[sGroup][oDD.id] = oDD;
16472 * Removes the supplied dd instance from the supplied group. Executed
16473 * by DragDrop.removeFromGroup, so don't call this function directly.
16474 * @method removeDDFromGroup
16478 removeDDFromGroup: function(oDD, sGroup) {
16479 if (!this.ids[sGroup]) {
16480 this.ids[sGroup] = {};
16483 var obj = this.ids[sGroup];
16484 if (obj && obj[oDD.id]) {
16485 delete obj[oDD.id];
16490 * Unregisters a drag and drop item. This is executed in
16491 * DragDrop.unreg, use that method instead of calling this directly.
16496 _remove: function(oDD) {
16497 for (var g in oDD.groups) {
16498 if (g && this.ids[g][oDD.id]) {
16499 delete this.ids[g][oDD.id];
16502 delete this.handleIds[oDD.id];
16506 * Each DragDrop handle element must be registered. This is done
16507 * automatically when executing DragDrop.setHandleElId()
16508 * @method regHandle
16509 * @param {String} sDDId the DragDrop id this element is a handle for
16510 * @param {String} sHandleId the id of the element that is the drag
16514 regHandle: function(sDDId, sHandleId) {
16515 if (!this.handleIds[sDDId]) {
16516 this.handleIds[sDDId] = {};
16518 this.handleIds[sDDId][sHandleId] = sHandleId;
16522 * Utility function to determine if a given element has been
16523 * registered as a drag drop item.
16524 * @method isDragDrop
16525 * @param {String} id the element id to check
16526 * @return {boolean} true if this element is a DragDrop item,
16530 isDragDrop: function(id) {
16531 return ( this.getDDById(id) ) ? true : false;
16535 * Returns the drag and drop instances that are in all groups the
16536 * passed in instance belongs to.
16537 * @method getRelated
16538 * @param {DragDrop} p_oDD the obj to get related data for
16539 * @param {boolean} bTargetsOnly if true, only return targetable objs
16540 * @return {DragDrop[]} the related instances
16543 getRelated: function(p_oDD, bTargetsOnly) {
16545 for (var i in p_oDD.groups) {
16546 for (j in this.ids[i]) {
16547 var dd = this.ids[i][j];
16548 if (! this.isTypeOfDD(dd)) {
16551 if (!bTargetsOnly || dd.isTarget) {
16552 oDDs[oDDs.length] = dd;
16561 * Returns true if the specified dd target is a legal target for
16562 * the specifice drag obj
16563 * @method isLegalTarget
16564 * @param {DragDrop} the drag obj
16565 * @param {DragDrop} the target
16566 * @return {boolean} true if the target is a legal target for the
16570 isLegalTarget: function (oDD, oTargetDD) {
16571 var targets = this.getRelated(oDD, true);
16572 for (var i=0, len=targets.length;i<len;++i) {
16573 if (targets[i].id == oTargetDD.id) {
16582 * My goal is to be able to transparently determine if an object is
16583 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16584 * returns "object", oDD.constructor.toString() always returns
16585 * "DragDrop" and not the name of the subclass. So for now it just
16586 * evaluates a well-known variable in DragDrop.
16587 * @method isTypeOfDD
16588 * @param {Object} the object to evaluate
16589 * @return {boolean} true if typeof oDD = DragDrop
16592 isTypeOfDD: function (oDD) {
16593 return (oDD && oDD.__ygDragDrop);
16597 * Utility function to determine if a given element has been
16598 * registered as a drag drop handle for the given Drag Drop object.
16600 * @param {String} id the element id to check
16601 * @return {boolean} true if this element is a DragDrop handle, false
16605 isHandle: function(sDDId, sHandleId) {
16606 return ( this.handleIds[sDDId] &&
16607 this.handleIds[sDDId][sHandleId] );
16611 * Returns the DragDrop instance for a given id
16612 * @method getDDById
16613 * @param {String} id the id of the DragDrop object
16614 * @return {DragDrop} the drag drop object, null if it is not found
16617 getDDById: function(id) {
16618 for (var i in this.ids) {
16619 if (this.ids[i][id]) {
16620 return this.ids[i][id];
16627 * Fired after a registered DragDrop object gets the mousedown event.
16628 * Sets up the events required to track the object being dragged
16629 * @method handleMouseDown
16630 * @param {Event} e the event
16631 * @param oDD the DragDrop object being dragged
16635 handleMouseDown: function(e, oDD) {
16637 Roo.QuickTips.disable();
16639 this.currentTarget = e.getTarget();
16641 this.dragCurrent = oDD;
16643 var el = oDD.getEl();
16645 // track start position
16646 this.startX = e.getPageX();
16647 this.startY = e.getPageY();
16649 this.deltaX = this.startX - el.offsetLeft;
16650 this.deltaY = this.startY - el.offsetTop;
16652 this.dragThreshMet = false;
16654 this.clickTimeout = setTimeout(
16656 var DDM = Roo.dd.DDM;
16657 DDM.startDrag(DDM.startX, DDM.startY);
16659 this.clickTimeThresh );
16663 * Fired when either the drag pixel threshol or the mousedown hold
16664 * time threshold has been met.
16665 * @method startDrag
16666 * @param x {int} the X position of the original mousedown
16667 * @param y {int} the Y position of the original mousedown
16670 startDrag: function(x, y) {
16671 clearTimeout(this.clickTimeout);
16672 if (this.dragCurrent) {
16673 this.dragCurrent.b4StartDrag(x, y);
16674 this.dragCurrent.startDrag(x, y);
16676 this.dragThreshMet = true;
16680 * Internal function to handle the mouseup event. Will be invoked
16681 * from the context of the document.
16682 * @method handleMouseUp
16683 * @param {Event} e the event
16687 handleMouseUp: function(e) {
16690 Roo.QuickTips.enable();
16692 if (! this.dragCurrent) {
16696 clearTimeout(this.clickTimeout);
16698 if (this.dragThreshMet) {
16699 this.fireEvents(e, true);
16709 * Utility to stop event propagation and event default, if these
16710 * features are turned on.
16711 * @method stopEvent
16712 * @param {Event} e the event as returned by this.getEvent()
16715 stopEvent: function(e){
16716 if(this.stopPropagation) {
16717 e.stopPropagation();
16720 if (this.preventDefault) {
16721 e.preventDefault();
16726 * Internal function to clean up event handlers after the drag
16727 * operation is complete
16729 * @param {Event} e the event
16733 stopDrag: function(e) {
16734 // Fire the drag end event for the item that was dragged
16735 if (this.dragCurrent) {
16736 if (this.dragThreshMet) {
16737 this.dragCurrent.b4EndDrag(e);
16738 this.dragCurrent.endDrag(e);
16741 this.dragCurrent.onMouseUp(e);
16744 this.dragCurrent = null;
16745 this.dragOvers = {};
16749 * Internal function to handle the mousemove event. Will be invoked
16750 * from the context of the html element.
16752 * @TODO figure out what we can do about mouse events lost when the
16753 * user drags objects beyond the window boundary. Currently we can
16754 * detect this in internet explorer by verifying that the mouse is
16755 * down during the mousemove event. Firefox doesn't give us the
16756 * button state on the mousemove event.
16757 * @method handleMouseMove
16758 * @param {Event} e the event
16762 handleMouseMove: function(e) {
16763 if (! this.dragCurrent) {
16767 // var button = e.which || e.button;
16769 // check for IE mouseup outside of page boundary
16770 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16772 return this.handleMouseUp(e);
16775 if (!this.dragThreshMet) {
16776 var diffX = Math.abs(this.startX - e.getPageX());
16777 var diffY = Math.abs(this.startY - e.getPageY());
16778 if (diffX > this.clickPixelThresh ||
16779 diffY > this.clickPixelThresh) {
16780 this.startDrag(this.startX, this.startY);
16784 if (this.dragThreshMet) {
16785 this.dragCurrent.b4Drag(e);
16786 this.dragCurrent.onDrag(e);
16787 if(!this.dragCurrent.moveOnly){
16788 this.fireEvents(e, false);
16798 * Iterates over all of the DragDrop elements to find ones we are
16799 * hovering over or dropping on
16800 * @method fireEvents
16801 * @param {Event} e the event
16802 * @param {boolean} isDrop is this a drop op or a mouseover op?
16806 fireEvents: function(e, isDrop) {
16807 var dc = this.dragCurrent;
16809 // If the user did the mouse up outside of the window, we could
16810 // get here even though we have ended the drag.
16811 if (!dc || dc.isLocked()) {
16815 var pt = e.getPoint();
16817 // cache the previous dragOver array
16823 var enterEvts = [];
16825 // Check to see if the object(s) we were hovering over is no longer
16826 // being hovered over so we can fire the onDragOut event
16827 for (var i in this.dragOvers) {
16829 var ddo = this.dragOvers[i];
16831 if (! this.isTypeOfDD(ddo)) {
16835 if (! this.isOverTarget(pt, ddo, this.mode)) {
16836 outEvts.push( ddo );
16839 oldOvers[i] = true;
16840 delete this.dragOvers[i];
16843 for (var sGroup in dc.groups) {
16845 if ("string" != typeof sGroup) {
16849 for (i in this.ids[sGroup]) {
16850 var oDD = this.ids[sGroup][i];
16851 if (! this.isTypeOfDD(oDD)) {
16855 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16856 if (this.isOverTarget(pt, oDD, this.mode)) {
16857 // look for drop interactions
16859 dropEvts.push( oDD );
16860 // look for drag enter and drag over interactions
16863 // initial drag over: dragEnter fires
16864 if (!oldOvers[oDD.id]) {
16865 enterEvts.push( oDD );
16866 // subsequent drag overs: dragOver fires
16868 overEvts.push( oDD );
16871 this.dragOvers[oDD.id] = oDD;
16879 if (outEvts.length) {
16880 dc.b4DragOut(e, outEvts);
16881 dc.onDragOut(e, outEvts);
16884 if (enterEvts.length) {
16885 dc.onDragEnter(e, enterEvts);
16888 if (overEvts.length) {
16889 dc.b4DragOver(e, overEvts);
16890 dc.onDragOver(e, overEvts);
16893 if (dropEvts.length) {
16894 dc.b4DragDrop(e, dropEvts);
16895 dc.onDragDrop(e, dropEvts);
16899 // fire dragout events
16901 for (i=0, len=outEvts.length; i<len; ++i) {
16902 dc.b4DragOut(e, outEvts[i].id);
16903 dc.onDragOut(e, outEvts[i].id);
16906 // fire enter events
16907 for (i=0,len=enterEvts.length; i<len; ++i) {
16908 // dc.b4DragEnter(e, oDD.id);
16909 dc.onDragEnter(e, enterEvts[i].id);
16912 // fire over events
16913 for (i=0,len=overEvts.length; i<len; ++i) {
16914 dc.b4DragOver(e, overEvts[i].id);
16915 dc.onDragOver(e, overEvts[i].id);
16918 // fire drop events
16919 for (i=0, len=dropEvts.length; i<len; ++i) {
16920 dc.b4DragDrop(e, dropEvts[i].id);
16921 dc.onDragDrop(e, dropEvts[i].id);
16926 // notify about a drop that did not find a target
16927 if (isDrop && !dropEvts.length) {
16928 dc.onInvalidDrop(e);
16934 * Helper function for getting the best match from the list of drag
16935 * and drop objects returned by the drag and drop events when we are
16936 * in INTERSECT mode. It returns either the first object that the
16937 * cursor is over, or the object that has the greatest overlap with
16938 * the dragged element.
16939 * @method getBestMatch
16940 * @param {DragDrop[]} dds The array of drag and drop objects
16942 * @return {DragDrop} The best single match
16945 getBestMatch: function(dds) {
16947 // Return null if the input is not what we expect
16948 //if (!dds || !dds.length || dds.length == 0) {
16950 // If there is only one item, it wins
16951 //} else if (dds.length == 1) {
16953 var len = dds.length;
16958 // Loop through the targeted items
16959 for (var i=0; i<len; ++i) {
16961 // If the cursor is over the object, it wins. If the
16962 // cursor is over multiple matches, the first one we come
16964 if (dd.cursorIsOver) {
16967 // Otherwise the object with the most overlap wins
16970 winner.overlap.getArea() < dd.overlap.getArea()) {
16981 * Refreshes the cache of the top-left and bottom-right points of the
16982 * drag and drop objects in the specified group(s). This is in the
16983 * format that is stored in the drag and drop instance, so typical
16986 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16990 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16992 * @TODO this really should be an indexed array. Alternatively this
16993 * method could accept both.
16994 * @method refreshCache
16995 * @param {Object} groups an associative array of groups to refresh
16998 refreshCache: function(groups) {
16999 for (var sGroup in groups) {
17000 if ("string" != typeof sGroup) {
17003 for (var i in this.ids[sGroup]) {
17004 var oDD = this.ids[sGroup][i];
17006 if (this.isTypeOfDD(oDD)) {
17007 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
17008 var loc = this.getLocation(oDD);
17010 this.locationCache[oDD.id] = loc;
17012 delete this.locationCache[oDD.id];
17013 // this will unregister the drag and drop object if
17014 // the element is not in a usable state
17023 * This checks to make sure an element exists and is in the DOM. The
17024 * main purpose is to handle cases where innerHTML is used to remove
17025 * drag and drop objects from the DOM. IE provides an 'unspecified
17026 * error' when trying to access the offsetParent of such an element
17028 * @param {HTMLElement} el the element to check
17029 * @return {boolean} true if the element looks usable
17032 verifyEl: function(el) {
17037 parent = el.offsetParent;
17040 parent = el.offsetParent;
17051 * Returns a Region object containing the drag and drop element's position
17052 * and size, including the padding configured for it
17053 * @method getLocation
17054 * @param {DragDrop} oDD the drag and drop object to get the
17056 * @return {Roo.lib.Region} a Region object representing the total area
17057 * the element occupies, including any padding
17058 * the instance is configured for.
17061 getLocation: function(oDD) {
17062 if (! this.isTypeOfDD(oDD)) {
17066 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
17069 pos= Roo.lib.Dom.getXY(el);
17077 x2 = x1 + el.offsetWidth;
17079 y2 = y1 + el.offsetHeight;
17081 t = y1 - oDD.padding[0];
17082 r = x2 + oDD.padding[1];
17083 b = y2 + oDD.padding[2];
17084 l = x1 - oDD.padding[3];
17086 return new Roo.lib.Region( t, r, b, l );
17090 * Checks the cursor location to see if it over the target
17091 * @method isOverTarget
17092 * @param {Roo.lib.Point} pt The point to evaluate
17093 * @param {DragDrop} oTarget the DragDrop object we are inspecting
17094 * @return {boolean} true if the mouse is over the target
17098 isOverTarget: function(pt, oTarget, intersect) {
17099 // use cache if available
17100 var loc = this.locationCache[oTarget.id];
17101 if (!loc || !this.useCache) {
17102 loc = this.getLocation(oTarget);
17103 this.locationCache[oTarget.id] = loc;
17111 oTarget.cursorIsOver = loc.contains( pt );
17113 // DragDrop is using this as a sanity check for the initial mousedown
17114 // in this case we are done. In POINT mode, if the drag obj has no
17115 // contraints, we are also done. Otherwise we need to evaluate the
17116 // location of the target as related to the actual location of the
17117 // dragged element.
17118 var dc = this.dragCurrent;
17119 if (!dc || !dc.getTargetCoord ||
17120 (!intersect && !dc.constrainX && !dc.constrainY)) {
17121 return oTarget.cursorIsOver;
17124 oTarget.overlap = null;
17126 // Get the current location of the drag element, this is the
17127 // location of the mouse event less the delta that represents
17128 // where the original mousedown happened on the element. We
17129 // need to consider constraints and ticks as well.
17130 var pos = dc.getTargetCoord(pt.x, pt.y);
17132 var el = dc.getDragEl();
17133 var curRegion = new Roo.lib.Region( pos.y,
17134 pos.x + el.offsetWidth,
17135 pos.y + el.offsetHeight,
17138 var overlap = curRegion.intersect(loc);
17141 oTarget.overlap = overlap;
17142 return (intersect) ? true : oTarget.cursorIsOver;
17149 * unload event handler
17150 * @method _onUnload
17154 _onUnload: function(e, me) {
17155 Roo.dd.DragDropMgr.unregAll();
17159 * Cleans up the drag and drop events and objects.
17164 unregAll: function() {
17166 if (this.dragCurrent) {
17168 this.dragCurrent = null;
17171 this._execOnAll("unreg", []);
17173 for (i in this.elementCache) {
17174 delete this.elementCache[i];
17177 this.elementCache = {};
17182 * A cache of DOM elements
17183 * @property elementCache
17190 * Get the wrapper for the DOM element specified
17191 * @method getElWrapper
17192 * @param {String} id the id of the element to get
17193 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
17195 * @deprecated This wrapper isn't that useful
17198 getElWrapper: function(id) {
17199 var oWrapper = this.elementCache[id];
17200 if (!oWrapper || !oWrapper.el) {
17201 oWrapper = this.elementCache[id] =
17202 new this.ElementWrapper(Roo.getDom(id));
17208 * Returns the actual DOM element
17209 * @method getElement
17210 * @param {String} id the id of the elment to get
17211 * @return {Object} The element
17212 * @deprecated use Roo.getDom instead
17215 getElement: function(id) {
17216 return Roo.getDom(id);
17220 * Returns the style property for the DOM element (i.e.,
17221 * document.getElById(id).style)
17223 * @param {String} id the id of the elment to get
17224 * @return {Object} The style property of the element
17225 * @deprecated use Roo.getDom instead
17228 getCss: function(id) {
17229 var el = Roo.getDom(id);
17230 return (el) ? el.style : null;
17234 * Inner class for cached elements
17235 * @class DragDropMgr.ElementWrapper
17240 ElementWrapper: function(el) {
17245 this.el = el || null;
17250 this.id = this.el && el.id;
17252 * A reference to the style property
17255 this.css = this.el && el.style;
17259 * Returns the X position of an html element
17261 * @param el the element for which to get the position
17262 * @return {int} the X coordinate
17264 * @deprecated use Roo.lib.Dom.getX instead
17267 getPosX: function(el) {
17268 return Roo.lib.Dom.getX(el);
17272 * Returns the Y position of an html element
17274 * @param el the element for which to get the position
17275 * @return {int} the Y coordinate
17276 * @deprecated use Roo.lib.Dom.getY instead
17279 getPosY: function(el) {
17280 return Roo.lib.Dom.getY(el);
17284 * Swap two nodes. In IE, we use the native method, for others we
17285 * emulate the IE behavior
17287 * @param n1 the first node to swap
17288 * @param n2 the other node to swap
17291 swapNode: function(n1, n2) {
17295 var p = n2.parentNode;
17296 var s = n2.nextSibling;
17299 p.insertBefore(n1, n2);
17300 } else if (n2 == n1.nextSibling) {
17301 p.insertBefore(n2, n1);
17303 n1.parentNode.replaceChild(n2, n1);
17304 p.insertBefore(n1, s);
17310 * Returns the current scroll position
17311 * @method getScroll
17315 getScroll: function () {
17316 var t, l, dde=document.documentElement, db=document.body;
17317 if (dde && (dde.scrollTop || dde.scrollLeft)) {
17319 l = dde.scrollLeft;
17326 return { top: t, left: l };
17330 * Returns the specified element style property
17332 * @param {HTMLElement} el the element
17333 * @param {string} styleProp the style property
17334 * @return {string} The value of the style property
17335 * @deprecated use Roo.lib.Dom.getStyle
17338 getStyle: function(el, styleProp) {
17339 return Roo.fly(el).getStyle(styleProp);
17343 * Gets the scrollTop
17344 * @method getScrollTop
17345 * @return {int} the document's scrollTop
17348 getScrollTop: function () { return this.getScroll().top; },
17351 * Gets the scrollLeft
17352 * @method getScrollLeft
17353 * @return {int} the document's scrollTop
17356 getScrollLeft: function () { return this.getScroll().left; },
17359 * Sets the x/y position of an element to the location of the
17362 * @param {HTMLElement} moveEl The element to move
17363 * @param {HTMLElement} targetEl The position reference element
17366 moveToEl: function (moveEl, targetEl) {
17367 var aCoord = Roo.lib.Dom.getXY(targetEl);
17368 Roo.lib.Dom.setXY(moveEl, aCoord);
17372 * Numeric array sort function
17373 * @method numericSort
17376 numericSort: function(a, b) { return (a - b); },
17380 * @property _timeoutCount
17387 * Trying to make the load order less important. Without this we get
17388 * an error if this file is loaded before the Event Utility.
17389 * @method _addListeners
17393 _addListeners: function() {
17394 var DDM = Roo.dd.DDM;
17395 if ( Roo.lib.Event && document ) {
17398 if (DDM._timeoutCount > 2000) {
17400 setTimeout(DDM._addListeners, 10);
17401 if (document && document.body) {
17402 DDM._timeoutCount += 1;
17409 * Recursively searches the immediate parent and all child nodes for
17410 * the handle element in order to determine wheter or not it was
17412 * @method handleWasClicked
17413 * @param node the html element to inspect
17416 handleWasClicked: function(node, id) {
17417 if (this.isHandle(id, node.id)) {
17420 // check to see if this is a text node child of the one we want
17421 var p = node.parentNode;
17424 if (this.isHandle(id, p.id)) {
17439 // shorter alias, save a few bytes
17440 Roo.dd.DDM = Roo.dd.DragDropMgr;
17441 Roo.dd.DDM._addListeners();
17445 * Ext JS Library 1.1.1
17446 * Copyright(c) 2006-2007, Ext JS, LLC.
17448 * Originally Released Under LGPL - original licence link has changed is not relivant.
17451 * <script type="text/javascript">
17456 * A DragDrop implementation where the linked element follows the
17457 * mouse cursor during a drag.
17458 * @extends Roo.dd.DragDrop
17460 * @param {String} id the id of the linked element
17461 * @param {String} sGroup the group of related DragDrop items
17462 * @param {object} config an object containing configurable attributes
17463 * Valid properties for DD:
17466 Roo.dd.DD = function(id, sGroup, config) {
17468 this.init(id, sGroup, config);
17472 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17475 * When set to true, the utility automatically tries to scroll the browser
17476 * window wehn a drag and drop element is dragged near the viewport boundary.
17477 * Defaults to true.
17484 * Sets the pointer offset to the distance between the linked element's top
17485 * left corner and the location the element was clicked
17486 * @method autoOffset
17487 * @param {int} iPageX the X coordinate of the click
17488 * @param {int} iPageY the Y coordinate of the click
17490 autoOffset: function(iPageX, iPageY) {
17491 var x = iPageX - this.startPageX;
17492 var y = iPageY - this.startPageY;
17493 this.setDelta(x, y);
17497 * Sets the pointer offset. You can call this directly to force the
17498 * offset to be in a particular location (e.g., pass in 0,0 to set it
17499 * to the center of the object)
17501 * @param {int} iDeltaX the distance from the left
17502 * @param {int} iDeltaY the distance from the top
17504 setDelta: function(iDeltaX, iDeltaY) {
17505 this.deltaX = iDeltaX;
17506 this.deltaY = iDeltaY;
17510 * Sets the drag element to the location of the mousedown or click event,
17511 * maintaining the cursor location relative to the location on the element
17512 * that was clicked. Override this if you want to place the element in a
17513 * location other than where the cursor is.
17514 * @method setDragElPos
17515 * @param {int} iPageX the X coordinate of the mousedown or drag event
17516 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17518 setDragElPos: function(iPageX, iPageY) {
17519 // the first time we do this, we are going to check to make sure
17520 // the element has css positioning
17522 var el = this.getDragEl();
17523 this.alignElWithMouse(el, iPageX, iPageY);
17527 * Sets the element to the location of the mousedown or click event,
17528 * maintaining the cursor location relative to the location on the element
17529 * that was clicked. Override this if you want to place the element in a
17530 * location other than where the cursor is.
17531 * @method alignElWithMouse
17532 * @param {HTMLElement} el the element to move
17533 * @param {int} iPageX the X coordinate of the mousedown or drag event
17534 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17536 alignElWithMouse: function(el, iPageX, iPageY) {
17537 var oCoord = this.getTargetCoord(iPageX, iPageY);
17538 var fly = el.dom ? el : Roo.fly(el);
17539 if (!this.deltaSetXY) {
17540 var aCoord = [oCoord.x, oCoord.y];
17542 var newLeft = fly.getLeft(true);
17543 var newTop = fly.getTop(true);
17544 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17546 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17549 this.cachePosition(oCoord.x, oCoord.y);
17550 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17555 * Saves the most recent position so that we can reset the constraints and
17556 * tick marks on-demand. We need to know this so that we can calculate the
17557 * number of pixels the element is offset from its original position.
17558 * @method cachePosition
17559 * @param iPageX the current x position (optional, this just makes it so we
17560 * don't have to look it up again)
17561 * @param iPageY the current y position (optional, this just makes it so we
17562 * don't have to look it up again)
17564 cachePosition: function(iPageX, iPageY) {
17566 this.lastPageX = iPageX;
17567 this.lastPageY = iPageY;
17569 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17570 this.lastPageX = aCoord[0];
17571 this.lastPageY = aCoord[1];
17576 * Auto-scroll the window if the dragged object has been moved beyond the
17577 * visible window boundary.
17578 * @method autoScroll
17579 * @param {int} x the drag element's x position
17580 * @param {int} y the drag element's y position
17581 * @param {int} h the height of the drag element
17582 * @param {int} w the width of the drag element
17585 autoScroll: function(x, y, h, w) {
17588 // The client height
17589 var clientH = Roo.lib.Dom.getViewWidth();
17591 // The client width
17592 var clientW = Roo.lib.Dom.getViewHeight();
17594 // The amt scrolled down
17595 var st = this.DDM.getScrollTop();
17597 // The amt scrolled right
17598 var sl = this.DDM.getScrollLeft();
17600 // Location of the bottom of the element
17603 // Location of the right of the element
17606 // The distance from the cursor to the bottom of the visible area,
17607 // adjusted so that we don't scroll if the cursor is beyond the
17608 // element drag constraints
17609 var toBot = (clientH + st - y - this.deltaY);
17611 // The distance from the cursor to the right of the visible area
17612 var toRight = (clientW + sl - x - this.deltaX);
17615 // How close to the edge the cursor must be before we scroll
17616 // var thresh = (document.all) ? 100 : 40;
17619 // How many pixels to scroll per autoscroll op. This helps to reduce
17620 // clunky scrolling. IE is more sensitive about this ... it needs this
17621 // value to be higher.
17622 var scrAmt = (document.all) ? 80 : 30;
17624 // Scroll down if we are near the bottom of the visible page and the
17625 // obj extends below the crease
17626 if ( bot > clientH && toBot < thresh ) {
17627 window.scrollTo(sl, st + scrAmt);
17630 // Scroll up if the window is scrolled down and the top of the object
17631 // goes above the top border
17632 if ( y < st && st > 0 && y - st < thresh ) {
17633 window.scrollTo(sl, st - scrAmt);
17636 // Scroll right if the obj is beyond the right border and the cursor is
17637 // near the border.
17638 if ( right > clientW && toRight < thresh ) {
17639 window.scrollTo(sl + scrAmt, st);
17642 // Scroll left if the window has been scrolled to the right and the obj
17643 // extends past the left border
17644 if ( x < sl && sl > 0 && x - sl < thresh ) {
17645 window.scrollTo(sl - scrAmt, st);
17651 * Finds the location the element should be placed if we want to move
17652 * it to where the mouse location less the click offset would place us.
17653 * @method getTargetCoord
17654 * @param {int} iPageX the X coordinate of the click
17655 * @param {int} iPageY the Y coordinate of the click
17656 * @return an object that contains the coordinates (Object.x and Object.y)
17659 getTargetCoord: function(iPageX, iPageY) {
17662 var x = iPageX - this.deltaX;
17663 var y = iPageY - this.deltaY;
17665 if (this.constrainX) {
17666 if (x < this.minX) { x = this.minX; }
17667 if (x > this.maxX) { x = this.maxX; }
17670 if (this.constrainY) {
17671 if (y < this.minY) { y = this.minY; }
17672 if (y > this.maxY) { y = this.maxY; }
17675 x = this.getTick(x, this.xTicks);
17676 y = this.getTick(y, this.yTicks);
17683 * Sets up config options specific to this class. Overrides
17684 * Roo.dd.DragDrop, but all versions of this method through the
17685 * inheritance chain are called
17687 applyConfig: function() {
17688 Roo.dd.DD.superclass.applyConfig.call(this);
17689 this.scroll = (this.config.scroll !== false);
17693 * Event that fires prior to the onMouseDown event. Overrides
17696 b4MouseDown: function(e) {
17697 // this.resetConstraints();
17698 this.autoOffset(e.getPageX(),
17703 * Event that fires prior to the onDrag event. Overrides
17706 b4Drag: function(e) {
17707 this.setDragElPos(e.getPageX(),
17711 toString: function() {
17712 return ("DD " + this.id);
17715 //////////////////////////////////////////////////////////////////////////
17716 // Debugging ygDragDrop events that can be overridden
17717 //////////////////////////////////////////////////////////////////////////
17719 startDrag: function(x, y) {
17722 onDrag: function(e) {
17725 onDragEnter: function(e, id) {
17728 onDragOver: function(e, id) {
17731 onDragOut: function(e, id) {
17734 onDragDrop: function(e, id) {
17737 endDrag: function(e) {
17744 * Ext JS Library 1.1.1
17745 * Copyright(c) 2006-2007, Ext JS, LLC.
17747 * Originally Released Under LGPL - original licence link has changed is not relivant.
17750 * <script type="text/javascript">
17754 * @class Roo.dd.DDProxy
17755 * A DragDrop implementation that inserts an empty, bordered div into
17756 * the document that follows the cursor during drag operations. At the time of
17757 * the click, the frame div is resized to the dimensions of the linked html
17758 * element, and moved to the exact location of the linked element.
17760 * References to the "frame" element refer to the single proxy element that
17761 * was created to be dragged in place of all DDProxy elements on the
17764 * @extends Roo.dd.DD
17766 * @param {String} id the id of the linked html element
17767 * @param {String} sGroup the group of related DragDrop objects
17768 * @param {object} config an object containing configurable attributes
17769 * Valid properties for DDProxy in addition to those in DragDrop:
17770 * resizeFrame, centerFrame, dragElId
17772 Roo.dd.DDProxy = function(id, sGroup, config) {
17774 this.init(id, sGroup, config);
17780 * The default drag frame div id
17781 * @property Roo.dd.DDProxy.dragElId
17785 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17787 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17790 * By default we resize the drag frame to be the same size as the element
17791 * we want to drag (this is to get the frame effect). We can turn it off
17792 * if we want a different behavior.
17793 * @property resizeFrame
17799 * By default the frame is positioned exactly where the drag element is, so
17800 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17801 * you do not have constraints on the obj is to have the drag frame centered
17802 * around the cursor. Set centerFrame to true for this effect.
17803 * @property centerFrame
17806 centerFrame: false,
17809 * Creates the proxy element if it does not yet exist
17810 * @method createFrame
17812 createFrame: function() {
17814 var body = document.body;
17816 if (!body || !body.firstChild) {
17817 setTimeout( function() { self.createFrame(); }, 50 );
17821 var div = this.getDragEl();
17824 div = document.createElement("div");
17825 div.id = this.dragElId;
17828 s.position = "absolute";
17829 s.visibility = "hidden";
17831 s.border = "2px solid #aaa";
17834 // appendChild can blow up IE if invoked prior to the window load event
17835 // while rendering a table. It is possible there are other scenarios
17836 // that would cause this to happen as well.
17837 body.insertBefore(div, body.firstChild);
17842 * Initialization for the drag frame element. Must be called in the
17843 * constructor of all subclasses
17844 * @method initFrame
17846 initFrame: function() {
17847 this.createFrame();
17850 applyConfig: function() {
17851 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17853 this.resizeFrame = (this.config.resizeFrame !== false);
17854 this.centerFrame = (this.config.centerFrame);
17855 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17859 * Resizes the drag frame to the dimensions of the clicked object, positions
17860 * it over the object, and finally displays it
17861 * @method showFrame
17862 * @param {int} iPageX X click position
17863 * @param {int} iPageY Y click position
17866 showFrame: function(iPageX, iPageY) {
17867 var el = this.getEl();
17868 var dragEl = this.getDragEl();
17869 var s = dragEl.style;
17871 this._resizeProxy();
17873 if (this.centerFrame) {
17874 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17875 Math.round(parseInt(s.height, 10)/2) );
17878 this.setDragElPos(iPageX, iPageY);
17880 Roo.fly(dragEl).show();
17884 * The proxy is automatically resized to the dimensions of the linked
17885 * element when a drag is initiated, unless resizeFrame is set to false
17886 * @method _resizeProxy
17889 _resizeProxy: function() {
17890 if (this.resizeFrame) {
17891 var el = this.getEl();
17892 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17896 // overrides Roo.dd.DragDrop
17897 b4MouseDown: function(e) {
17898 var x = e.getPageX();
17899 var y = e.getPageY();
17900 this.autoOffset(x, y);
17901 this.setDragElPos(x, y);
17904 // overrides Roo.dd.DragDrop
17905 b4StartDrag: function(x, y) {
17906 // show the drag frame
17907 this.showFrame(x, y);
17910 // overrides Roo.dd.DragDrop
17911 b4EndDrag: function(e) {
17912 Roo.fly(this.getDragEl()).hide();
17915 // overrides Roo.dd.DragDrop
17916 // By default we try to move the element to the last location of the frame.
17917 // This is so that the default behavior mirrors that of Roo.dd.DD.
17918 endDrag: function(e) {
17920 var lel = this.getEl();
17921 var del = this.getDragEl();
17923 // Show the drag frame briefly so we can get its position
17924 del.style.visibility = "";
17927 // Hide the linked element before the move to get around a Safari
17929 lel.style.visibility = "hidden";
17930 Roo.dd.DDM.moveToEl(lel, del);
17931 del.style.visibility = "hidden";
17932 lel.style.visibility = "";
17937 beforeMove : function(){
17941 afterDrag : function(){
17945 toString: function() {
17946 return ("DDProxy " + this.id);
17952 * Ext JS Library 1.1.1
17953 * Copyright(c) 2006-2007, Ext JS, LLC.
17955 * Originally Released Under LGPL - original licence link has changed is not relivant.
17958 * <script type="text/javascript">
17962 * @class Roo.dd.DDTarget
17963 * A DragDrop implementation that does not move, but can be a drop
17964 * target. You would get the same result by simply omitting implementation
17965 * for the event callbacks, but this way we reduce the processing cost of the
17966 * event listener and the callbacks.
17967 * @extends Roo.dd.DragDrop
17969 * @param {String} id the id of the element that is a drop target
17970 * @param {String} sGroup the group of related DragDrop objects
17971 * @param {object} config an object containing configurable attributes
17972 * Valid properties for DDTarget in addition to those in
17976 Roo.dd.DDTarget = function(id, sGroup, config) {
17978 this.initTarget(id, sGroup, config);
17980 if (config.listeners || config.events) {
17981 Roo.dd.DragDrop.superclass.constructor.call(this, {
17982 listeners : config.listeners || {},
17983 events : config.events || {}
17988 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17989 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17990 toString: function() {
17991 return ("DDTarget " + this.id);
17996 * Ext JS Library 1.1.1
17997 * Copyright(c) 2006-2007, Ext JS, LLC.
17999 * Originally Released Under LGPL - original licence link has changed is not relivant.
18002 * <script type="text/javascript">
18007 * @class Roo.dd.ScrollManager
18008 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
18009 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
18012 Roo.dd.ScrollManager = function(){
18013 var ddm = Roo.dd.DragDropMgr;
18020 var onStop = function(e){
18025 var triggerRefresh = function(){
18026 if(ddm.dragCurrent){
18027 ddm.refreshCache(ddm.dragCurrent.groups);
18031 var doScroll = function(){
18032 if(ddm.dragCurrent){
18033 var dds = Roo.dd.ScrollManager;
18035 if(proc.el.scroll(proc.dir, dds.increment)){
18039 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
18044 var clearProc = function(){
18046 clearInterval(proc.id);
18053 var startProc = function(el, dir){
18054 Roo.log('scroll startproc');
18058 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
18061 var onFire = function(e, isDrop){
18063 if(isDrop || !ddm.dragCurrent){ return; }
18064 var dds = Roo.dd.ScrollManager;
18065 if(!dragEl || dragEl != ddm.dragCurrent){
18066 dragEl = ddm.dragCurrent;
18067 // refresh regions on drag start
18068 dds.refreshCache();
18071 var xy = Roo.lib.Event.getXY(e);
18072 var pt = new Roo.lib.Point(xy[0], xy[1]);
18073 for(var id in els){
18074 var el = els[id], r = el._region;
18075 if(r && r.contains(pt) && el.isScrollable()){
18076 if(r.bottom - pt.y <= dds.thresh){
18078 startProc(el, "down");
18081 }else if(r.right - pt.x <= dds.thresh){
18083 startProc(el, "left");
18086 }else if(pt.y - r.top <= dds.thresh){
18088 startProc(el, "up");
18091 }else if(pt.x - r.left <= dds.thresh){
18093 startProc(el, "right");
18102 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
18103 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
18107 * Registers new overflow element(s) to auto scroll
18108 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
18110 register : function(el){
18111 if(el instanceof Array){
18112 for(var i = 0, len = el.length; i < len; i++) {
18113 this.register(el[i]);
18119 Roo.dd.ScrollManager.els = els;
18123 * Unregisters overflow element(s) so they are no longer scrolled
18124 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
18126 unregister : function(el){
18127 if(el instanceof Array){
18128 for(var i = 0, len = el.length; i < len; i++) {
18129 this.unregister(el[i]);
18138 * The number of pixels from the edge of a container the pointer needs to be to
18139 * trigger scrolling (defaults to 25)
18145 * The number of pixels to scroll in each scroll increment (defaults to 50)
18151 * The frequency of scrolls in milliseconds (defaults to 500)
18157 * True to animate the scroll (defaults to true)
18163 * The animation duration in seconds -
18164 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
18170 * Manually trigger a cache refresh.
18172 refreshCache : function(){
18173 for(var id in els){
18174 if(typeof els[id] == 'object'){ // for people extending the object prototype
18175 els[id]._region = els[id].getRegion();
18182 * Ext JS Library 1.1.1
18183 * Copyright(c) 2006-2007, Ext JS, LLC.
18185 * Originally Released Under LGPL - original licence link has changed is not relivant.
18188 * <script type="text/javascript">
18193 * @class Roo.dd.Registry
18194 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
18195 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
18198 Roo.dd.Registry = function(){
18201 var autoIdSeed = 0;
18203 var getId = function(el, autogen){
18204 if(typeof el == "string"){
18208 if(!id && autogen !== false){
18209 id = "roodd-" + (++autoIdSeed);
18217 * Register a drag drop element
18218 * @param {String|HTMLElement} element The id or DOM node to register
18219 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
18220 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
18221 * knows how to interpret, plus there are some specific properties known to the Registry that should be
18222 * populated in the data object (if applicable):
18224 Value Description<br />
18225 --------- ------------------------------------------<br />
18226 handles Array of DOM nodes that trigger dragging<br />
18227 for the element being registered<br />
18228 isHandle True if the element passed in triggers<br />
18229 dragging itself, else false
18232 register : function(el, data){
18234 if(typeof el == "string"){
18235 el = document.getElementById(el);
18238 elements[getId(el)] = data;
18239 if(data.isHandle !== false){
18240 handles[data.ddel.id] = data;
18243 var hs = data.handles;
18244 for(var i = 0, len = hs.length; i < len; i++){
18245 handles[getId(hs[i])] = data;
18251 * Unregister a drag drop element
18252 * @param {String|HTMLElement} element The id or DOM node to unregister
18254 unregister : function(el){
18255 var id = getId(el, false);
18256 var data = elements[id];
18258 delete elements[id];
18260 var hs = data.handles;
18261 for(var i = 0, len = hs.length; i < len; i++){
18262 delete handles[getId(hs[i], false)];
18269 * Returns the handle registered for a DOM Node by id
18270 * @param {String|HTMLElement} id The DOM node or id to look up
18271 * @return {Object} handle The custom handle data
18273 getHandle : function(id){
18274 if(typeof id != "string"){ // must be element?
18277 return handles[id];
18281 * Returns the handle that is registered for the DOM node that is the target of the event
18282 * @param {Event} e The event
18283 * @return {Object} handle The custom handle data
18285 getHandleFromEvent : function(e){
18286 var t = Roo.lib.Event.getTarget(e);
18287 return t ? handles[t.id] : null;
18291 * Returns a custom data object that is registered for a DOM node by id
18292 * @param {String|HTMLElement} id The DOM node or id to look up
18293 * @return {Object} data The custom data
18295 getTarget : function(id){
18296 if(typeof id != "string"){ // must be element?
18299 return elements[id];
18303 * Returns a custom data object that is registered for the DOM node that is the target of the event
18304 * @param {Event} e The event
18305 * @return {Object} data The custom data
18307 getTargetFromEvent : function(e){
18308 var t = Roo.lib.Event.getTarget(e);
18309 return t ? elements[t.id] || handles[t.id] : null;
18314 * Ext JS Library 1.1.1
18315 * Copyright(c) 2006-2007, Ext JS, LLC.
18317 * Originally Released Under LGPL - original licence link has changed is not relivant.
18320 * <script type="text/javascript">
18325 * @class Roo.dd.StatusProxy
18326 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
18327 * default drag proxy used by all Roo.dd components.
18329 * @param {Object} config
18331 Roo.dd.StatusProxy = function(config){
18332 Roo.apply(this, config);
18333 this.id = this.id || Roo.id();
18334 this.el = new Roo.Layer({
18336 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
18337 {tag: "div", cls: "x-dd-drop-icon"},
18338 {tag: "div", cls: "x-dd-drag-ghost"}
18341 shadow: !config || config.shadow !== false
18343 this.ghost = Roo.get(this.el.dom.childNodes[1]);
18344 this.dropStatus = this.dropNotAllowed;
18347 Roo.dd.StatusProxy.prototype = {
18349 * @cfg {String} dropAllowed
18350 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
18352 dropAllowed : "x-dd-drop-ok",
18354 * @cfg {String} dropNotAllowed
18355 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
18357 dropNotAllowed : "x-dd-drop-nodrop",
18360 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
18361 * over the current target element.
18362 * @param {String} cssClass The css class for the new drop status indicator image
18364 setStatus : function(cssClass){
18365 cssClass = cssClass || this.dropNotAllowed;
18366 if(this.dropStatus != cssClass){
18367 this.el.replaceClass(this.dropStatus, cssClass);
18368 this.dropStatus = cssClass;
18373 * Resets the status indicator to the default dropNotAllowed value
18374 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
18376 reset : function(clearGhost){
18377 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
18378 this.dropStatus = this.dropNotAllowed;
18380 this.ghost.update("");
18385 * Updates the contents of the ghost element
18386 * @param {String} html The html that will replace the current innerHTML of the ghost element
18388 update : function(html){
18389 if(typeof html == "string"){
18390 this.ghost.update(html);
18392 this.ghost.update("");
18393 html.style.margin = "0";
18394 this.ghost.dom.appendChild(html);
18396 // ensure float = none set?? cant remember why though.
18397 var el = this.ghost.dom.firstChild;
18399 Roo.fly(el).setStyle('float', 'none');
18404 * Returns the underlying proxy {@link Roo.Layer}
18405 * @return {Roo.Layer} el
18407 getEl : function(){
18412 * Returns the ghost element
18413 * @return {Roo.Element} el
18415 getGhost : function(){
18421 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
18423 hide : function(clear){
18431 * Stops the repair animation if it's currently running
18434 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
18440 * Displays this proxy
18447 * Force the Layer to sync its shadow and shim positions to the element
18454 * Causes the proxy to return to its position of origin via an animation. Should be called after an
18455 * invalid drop operation by the item being dragged.
18456 * @param {Array} xy The XY position of the element ([x, y])
18457 * @param {Function} callback The function to call after the repair is complete
18458 * @param {Object} scope The scope in which to execute the callback
18460 repair : function(xy, callback, scope){
18461 this.callback = callback;
18462 this.scope = scope;
18463 if(xy && this.animRepair !== false){
18464 this.el.addClass("x-dd-drag-repair");
18465 this.el.hideUnders(true);
18466 this.anim = this.el.shift({
18467 duration: this.repairDuration || .5,
18471 callback: this.afterRepair,
18475 this.afterRepair();
18480 afterRepair : function(){
18482 if(typeof this.callback == "function"){
18483 this.callback.call(this.scope || this);
18485 this.callback = null;
18490 * Ext JS Library 1.1.1
18491 * Copyright(c) 2006-2007, Ext JS, LLC.
18493 * Originally Released Under LGPL - original licence link has changed is not relivant.
18496 * <script type="text/javascript">
18500 * @class Roo.dd.DragSource
18501 * @extends Roo.dd.DDProxy
18502 * A simple class that provides the basic implementation needed to make any element draggable.
18504 * @param {String/HTMLElement/Element} el The container element
18505 * @param {Object} config
18507 Roo.dd.DragSource = function(el, config){
18508 this.el = Roo.get(el);
18509 this.dragData = {};
18511 Roo.apply(this, config);
18514 this.proxy = new Roo.dd.StatusProxy();
18517 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18518 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18520 this.dragging = false;
18523 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18525 * @cfg {String} dropAllowed
18526 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18528 dropAllowed : "x-dd-drop-ok",
18530 * @cfg {String} dropNotAllowed
18531 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18533 dropNotAllowed : "x-dd-drop-nodrop",
18536 * Returns the data object associated with this drag source
18537 * @return {Object} data An object containing arbitrary data
18539 getDragData : function(e){
18540 return this.dragData;
18544 onDragEnter : function(e, id){
18545 var target = Roo.dd.DragDropMgr.getDDById(id);
18546 this.cachedTarget = target;
18547 if(this.beforeDragEnter(target, e, id) !== false){
18548 if(target.isNotifyTarget){
18549 var status = target.notifyEnter(this, e, this.dragData);
18550 this.proxy.setStatus(status);
18552 this.proxy.setStatus(this.dropAllowed);
18555 if(this.afterDragEnter){
18557 * An empty function by default, but provided so that you can perform a custom action
18558 * when the dragged item enters the drop target by providing an implementation.
18559 * @param {Roo.dd.DragDrop} target The drop target
18560 * @param {Event} e The event object
18561 * @param {String} id The id of the dragged element
18562 * @method afterDragEnter
18564 this.afterDragEnter(target, e, id);
18570 * An empty function by default, but provided so that you can perform a custom action
18571 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18572 * @param {Roo.dd.DragDrop} target The drop target
18573 * @param {Event} e The event object
18574 * @param {String} id The id of the dragged element
18575 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18577 beforeDragEnter : function(target, e, id){
18582 alignElWithMouse: function() {
18583 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18588 onDragOver : function(e, id){
18589 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18590 if(this.beforeDragOver(target, e, id) !== false){
18591 if(target.isNotifyTarget){
18592 var status = target.notifyOver(this, e, this.dragData);
18593 this.proxy.setStatus(status);
18596 if(this.afterDragOver){
18598 * An empty function by default, but provided so that you can perform a custom action
18599 * while the dragged item is over the drop target by providing an implementation.
18600 * @param {Roo.dd.DragDrop} target The drop target
18601 * @param {Event} e The event object
18602 * @param {String} id The id of the dragged element
18603 * @method afterDragOver
18605 this.afterDragOver(target, e, id);
18611 * An empty function by default, but provided so that you can perform a custom action
18612 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18613 * @param {Roo.dd.DragDrop} target The drop target
18614 * @param {Event} e The event object
18615 * @param {String} id The id of the dragged element
18616 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18618 beforeDragOver : function(target, e, id){
18623 onDragOut : function(e, id){
18624 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18625 if(this.beforeDragOut(target, e, id) !== false){
18626 if(target.isNotifyTarget){
18627 target.notifyOut(this, e, this.dragData);
18629 this.proxy.reset();
18630 if(this.afterDragOut){
18632 * An empty function by default, but provided so that you can perform a custom action
18633 * after the dragged item is dragged out of the target without dropping.
18634 * @param {Roo.dd.DragDrop} target The drop target
18635 * @param {Event} e The event object
18636 * @param {String} id The id of the dragged element
18637 * @method afterDragOut
18639 this.afterDragOut(target, e, id);
18642 this.cachedTarget = null;
18646 * An empty function by default, but provided so that you can perform a custom action before the dragged
18647 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18648 * @param {Roo.dd.DragDrop} target The drop target
18649 * @param {Event} e The event object
18650 * @param {String} id The id of the dragged element
18651 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18653 beforeDragOut : function(target, e, id){
18658 onDragDrop : function(e, id){
18659 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18660 if(this.beforeDragDrop(target, e, id) !== false){
18661 if(target.isNotifyTarget){
18662 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18663 this.onValidDrop(target, e, id);
18665 this.onInvalidDrop(target, e, id);
18668 this.onValidDrop(target, e, id);
18671 if(this.afterDragDrop){
18673 * An empty function by default, but provided so that you can perform a custom action
18674 * after a valid drag drop has occurred by providing an implementation.
18675 * @param {Roo.dd.DragDrop} target The drop target
18676 * @param {Event} e The event object
18677 * @param {String} id The id of the dropped element
18678 * @method afterDragDrop
18680 this.afterDragDrop(target, e, id);
18683 delete this.cachedTarget;
18687 * An empty function by default, but provided so that you can perform a custom action before the dragged
18688 * item is dropped onto the target and optionally cancel the onDragDrop.
18689 * @param {Roo.dd.DragDrop} target The drop target
18690 * @param {Event} e The event object
18691 * @param {String} id The id of the dragged element
18692 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18694 beforeDragDrop : function(target, e, id){
18699 onValidDrop : function(target, e, id){
18701 if(this.afterValidDrop){
18703 * An empty function by default, but provided so that you can perform a custom action
18704 * after a valid drop has occurred by providing an implementation.
18705 * @param {Object} target The target DD
18706 * @param {Event} e The event object
18707 * @param {String} id The id of the dropped element
18708 * @method afterInvalidDrop
18710 this.afterValidDrop(target, e, id);
18715 getRepairXY : function(e, data){
18716 return this.el.getXY();
18720 onInvalidDrop : function(target, e, id){
18721 this.beforeInvalidDrop(target, e, id);
18722 if(this.cachedTarget){
18723 if(this.cachedTarget.isNotifyTarget){
18724 this.cachedTarget.notifyOut(this, e, this.dragData);
18726 this.cacheTarget = null;
18728 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18730 if(this.afterInvalidDrop){
18732 * An empty function by default, but provided so that you can perform a custom action
18733 * after an invalid drop has occurred by providing an implementation.
18734 * @param {Event} e The event object
18735 * @param {String} id The id of the dropped element
18736 * @method afterInvalidDrop
18738 this.afterInvalidDrop(e, id);
18743 afterRepair : function(){
18745 this.el.highlight(this.hlColor || "c3daf9");
18747 this.dragging = false;
18751 * An empty function by default, but provided so that you can perform a custom action after an invalid
18752 * drop has occurred.
18753 * @param {Roo.dd.DragDrop} target The drop target
18754 * @param {Event} e The event object
18755 * @param {String} id The id of the dragged element
18756 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18758 beforeInvalidDrop : function(target, e, id){
18763 handleMouseDown : function(e){
18764 if(this.dragging) {
18767 var data = this.getDragData(e);
18768 if(data && this.onBeforeDrag(data, e) !== false){
18769 this.dragData = data;
18771 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18776 * An empty function by default, but provided so that you can perform a custom action before the initial
18777 * drag event begins and optionally cancel it.
18778 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18779 * @param {Event} e The event object
18780 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18782 onBeforeDrag : function(data, e){
18787 * An empty function by default, but provided so that you can perform a custom action once the initial
18788 * drag event has begun. The drag cannot be canceled from this function.
18789 * @param {Number} x The x position of the click on the dragged object
18790 * @param {Number} y The y position of the click on the dragged object
18792 onStartDrag : Roo.emptyFn,
18794 // private - YUI override
18795 startDrag : function(x, y){
18796 this.proxy.reset();
18797 this.dragging = true;
18798 this.proxy.update("");
18799 this.onInitDrag(x, y);
18804 onInitDrag : function(x, y){
18805 var clone = this.el.dom.cloneNode(true);
18806 clone.id = Roo.id(); // prevent duplicate ids
18807 this.proxy.update(clone);
18808 this.onStartDrag(x, y);
18813 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18814 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18816 getProxy : function(){
18821 * Hides the drag source's {@link Roo.dd.StatusProxy}
18823 hideProxy : function(){
18825 this.proxy.reset(true);
18826 this.dragging = false;
18830 triggerCacheRefresh : function(){
18831 Roo.dd.DDM.refreshCache(this.groups);
18834 // private - override to prevent hiding
18835 b4EndDrag: function(e) {
18838 // private - override to prevent moving
18839 endDrag : function(e){
18840 this.onEndDrag(this.dragData, e);
18844 onEndDrag : function(data, e){
18847 // private - pin to cursor
18848 autoOffset : function(x, y) {
18849 this.setDelta(-12, -20);
18853 * Ext JS Library 1.1.1
18854 * Copyright(c) 2006-2007, Ext JS, LLC.
18856 * Originally Released Under LGPL - original licence link has changed is not relivant.
18859 * <script type="text/javascript">
18864 * @class Roo.dd.DropTarget
18865 * @extends Roo.dd.DDTarget
18866 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18867 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18869 * @param {String/HTMLElement/Element} el The container element
18870 * @param {Object} config
18872 Roo.dd.DropTarget = function(el, config){
18873 this.el = Roo.get(el);
18875 var listeners = false; ;
18876 if (config && config.listeners) {
18877 listeners= config.listeners;
18878 delete config.listeners;
18880 Roo.apply(this, config);
18882 if(this.containerScroll){
18883 Roo.dd.ScrollManager.register(this.el);
18887 * @scope Roo.dd.DropTarget
18892 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18893 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18894 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18896 * IMPORTANT : it should set this.overClass and this.dropAllowed
18898 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18899 * @param {Event} e The event
18900 * @param {Object} data An object containing arbitrary data supplied by the drag source
18906 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18907 * This method will be called on every mouse movement while the drag source is over the drop target.
18908 * This default implementation simply returns the dropAllowed config value.
18910 * IMPORTANT : it should set this.dropAllowed
18912 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18913 * @param {Event} e The event
18914 * @param {Object} data An object containing arbitrary data supplied by the drag source
18920 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18921 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18922 * overClass (if any) from the drop element.
18924 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18925 * @param {Event} e The event
18926 * @param {Object} data An object containing arbitrary data supplied by the drag source
18932 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18933 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18934 * implementation that does something to process the drop event and returns true so that the drag source's
18935 * repair action does not run.
18937 * IMPORTANT : it should set this.success
18939 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18940 * @param {Event} e The event
18941 * @param {Object} data An object containing arbitrary data supplied by the drag source
18947 Roo.dd.DropTarget.superclass.constructor.call( this,
18949 this.ddGroup || this.group,
18952 listeners : listeners || {}
18960 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18962 * @cfg {String} overClass
18963 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18966 * @cfg {String} ddGroup
18967 * The drag drop group to handle drop events for
18971 * @cfg {String} dropAllowed
18972 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18974 dropAllowed : "x-dd-drop-ok",
18976 * @cfg {String} dropNotAllowed
18977 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18979 dropNotAllowed : "x-dd-drop-nodrop",
18981 * @cfg {boolean} success
18982 * set this after drop listener..
18986 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18987 * if the drop point is valid for over/enter..
18994 isNotifyTarget : true,
18999 notifyEnter : function(dd, e, data)
19002 this.fireEvent('enter', dd, e, data);
19003 if(this.overClass){
19004 this.el.addClass(this.overClass);
19006 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19007 this.valid ? this.dropAllowed : this.dropNotAllowed
19014 notifyOver : function(dd, e, data)
19017 this.fireEvent('over', dd, e, data);
19018 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19019 this.valid ? this.dropAllowed : this.dropNotAllowed
19026 notifyOut : function(dd, e, data)
19028 this.fireEvent('out', dd, e, data);
19029 if(this.overClass){
19030 this.el.removeClass(this.overClass);
19037 notifyDrop : function(dd, e, data)
19039 this.success = false;
19040 this.fireEvent('drop', dd, e, data);
19041 return this.success;
19045 * Ext JS Library 1.1.1
19046 * Copyright(c) 2006-2007, Ext JS, LLC.
19048 * Originally Released Under LGPL - original licence link has changed is not relivant.
19051 * <script type="text/javascript">
19056 * @class Roo.dd.DragZone
19057 * @extends Roo.dd.DragSource
19058 * This class provides a container DD instance that proxies for multiple child node sources.<br />
19059 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
19061 * @param {String/HTMLElement/Element} el The container element
19062 * @param {Object} config
19064 Roo.dd.DragZone = function(el, config){
19065 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
19066 if(this.containerScroll){
19067 Roo.dd.ScrollManager.register(this.el);
19071 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
19073 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
19074 * for auto scrolling during drag operations.
19077 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
19078 * method after a failed drop (defaults to "c3daf9" - light blue)
19082 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
19083 * for a valid target to drag based on the mouse down. Override this method
19084 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
19085 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
19086 * @param {EventObject} e The mouse down event
19087 * @return {Object} The dragData
19089 getDragData : function(e){
19090 return Roo.dd.Registry.getHandleFromEvent(e);
19094 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
19095 * this.dragData.ddel
19096 * @param {Number} x The x position of the click on the dragged object
19097 * @param {Number} y The y position of the click on the dragged object
19098 * @return {Boolean} true to continue the drag, false to cancel
19100 onInitDrag : function(x, y){
19101 this.proxy.update(this.dragData.ddel.cloneNode(true));
19102 this.onStartDrag(x, y);
19107 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
19109 afterRepair : function(){
19111 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
19113 this.dragging = false;
19117 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
19118 * the XY of this.dragData.ddel
19119 * @param {EventObject} e The mouse up event
19120 * @return {Array} The xy location (e.g. [100, 200])
19122 getRepairXY : function(e){
19123 return Roo.Element.fly(this.dragData.ddel).getXY();
19127 * Ext JS Library 1.1.1
19128 * Copyright(c) 2006-2007, Ext JS, LLC.
19130 * Originally Released Under LGPL - original licence link has changed is not relivant.
19133 * <script type="text/javascript">
19136 * @class Roo.dd.DropZone
19137 * @extends Roo.dd.DropTarget
19138 * This class provides a container DD instance that proxies for multiple child node targets.<br />
19139 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
19141 * @param {String/HTMLElement/Element} el The container element
19142 * @param {Object} config
19144 Roo.dd.DropZone = function(el, config){
19145 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
19148 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
19150 * Returns a custom data object associated with the DOM node that is the target of the event. By default
19151 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
19152 * provide your own custom lookup.
19153 * @param {Event} e The event
19154 * @return {Object} data The custom data
19156 getTargetFromEvent : function(e){
19157 return Roo.dd.Registry.getTargetFromEvent(e);
19161 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
19162 * that it has registered. This method has no default implementation and should be overridden to provide
19163 * node-specific processing if necessary.
19164 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19165 * {@link #getTargetFromEvent} for this node)
19166 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19167 * @param {Event} e The event
19168 * @param {Object} data An object containing arbitrary data supplied by the drag source
19170 onNodeEnter : function(n, dd, e, data){
19175 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
19176 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
19177 * overridden to provide the proper feedback.
19178 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19179 * {@link #getTargetFromEvent} for this node)
19180 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19181 * @param {Event} e The event
19182 * @param {Object} data An object containing arbitrary data supplied by the drag source
19183 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19184 * underlying {@link Roo.dd.StatusProxy} can be updated
19186 onNodeOver : function(n, dd, e, data){
19187 return this.dropAllowed;
19191 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
19192 * the drop node without dropping. This method has no default implementation and should be overridden to provide
19193 * node-specific processing if necessary.
19194 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19195 * {@link #getTargetFromEvent} for this node)
19196 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19197 * @param {Event} e The event
19198 * @param {Object} data An object containing arbitrary data supplied by the drag source
19200 onNodeOut : function(n, dd, e, data){
19205 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
19206 * the drop node. The default implementation returns false, so it should be overridden to provide the
19207 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
19208 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19209 * {@link #getTargetFromEvent} for this node)
19210 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19211 * @param {Event} e The event
19212 * @param {Object} data An object containing arbitrary data supplied by the drag source
19213 * @return {Boolean} True if the drop was valid, else false
19215 onNodeDrop : function(n, dd, e, data){
19220 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
19221 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
19222 * it should be overridden to provide the proper feedback if necessary.
19223 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19224 * @param {Event} e The event
19225 * @param {Object} data An object containing arbitrary data supplied by the drag source
19226 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19227 * underlying {@link Roo.dd.StatusProxy} can be updated
19229 onContainerOver : function(dd, e, data){
19230 return this.dropNotAllowed;
19234 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
19235 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
19236 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
19237 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
19238 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19239 * @param {Event} e The event
19240 * @param {Object} data An object containing arbitrary data supplied by the drag source
19241 * @return {Boolean} True if the drop was valid, else false
19243 onContainerDrop : function(dd, e, data){
19248 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
19249 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
19250 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
19251 * you should override this method and provide a custom implementation.
19252 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19253 * @param {Event} e The event
19254 * @param {Object} data An object containing arbitrary data supplied by the drag source
19255 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19256 * underlying {@link Roo.dd.StatusProxy} can be updated
19258 notifyEnter : function(dd, e, data){
19259 return this.dropNotAllowed;
19263 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
19264 * This method will be called on every mouse movement while the drag source is over the drop zone.
19265 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
19266 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
19267 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
19268 * registered node, it will call {@link #onContainerOver}.
19269 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19270 * @param {Event} e The event
19271 * @param {Object} data An object containing arbitrary data supplied by the drag source
19272 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19273 * underlying {@link Roo.dd.StatusProxy} can be updated
19275 notifyOver : function(dd, e, data){
19276 var n = this.getTargetFromEvent(e);
19277 if(!n){ // not over valid drop target
19278 if(this.lastOverNode){
19279 this.onNodeOut(this.lastOverNode, dd, e, data);
19280 this.lastOverNode = null;
19282 return this.onContainerOver(dd, e, data);
19284 if(this.lastOverNode != n){
19285 if(this.lastOverNode){
19286 this.onNodeOut(this.lastOverNode, dd, e, data);
19288 this.onNodeEnter(n, dd, e, data);
19289 this.lastOverNode = n;
19291 return this.onNodeOver(n, dd, e, data);
19295 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
19296 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
19297 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
19298 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
19299 * @param {Event} e The event
19300 * @param {Object} data An object containing arbitrary data supplied by the drag zone
19302 notifyOut : function(dd, e, data){
19303 if(this.lastOverNode){
19304 this.onNodeOut(this.lastOverNode, dd, e, data);
19305 this.lastOverNode = null;
19310 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
19311 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
19312 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
19313 * otherwise it will call {@link #onContainerDrop}.
19314 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19315 * @param {Event} e The event
19316 * @param {Object} data An object containing arbitrary data supplied by the drag source
19317 * @return {Boolean} True if the drop was valid, else false
19319 notifyDrop : function(dd, e, data){
19320 if(this.lastOverNode){
19321 this.onNodeOut(this.lastOverNode, dd, e, data);
19322 this.lastOverNode = null;
19324 var n = this.getTargetFromEvent(e);
19326 this.onNodeDrop(n, dd, e, data) :
19327 this.onContainerDrop(dd, e, data);
19331 triggerCacheRefresh : function(){
19332 Roo.dd.DDM.refreshCache(this.groups);
19336 * Ext JS Library 1.1.1
19337 * Copyright(c) 2006-2007, Ext JS, LLC.
19339 * Originally Released Under LGPL - original licence link has changed is not relivant.
19342 * <script type="text/javascript">
19347 * @class Roo.data.SortTypes
19349 * Defines the default sorting (casting?) comparison functions used when sorting data.
19351 Roo.data.SortTypes = {
19353 * Default sort that does nothing
19354 * @param {Mixed} s The value being converted
19355 * @return {Mixed} The comparison value
19357 none : function(s){
19362 * The regular expression used to strip tags
19366 stripTagsRE : /<\/?[^>]+>/gi,
19369 * Strips all HTML tags to sort on text only
19370 * @param {Mixed} s The value being converted
19371 * @return {String} The comparison value
19373 asText : function(s){
19374 return String(s).replace(this.stripTagsRE, "");
19378 * Strips all HTML tags to sort on text only - Case insensitive
19379 * @param {Mixed} s The value being converted
19380 * @return {String} The comparison value
19382 asUCText : function(s){
19383 return String(s).toUpperCase().replace(this.stripTagsRE, "");
19387 * Case insensitive string
19388 * @param {Mixed} s The value being converted
19389 * @return {String} The comparison value
19391 asUCString : function(s) {
19392 return String(s).toUpperCase();
19397 * @param {Mixed} s The value being converted
19398 * @return {Number} The comparison value
19400 asDate : function(s) {
19404 if(s instanceof Date){
19405 return s.getTime();
19407 return Date.parse(String(s));
19412 * @param {Mixed} s The value being converted
19413 * @return {Float} The comparison value
19415 asFloat : function(s) {
19416 var val = parseFloat(String(s).replace(/,/g, ""));
19417 if(isNaN(val)) val = 0;
19423 * @param {Mixed} s The value being converted
19424 * @return {Number} The comparison value
19426 asInt : function(s) {
19427 var val = parseInt(String(s).replace(/,/g, ""));
19428 if(isNaN(val)) val = 0;
19433 * Ext JS Library 1.1.1
19434 * Copyright(c) 2006-2007, Ext JS, LLC.
19436 * Originally Released Under LGPL - original licence link has changed is not relivant.
19439 * <script type="text/javascript">
19443 * @class Roo.data.Record
19444 * Instances of this class encapsulate both record <em>definition</em> information, and record
19445 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
19446 * to access Records cached in an {@link Roo.data.Store} object.<br>
19448 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
19449 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
19452 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
19454 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
19455 * {@link #create}. The parameters are the same.
19456 * @param {Array} data An associative Array of data values keyed by the field name.
19457 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
19458 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
19459 * not specified an integer id is generated.
19461 Roo.data.Record = function(data, id){
19462 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
19467 * Generate a constructor for a specific record layout.
19468 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
19469 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
19470 * Each field definition object may contain the following properties: <ul>
19471 * <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,
19472 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
19473 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
19474 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
19475 * is being used, then this is a string containing the javascript expression to reference the data relative to
19476 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
19477 * to the data item relative to the record element. If the mapping expression is the same as the field name,
19478 * this may be omitted.</p></li>
19479 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
19480 * <ul><li>auto (Default, implies no conversion)</li>
19485 * <li>date</li></ul></p></li>
19486 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
19487 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
19488 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19489 * by the Reader into an object that will be stored in the Record. It is passed the
19490 * following parameters:<ul>
19491 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19493 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19495 * <br>usage:<br><pre><code>
19496 var TopicRecord = Roo.data.Record.create(
19497 {name: 'title', mapping: 'topic_title'},
19498 {name: 'author', mapping: 'username'},
19499 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19500 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19501 {name: 'lastPoster', mapping: 'user2'},
19502 {name: 'excerpt', mapping: 'post_text'}
19505 var myNewRecord = new TopicRecord({
19506 title: 'Do my job please',
19509 lastPost: new Date(),
19510 lastPoster: 'Animal',
19511 excerpt: 'No way dude!'
19513 myStore.add(myNewRecord);
19518 Roo.data.Record.create = function(o){
19519 var f = function(){
19520 f.superclass.constructor.apply(this, arguments);
19522 Roo.extend(f, Roo.data.Record);
19523 var p = f.prototype;
19524 p.fields = new Roo.util.MixedCollection(false, function(field){
19527 for(var i = 0, len = o.length; i < len; i++){
19528 p.fields.add(new Roo.data.Field(o[i]));
19530 f.getField = function(name){
19531 return p.fields.get(name);
19536 Roo.data.Record.AUTO_ID = 1000;
19537 Roo.data.Record.EDIT = 'edit';
19538 Roo.data.Record.REJECT = 'reject';
19539 Roo.data.Record.COMMIT = 'commit';
19541 Roo.data.Record.prototype = {
19543 * Readonly flag - true if this record has been modified.
19552 join : function(store){
19553 this.store = store;
19557 * Set the named field to the specified value.
19558 * @param {String} name The name of the field to set.
19559 * @param {Object} value The value to set the field to.
19561 set : function(name, value){
19562 if(this.data[name] == value){
19566 if(!this.modified){
19567 this.modified = {};
19569 if(typeof this.modified[name] == 'undefined'){
19570 this.modified[name] = this.data[name];
19572 this.data[name] = value;
19573 if(!this.editing && this.store){
19574 this.store.afterEdit(this);
19579 * Get the value of the named field.
19580 * @param {String} name The name of the field to get the value of.
19581 * @return {Object} The value of the field.
19583 get : function(name){
19584 return this.data[name];
19588 beginEdit : function(){
19589 this.editing = true;
19590 this.modified = {};
19594 cancelEdit : function(){
19595 this.editing = false;
19596 delete this.modified;
19600 endEdit : function(){
19601 this.editing = false;
19602 if(this.dirty && this.store){
19603 this.store.afterEdit(this);
19608 * Usually called by the {@link Roo.data.Store} which owns the Record.
19609 * Rejects all changes made to the Record since either creation, or the last commit operation.
19610 * Modified fields are reverted to their original values.
19612 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19613 * of reject operations.
19615 reject : function(){
19616 var m = this.modified;
19618 if(typeof m[n] != "function"){
19619 this.data[n] = m[n];
19622 this.dirty = false;
19623 delete this.modified;
19624 this.editing = false;
19626 this.store.afterReject(this);
19631 * Usually called by the {@link Roo.data.Store} which owns the Record.
19632 * Commits all changes made to the Record since either creation, or the last commit operation.
19634 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19635 * of commit operations.
19637 commit : function(){
19638 this.dirty = false;
19639 delete this.modified;
19640 this.editing = false;
19642 this.store.afterCommit(this);
19647 hasError : function(){
19648 return this.error != null;
19652 clearError : function(){
19657 * Creates a copy of this record.
19658 * @param {String} id (optional) A new record id if you don't want to use this record's id
19661 copy : function(newId) {
19662 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19666 * Ext JS Library 1.1.1
19667 * Copyright(c) 2006-2007, Ext JS, LLC.
19669 * Originally Released Under LGPL - original licence link has changed is not relivant.
19672 * <script type="text/javascript">
19678 * @class Roo.data.Store
19679 * @extends Roo.util.Observable
19680 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19681 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19683 * 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
19684 * has no knowledge of the format of the data returned by the Proxy.<br>
19686 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19687 * instances from the data object. These records are cached and made available through accessor functions.
19689 * Creates a new Store.
19690 * @param {Object} config A config object containing the objects needed for the Store to access data,
19691 * and read the data into Records.
19693 Roo.data.Store = function(config){
19694 this.data = new Roo.util.MixedCollection(false);
19695 this.data.getKey = function(o){
19698 this.baseParams = {};
19700 this.paramNames = {
19705 "multisort" : "_multisort"
19708 if(config && config.data){
19709 this.inlineData = config.data;
19710 delete config.data;
19713 Roo.apply(this, config);
19715 if(this.reader){ // reader passed
19716 this.reader = Roo.factory(this.reader, Roo.data);
19717 this.reader.xmodule = this.xmodule || false;
19718 if(!this.recordType){
19719 this.recordType = this.reader.recordType;
19721 if(this.reader.onMetaChange){
19722 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19726 if(this.recordType){
19727 this.fields = this.recordType.prototype.fields;
19729 this.modified = [];
19733 * @event datachanged
19734 * Fires when the data cache has changed, and a widget which is using this Store
19735 * as a Record cache should refresh its view.
19736 * @param {Store} this
19738 datachanged : true,
19740 * @event metachange
19741 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19742 * @param {Store} this
19743 * @param {Object} meta The JSON metadata
19748 * Fires when Records have been added to the Store
19749 * @param {Store} this
19750 * @param {Roo.data.Record[]} records The array of Records added
19751 * @param {Number} index The index at which the record(s) were added
19756 * Fires when a Record has been removed from the Store
19757 * @param {Store} this
19758 * @param {Roo.data.Record} record The Record that was removed
19759 * @param {Number} index The index at which the record was removed
19764 * Fires when a Record has been updated
19765 * @param {Store} this
19766 * @param {Roo.data.Record} record The Record that was updated
19767 * @param {String} operation The update operation being performed. Value may be one of:
19769 Roo.data.Record.EDIT
19770 Roo.data.Record.REJECT
19771 Roo.data.Record.COMMIT
19777 * Fires when the data cache has been cleared.
19778 * @param {Store} this
19782 * @event beforeload
19783 * Fires before a request is made for a new data object. If the beforeload handler returns false
19784 * the load action will be canceled.
19785 * @param {Store} this
19786 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19790 * @event beforeloadadd
19791 * Fires after a new set of Records has been loaded.
19792 * @param {Store} this
19793 * @param {Roo.data.Record[]} records The Records that were loaded
19794 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19796 beforeloadadd : true,
19799 * Fires after a new set of Records has been loaded, before they are added to the store.
19800 * @param {Store} this
19801 * @param {Roo.data.Record[]} records The Records that were loaded
19802 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19803 * @params {Object} return from reader
19807 * @event loadexception
19808 * Fires if an exception occurs in the Proxy during loading.
19809 * Called with the signature of the Proxy's "loadexception" event.
19810 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19813 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19814 * @param {Object} load options
19815 * @param {Object} jsonData from your request (normally this contains the Exception)
19817 loadexception : true
19821 this.proxy = Roo.factory(this.proxy, Roo.data);
19822 this.proxy.xmodule = this.xmodule || false;
19823 this.relayEvents(this.proxy, ["loadexception"]);
19825 this.sortToggle = {};
19826 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19828 Roo.data.Store.superclass.constructor.call(this);
19830 if(this.inlineData){
19831 this.loadData(this.inlineData);
19832 delete this.inlineData;
19836 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19838 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19839 * without a remote query - used by combo/forms at present.
19843 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19846 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19849 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19850 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19853 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19854 * on any HTTP request
19857 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19860 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19864 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19865 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19867 remoteSort : false,
19870 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19871 * loaded or when a record is removed. (defaults to false).
19873 pruneModifiedRecords : false,
19876 lastOptions : null,
19879 * Add Records to the Store and fires the add event.
19880 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19882 add : function(records){
19883 records = [].concat(records);
19884 for(var i = 0, len = records.length; i < len; i++){
19885 records[i].join(this);
19887 var index = this.data.length;
19888 this.data.addAll(records);
19889 this.fireEvent("add", this, records, index);
19893 * Remove a Record from the Store and fires the remove event.
19894 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19896 remove : function(record){
19897 var index = this.data.indexOf(record);
19898 this.data.removeAt(index);
19899 if(this.pruneModifiedRecords){
19900 this.modified.remove(record);
19902 this.fireEvent("remove", this, record, index);
19906 * Remove all Records from the Store and fires the clear event.
19908 removeAll : function(){
19910 if(this.pruneModifiedRecords){
19911 this.modified = [];
19913 this.fireEvent("clear", this);
19917 * Inserts Records to the Store at the given index and fires the add event.
19918 * @param {Number} index The start index at which to insert the passed Records.
19919 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19921 insert : function(index, records){
19922 records = [].concat(records);
19923 for(var i = 0, len = records.length; i < len; i++){
19924 this.data.insert(index, records[i]);
19925 records[i].join(this);
19927 this.fireEvent("add", this, records, index);
19931 * Get the index within the cache of the passed Record.
19932 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19933 * @return {Number} The index of the passed Record. Returns -1 if not found.
19935 indexOf : function(record){
19936 return this.data.indexOf(record);
19940 * Get the index within the cache of the Record with the passed id.
19941 * @param {String} id The id of the Record to find.
19942 * @return {Number} The index of the Record. Returns -1 if not found.
19944 indexOfId : function(id){
19945 return this.data.indexOfKey(id);
19949 * Get the Record with the specified id.
19950 * @param {String} id The id of the Record to find.
19951 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19953 getById : function(id){
19954 return this.data.key(id);
19958 * Get the Record at the specified index.
19959 * @param {Number} index The index of the Record to find.
19960 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19962 getAt : function(index){
19963 return this.data.itemAt(index);
19967 * Returns a range of Records between specified indices.
19968 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19969 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19970 * @return {Roo.data.Record[]} An array of Records
19972 getRange : function(start, end){
19973 return this.data.getRange(start, end);
19977 storeOptions : function(o){
19978 o = Roo.apply({}, o);
19981 this.lastOptions = o;
19985 * Loads the Record cache from the configured Proxy using the configured Reader.
19987 * If using remote paging, then the first load call must specify the <em>start</em>
19988 * and <em>limit</em> properties in the options.params property to establish the initial
19989 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19991 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19992 * and this call will return before the new data has been loaded. Perform any post-processing
19993 * in a callback function, or in a "load" event handler.</strong>
19995 * @param {Object} options An object containing properties which control loading options:<ul>
19996 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19997 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19998 * passed the following arguments:<ul>
19999 * <li>r : Roo.data.Record[]</li>
20000 * <li>options: Options object from the load call</li>
20001 * <li>success: Boolean success indicator</li></ul></li>
20002 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
20003 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
20006 load : function(options){
20007 options = options || {};
20008 if(this.fireEvent("beforeload", this, options) !== false){
20009 this.storeOptions(options);
20010 var p = Roo.apply(options.params || {}, this.baseParams);
20011 // if meta was not loaded from remote source.. try requesting it.
20012 if (!this.reader.metaFromRemote) {
20013 p._requestMeta = 1;
20015 if(this.sortInfo && this.remoteSort){
20016 var pn = this.paramNames;
20017 p[pn["sort"]] = this.sortInfo.field;
20018 p[pn["dir"]] = this.sortInfo.direction;
20020 if (this.multiSort) {
20021 var pn = this.paramNames;
20022 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
20025 this.proxy.load(p, this.reader, this.loadRecords, this, options);
20030 * Reloads the Record cache from the configured Proxy using the configured Reader and
20031 * the options from the last load operation performed.
20032 * @param {Object} options (optional) An object containing properties which may override the options
20033 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
20034 * the most recently used options are reused).
20036 reload : function(options){
20037 this.load(Roo.applyIf(options||{}, this.lastOptions));
20041 // Called as a callback by the Reader during a load operation.
20042 loadRecords : function(o, options, success){
20043 if(!o || success === false){
20044 if(success !== false){
20045 this.fireEvent("load", this, [], options, o);
20047 if(options.callback){
20048 options.callback.call(options.scope || this, [], options, false);
20052 // if data returned failure - throw an exception.
20053 if (o.success === false) {
20054 // show a message if no listener is registered.
20055 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
20056 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
20058 // loadmask wil be hooked into this..
20059 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
20062 var r = o.records, t = o.totalRecords || r.length;
20064 this.fireEvent("beforeloadadd", this, r, options, o);
20066 if(!options || options.add !== true){
20067 if(this.pruneModifiedRecords){
20068 this.modified = [];
20070 for(var i = 0, len = r.length; i < len; i++){
20074 this.data = this.snapshot;
20075 delete this.snapshot;
20078 this.data.addAll(r);
20079 this.totalLength = t;
20081 this.fireEvent("datachanged", this);
20083 this.totalLength = Math.max(t, this.data.length+r.length);
20086 this.fireEvent("load", this, r, options, o);
20087 if(options.callback){
20088 options.callback.call(options.scope || this, r, options, true);
20094 * Loads data from a passed data block. A Reader which understands the format of the data
20095 * must have been configured in the constructor.
20096 * @param {Object} data The data block from which to read the Records. The format of the data expected
20097 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
20098 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
20100 loadData : function(o, append){
20101 var r = this.reader.readRecords(o);
20102 this.loadRecords(r, {add: append}, true);
20106 * Gets the number of cached records.
20108 * <em>If using paging, this may not be the total size of the dataset. If the data object
20109 * used by the Reader contains the dataset size, then the getTotalCount() function returns
20110 * the data set size</em>
20112 getCount : function(){
20113 return this.data.length || 0;
20117 * Gets the total number of records in the dataset as returned by the server.
20119 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
20120 * the dataset size</em>
20122 getTotalCount : function(){
20123 return this.totalLength || 0;
20127 * Returns the sort state of the Store as an object with two properties:
20129 field {String} The name of the field by which the Records are sorted
20130 direction {String} The sort order, "ASC" or "DESC"
20133 getSortState : function(){
20134 return this.sortInfo;
20138 applySort : function(){
20139 if(this.sortInfo && !this.remoteSort){
20140 var s = this.sortInfo, f = s.field;
20141 var st = this.fields.get(f).sortType;
20142 var fn = function(r1, r2){
20143 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
20144 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
20146 this.data.sort(s.direction, fn);
20147 if(this.snapshot && this.snapshot != this.data){
20148 this.snapshot.sort(s.direction, fn);
20154 * Sets the default sort column and order to be used by the next load operation.
20155 * @param {String} fieldName The name of the field to sort by.
20156 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20158 setDefaultSort : function(field, dir){
20159 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
20163 * Sort the Records.
20164 * If remote sorting is used, the sort is performed on the server, and the cache is
20165 * reloaded. If local sorting is used, the cache is sorted internally.
20166 * @param {String} fieldName The name of the field to sort by.
20167 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20169 sort : function(fieldName, dir){
20170 var f = this.fields.get(fieldName);
20172 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
20174 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
20175 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
20180 this.sortToggle[f.name] = dir;
20181 this.sortInfo = {field: f.name, direction: dir};
20182 if(!this.remoteSort){
20184 this.fireEvent("datachanged", this);
20186 this.load(this.lastOptions);
20191 * Calls the specified function for each of the Records in the cache.
20192 * @param {Function} fn The function to call. The Record is passed as the first parameter.
20193 * Returning <em>false</em> aborts and exits the iteration.
20194 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
20196 each : function(fn, scope){
20197 this.data.each(fn, scope);
20201 * Gets all records modified since the last commit. Modified records are persisted across load operations
20202 * (e.g., during paging).
20203 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
20205 getModifiedRecords : function(){
20206 return this.modified;
20210 createFilterFn : function(property, value, anyMatch){
20211 if(!value.exec){ // not a regex
20212 value = String(value);
20213 if(value.length == 0){
20216 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
20218 return function(r){
20219 return value.test(r.data[property]);
20224 * Sums the value of <i>property</i> for each record between start and end and returns the result.
20225 * @param {String} property A field on your records
20226 * @param {Number} start The record index to start at (defaults to 0)
20227 * @param {Number} end The last record index to include (defaults to length - 1)
20228 * @return {Number} The sum
20230 sum : function(property, start, end){
20231 var rs = this.data.items, v = 0;
20232 start = start || 0;
20233 end = (end || end === 0) ? end : rs.length-1;
20235 for(var i = start; i <= end; i++){
20236 v += (rs[i].data[property] || 0);
20242 * Filter the records by a specified property.
20243 * @param {String} field A field on your records
20244 * @param {String/RegExp} value Either a string that the field
20245 * should start with or a RegExp to test against the field
20246 * @param {Boolean} anyMatch True to match any part not just the beginning
20248 filter : function(property, value, anyMatch){
20249 var fn = this.createFilterFn(property, value, anyMatch);
20250 return fn ? this.filterBy(fn) : this.clearFilter();
20254 * Filter by a function. The specified function will be called with each
20255 * record in this data source. If the function returns true the record is included,
20256 * otherwise it is filtered.
20257 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20258 * @param {Object} scope (optional) The scope of the function (defaults to this)
20260 filterBy : function(fn, scope){
20261 this.snapshot = this.snapshot || this.data;
20262 this.data = this.queryBy(fn, scope||this);
20263 this.fireEvent("datachanged", this);
20267 * Query the records by a specified property.
20268 * @param {String} field A field on your records
20269 * @param {String/RegExp} value Either a string that the field
20270 * should start with or a RegExp to test against the field
20271 * @param {Boolean} anyMatch True to match any part not just the beginning
20272 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20274 query : function(property, value, anyMatch){
20275 var fn = this.createFilterFn(property, value, anyMatch);
20276 return fn ? this.queryBy(fn) : this.data.clone();
20280 * Query by a function. The specified function will be called with each
20281 * record in this data source. If the function returns true the record is included
20283 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20284 * @param {Object} scope (optional) The scope of the function (defaults to this)
20285 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20287 queryBy : function(fn, scope){
20288 var data = this.snapshot || this.data;
20289 return data.filterBy(fn, scope||this);
20293 * Collects unique values for a particular dataIndex from this store.
20294 * @param {String} dataIndex The property to collect
20295 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
20296 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
20297 * @return {Array} An array of the unique values
20299 collect : function(dataIndex, allowNull, bypassFilter){
20300 var d = (bypassFilter === true && this.snapshot) ?
20301 this.snapshot.items : this.data.items;
20302 var v, sv, r = [], l = {};
20303 for(var i = 0, len = d.length; i < len; i++){
20304 v = d[i].data[dataIndex];
20306 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
20315 * Revert to a view of the Record cache with no filtering applied.
20316 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
20318 clearFilter : function(suppressEvent){
20319 if(this.snapshot && this.snapshot != this.data){
20320 this.data = this.snapshot;
20321 delete this.snapshot;
20322 if(suppressEvent !== true){
20323 this.fireEvent("datachanged", this);
20329 afterEdit : function(record){
20330 if(this.modified.indexOf(record) == -1){
20331 this.modified.push(record);
20333 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
20337 afterReject : function(record){
20338 this.modified.remove(record);
20339 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
20343 afterCommit : function(record){
20344 this.modified.remove(record);
20345 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
20349 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
20350 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
20352 commitChanges : function(){
20353 var m = this.modified.slice(0);
20354 this.modified = [];
20355 for(var i = 0, len = m.length; i < len; i++){
20361 * Cancel outstanding changes on all changed records.
20363 rejectChanges : function(){
20364 var m = this.modified.slice(0);
20365 this.modified = [];
20366 for(var i = 0, len = m.length; i < len; i++){
20371 onMetaChange : function(meta, rtype, o){
20372 this.recordType = rtype;
20373 this.fields = rtype.prototype.fields;
20374 delete this.snapshot;
20375 this.sortInfo = meta.sortInfo || this.sortInfo;
20376 this.modified = [];
20377 this.fireEvent('metachange', this, this.reader.meta);
20381 * Ext JS Library 1.1.1
20382 * Copyright(c) 2006-2007, Ext JS, LLC.
20384 * Originally Released Under LGPL - original licence link has changed is not relivant.
20387 * <script type="text/javascript">
20391 * @class Roo.data.SimpleStore
20392 * @extends Roo.data.Store
20393 * Small helper class to make creating Stores from Array data easier.
20394 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
20395 * @cfg {Array} fields An array of field definition objects, or field name strings.
20396 * @cfg {Array} data The multi-dimensional array of data
20398 * @param {Object} config
20400 Roo.data.SimpleStore = function(config){
20401 Roo.data.SimpleStore.superclass.constructor.call(this, {
20403 reader: new Roo.data.ArrayReader({
20406 Roo.data.Record.create(config.fields)
20408 proxy : new Roo.data.MemoryProxy(config.data)
20412 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
20414 * Ext JS Library 1.1.1
20415 * Copyright(c) 2006-2007, Ext JS, LLC.
20417 * Originally Released Under LGPL - original licence link has changed is not relivant.
20420 * <script type="text/javascript">
20425 * @extends Roo.data.Store
20426 * @class Roo.data.JsonStore
20427 * Small helper class to make creating Stores for JSON data easier. <br/>
20429 var store = new Roo.data.JsonStore({
20430 url: 'get-images.php',
20432 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
20435 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
20436 * JsonReader and HttpProxy (unless inline data is provided).</b>
20437 * @cfg {Array} fields An array of field definition objects, or field name strings.
20439 * @param {Object} config
20441 Roo.data.JsonStore = function(c){
20442 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
20443 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
20444 reader: new Roo.data.JsonReader(c, c.fields)
20447 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
20449 * Ext JS Library 1.1.1
20450 * Copyright(c) 2006-2007, Ext JS, LLC.
20452 * Originally Released Under LGPL - original licence link has changed is not relivant.
20455 * <script type="text/javascript">
20459 Roo.data.Field = function(config){
20460 if(typeof config == "string"){
20461 config = {name: config};
20463 Roo.apply(this, config);
20466 this.type = "auto";
20469 var st = Roo.data.SortTypes;
20470 // named sortTypes are supported, here we look them up
20471 if(typeof this.sortType == "string"){
20472 this.sortType = st[this.sortType];
20475 // set default sortType for strings and dates
20476 if(!this.sortType){
20479 this.sortType = st.asUCString;
20482 this.sortType = st.asDate;
20485 this.sortType = st.none;
20490 var stripRe = /[\$,%]/g;
20492 // prebuilt conversion function for this field, instead of
20493 // switching every time we're reading a value
20495 var cv, dateFormat = this.dateFormat;
20500 cv = function(v){ return v; };
20503 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20507 return v !== undefined && v !== null && v !== '' ?
20508 parseInt(String(v).replace(stripRe, ""), 10) : '';
20513 return v !== undefined && v !== null && v !== '' ?
20514 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20519 cv = function(v){ return v === true || v === "true" || v == 1; };
20526 if(v instanceof Date){
20530 if(dateFormat == "timestamp"){
20531 return new Date(v*1000);
20533 return Date.parseDate(v, dateFormat);
20535 var parsed = Date.parse(v);
20536 return parsed ? new Date(parsed) : null;
20545 Roo.data.Field.prototype = {
20553 * Ext JS Library 1.1.1
20554 * Copyright(c) 2006-2007, Ext JS, LLC.
20556 * Originally Released Under LGPL - original licence link has changed is not relivant.
20559 * <script type="text/javascript">
20562 // Base class for reading structured data from a data source. This class is intended to be
20563 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20566 * @class Roo.data.DataReader
20567 * Base class for reading structured data from a data source. This class is intended to be
20568 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20571 Roo.data.DataReader = function(meta, recordType){
20575 this.recordType = recordType instanceof Array ?
20576 Roo.data.Record.create(recordType) : recordType;
20579 Roo.data.DataReader.prototype = {
20581 * Create an empty record
20582 * @param {Object} data (optional) - overlay some values
20583 * @return {Roo.data.Record} record created.
20585 newRow : function(d) {
20587 this.recordType.prototype.fields.each(function(c) {
20589 case 'int' : da[c.name] = 0; break;
20590 case 'date' : da[c.name] = new Date(); break;
20591 case 'float' : da[c.name] = 0.0; break;
20592 case 'boolean' : da[c.name] = false; break;
20593 default : da[c.name] = ""; break;
20597 return new this.recordType(Roo.apply(da, d));
20602 * Ext JS Library 1.1.1
20603 * Copyright(c) 2006-2007, Ext JS, LLC.
20605 * Originally Released Under LGPL - original licence link has changed is not relivant.
20608 * <script type="text/javascript">
20612 * @class Roo.data.DataProxy
20613 * @extends Roo.data.Observable
20614 * This class is an abstract base class for implementations which provide retrieval of
20615 * unformatted data objects.<br>
20617 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20618 * (of the appropriate type which knows how to parse the data object) to provide a block of
20619 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20621 * Custom implementations must implement the load method as described in
20622 * {@link Roo.data.HttpProxy#load}.
20624 Roo.data.DataProxy = function(){
20627 * @event beforeload
20628 * Fires before a network request is made to retrieve a data object.
20629 * @param {Object} This DataProxy object.
20630 * @param {Object} params The params parameter to the load function.
20635 * Fires before the load method's callback is called.
20636 * @param {Object} This DataProxy object.
20637 * @param {Object} o The data object.
20638 * @param {Object} arg The callback argument object passed to the load function.
20642 * @event loadexception
20643 * Fires if an Exception occurs during data retrieval.
20644 * @param {Object} This DataProxy object.
20645 * @param {Object} o The data object.
20646 * @param {Object} arg The callback argument object passed to the load function.
20647 * @param {Object} e The Exception.
20649 loadexception : true
20651 Roo.data.DataProxy.superclass.constructor.call(this);
20654 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20657 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20661 * Ext JS Library 1.1.1
20662 * Copyright(c) 2006-2007, Ext JS, LLC.
20664 * Originally Released Under LGPL - original licence link has changed is not relivant.
20667 * <script type="text/javascript">
20670 * @class Roo.data.MemoryProxy
20671 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20672 * to the Reader when its load method is called.
20674 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20676 Roo.data.MemoryProxy = function(data){
20680 Roo.data.MemoryProxy.superclass.constructor.call(this);
20684 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20686 * Load data from the requested source (in this case an in-memory
20687 * data object passed to the constructor), read the data object into
20688 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20689 * process that block using the passed callback.
20690 * @param {Object} params This parameter is not used by the MemoryProxy class.
20691 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20692 * object into a block of Roo.data.Records.
20693 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20694 * The function must be passed <ul>
20695 * <li>The Record block object</li>
20696 * <li>The "arg" argument from the load function</li>
20697 * <li>A boolean success indicator</li>
20699 * @param {Object} scope The scope in which to call the callback
20700 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20702 load : function(params, reader, callback, scope, arg){
20703 params = params || {};
20706 result = reader.readRecords(this.data);
20708 this.fireEvent("loadexception", this, arg, null, e);
20709 callback.call(scope, null, arg, false);
20712 callback.call(scope, result, arg, true);
20716 update : function(params, records){
20721 * Ext JS Library 1.1.1
20722 * Copyright(c) 2006-2007, Ext JS, LLC.
20724 * Originally Released Under LGPL - original licence link has changed is not relivant.
20727 * <script type="text/javascript">
20730 * @class Roo.data.HttpProxy
20731 * @extends Roo.data.DataProxy
20732 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20733 * configured to reference a certain URL.<br><br>
20735 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20736 * from which the running page was served.<br><br>
20738 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20740 * Be aware that to enable the browser to parse an XML document, the server must set
20741 * the Content-Type header in the HTTP response to "text/xml".
20743 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20744 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20745 * will be used to make the request.
20747 Roo.data.HttpProxy = function(conn){
20748 Roo.data.HttpProxy.superclass.constructor.call(this);
20749 // is conn a conn config or a real conn?
20751 this.useAjax = !conn || !conn.events;
20755 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20756 // thse are take from connection...
20759 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20762 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20763 * extra parameters to each request made by this object. (defaults to undefined)
20766 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20767 * to each request made by this object. (defaults to undefined)
20770 * @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)
20773 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20776 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20782 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20786 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20787 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20788 * a finer-grained basis than the DataProxy events.
20790 getConnection : function(){
20791 return this.useAjax ? Roo.Ajax : this.conn;
20795 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20796 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20797 * process that block using the passed callback.
20798 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20799 * for the request to the remote server.
20800 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20801 * object into a block of Roo.data.Records.
20802 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20803 * The function must be passed <ul>
20804 * <li>The Record block object</li>
20805 * <li>The "arg" argument from the load function</li>
20806 * <li>A boolean success indicator</li>
20808 * @param {Object} scope The scope in which to call the callback
20809 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20811 load : function(params, reader, callback, scope, arg){
20812 if(this.fireEvent("beforeload", this, params) !== false){
20814 params : params || {},
20816 callback : callback,
20821 callback : this.loadResponse,
20825 Roo.applyIf(o, this.conn);
20826 if(this.activeRequest){
20827 Roo.Ajax.abort(this.activeRequest);
20829 this.activeRequest = Roo.Ajax.request(o);
20831 this.conn.request(o);
20834 callback.call(scope||this, null, arg, false);
20839 loadResponse : function(o, success, response){
20840 delete this.activeRequest;
20842 this.fireEvent("loadexception", this, o, response);
20843 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20848 result = o.reader.read(response);
20850 this.fireEvent("loadexception", this, o, response, e);
20851 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20855 this.fireEvent("load", this, o, o.request.arg);
20856 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20860 update : function(dataSet){
20865 updateResponse : function(dataSet){
20870 * Ext JS Library 1.1.1
20871 * Copyright(c) 2006-2007, Ext JS, LLC.
20873 * Originally Released Under LGPL - original licence link has changed is not relivant.
20876 * <script type="text/javascript">
20880 * @class Roo.data.ScriptTagProxy
20881 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20882 * other than the originating domain of the running page.<br><br>
20884 * <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
20885 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20887 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20888 * source code that is used as the source inside a <script> tag.<br><br>
20890 * In order for the browser to process the returned data, the server must wrap the data object
20891 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20892 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20893 * depending on whether the callback name was passed:
20896 boolean scriptTag = false;
20897 String cb = request.getParameter("callback");
20900 response.setContentType("text/javascript");
20902 response.setContentType("application/x-json");
20904 Writer out = response.getWriter();
20906 out.write(cb + "(");
20908 out.print(dataBlock.toJsonString());
20915 * @param {Object} config A configuration object.
20917 Roo.data.ScriptTagProxy = function(config){
20918 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20919 Roo.apply(this, config);
20920 this.head = document.getElementsByTagName("head")[0];
20923 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20925 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20927 * @cfg {String} url The URL from which to request the data object.
20930 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20934 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20935 * the server the name of the callback function set up by the load call to process the returned data object.
20936 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20937 * javascript output which calls this named function passing the data object as its only parameter.
20939 callbackParam : "callback",
20941 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20942 * name to the request.
20947 * Load data from the configured URL, read the data object into
20948 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20949 * process that block using the passed callback.
20950 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20951 * for the request to the remote server.
20952 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20953 * object into a block of Roo.data.Records.
20954 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20955 * The function must be passed <ul>
20956 * <li>The Record block object</li>
20957 * <li>The "arg" argument from the load function</li>
20958 * <li>A boolean success indicator</li>
20960 * @param {Object} scope The scope in which to call the callback
20961 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20963 load : function(params, reader, callback, scope, arg){
20964 if(this.fireEvent("beforeload", this, params) !== false){
20966 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20968 var url = this.url;
20969 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20971 url += "&_dc=" + (new Date().getTime());
20973 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20976 cb : "stcCallback"+transId,
20977 scriptId : "stcScript"+transId,
20981 callback : callback,
20987 window[trans.cb] = function(o){
20988 conn.handleResponse(o, trans);
20991 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20993 if(this.autoAbort !== false){
20997 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20999 var script = document.createElement("script");
21000 script.setAttribute("src", url);
21001 script.setAttribute("type", "text/javascript");
21002 script.setAttribute("id", trans.scriptId);
21003 this.head.appendChild(script);
21005 this.trans = trans;
21007 callback.call(scope||this, null, arg, false);
21012 isLoading : function(){
21013 return this.trans ? true : false;
21017 * Abort the current server request.
21019 abort : function(){
21020 if(this.isLoading()){
21021 this.destroyTrans(this.trans);
21026 destroyTrans : function(trans, isLoaded){
21027 this.head.removeChild(document.getElementById(trans.scriptId));
21028 clearTimeout(trans.timeoutId);
21030 window[trans.cb] = undefined;
21032 delete window[trans.cb];
21035 // if hasn't been loaded, wait for load to remove it to prevent script error
21036 window[trans.cb] = function(){
21037 window[trans.cb] = undefined;
21039 delete window[trans.cb];
21046 handleResponse : function(o, trans){
21047 this.trans = false;
21048 this.destroyTrans(trans, true);
21051 result = trans.reader.readRecords(o);
21053 this.fireEvent("loadexception", this, o, trans.arg, e);
21054 trans.callback.call(trans.scope||window, null, trans.arg, false);
21057 this.fireEvent("load", this, o, trans.arg);
21058 trans.callback.call(trans.scope||window, result, trans.arg, true);
21062 handleFailure : function(trans){
21063 this.trans = false;
21064 this.destroyTrans(trans, false);
21065 this.fireEvent("loadexception", this, null, trans.arg);
21066 trans.callback.call(trans.scope||window, null, trans.arg, false);
21070 * Ext JS Library 1.1.1
21071 * Copyright(c) 2006-2007, Ext JS, LLC.
21073 * Originally Released Under LGPL - original licence link has changed is not relivant.
21076 * <script type="text/javascript">
21080 * @class Roo.data.JsonReader
21081 * @extends Roo.data.DataReader
21082 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
21083 * based on mappings in a provided Roo.data.Record constructor.
21085 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
21086 * in the reply previously.
21091 var RecordDef = Roo.data.Record.create([
21092 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21093 {name: 'occupation'} // This field will use "occupation" as the mapping.
21095 var myReader = new Roo.data.JsonReader({
21096 totalProperty: "results", // The property which contains the total dataset size (optional)
21097 root: "rows", // The property which contains an Array of row objects
21098 id: "id" // The property within each row object that provides an ID for the record (optional)
21102 * This would consume a JSON file like this:
21104 { 'results': 2, 'rows': [
21105 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
21106 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
21109 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
21110 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21111 * paged from the remote server.
21112 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
21113 * @cfg {String} root name of the property which contains the Array of row objects.
21114 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
21116 * Create a new JsonReader
21117 * @param {Object} meta Metadata configuration options
21118 * @param {Object} recordType Either an Array of field definition objects,
21119 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
21121 Roo.data.JsonReader = function(meta, recordType){
21124 // set some defaults:
21125 Roo.applyIf(meta, {
21126 totalProperty: 'total',
21127 successProperty : 'success',
21132 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21134 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
21137 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
21138 * Used by Store query builder to append _requestMeta to params.
21141 metaFromRemote : false,
21143 * This method is only used by a DataProxy which has retrieved data from a remote server.
21144 * @param {Object} response The XHR object which contains the JSON data in its responseText.
21145 * @return {Object} data A data block which is used by an Roo.data.Store object as
21146 * a cache of Roo.data.Records.
21148 read : function(response){
21149 var json = response.responseText;
21151 var o = /* eval:var:o */ eval("("+json+")");
21153 throw {message: "JsonReader.read: Json object not found"};
21159 this.metaFromRemote = true;
21160 this.meta = o.metaData;
21161 this.recordType = Roo.data.Record.create(o.metaData.fields);
21162 this.onMetaChange(this.meta, this.recordType, o);
21164 return this.readRecords(o);
21167 // private function a store will implement
21168 onMetaChange : function(meta, recordType, o){
21175 simpleAccess: function(obj, subsc) {
21182 getJsonAccessor: function(){
21184 return function(expr) {
21186 return(re.test(expr))
21187 ? new Function("obj", "return obj." + expr)
21192 return Roo.emptyFn;
21197 * Create a data block containing Roo.data.Records from an XML document.
21198 * @param {Object} o An object which contains an Array of row objects in the property specified
21199 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
21200 * which contains the total size of the dataset.
21201 * @return {Object} data A data block which is used by an Roo.data.Store object as
21202 * a cache of Roo.data.Records.
21204 readRecords : function(o){
21206 * After any data loads, the raw JSON data is available for further custom processing.
21210 var s = this.meta, Record = this.recordType,
21211 f = Record.prototype.fields, fi = f.items, fl = f.length;
21213 // Generate extraction functions for the totalProperty, the root, the id, and for each field
21215 if(s.totalProperty) {
21216 this.getTotal = this.getJsonAccessor(s.totalProperty);
21218 if(s.successProperty) {
21219 this.getSuccess = this.getJsonAccessor(s.successProperty);
21221 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
21223 var g = this.getJsonAccessor(s.id);
21224 this.getId = function(rec) {
21226 return (r === undefined || r === "") ? null : r;
21229 this.getId = function(){return null;};
21232 for(var jj = 0; jj < fl; jj++){
21234 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
21235 this.ef[jj] = this.getJsonAccessor(map);
21239 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
21240 if(s.totalProperty){
21241 var vt = parseInt(this.getTotal(o), 10);
21246 if(s.successProperty){
21247 var vs = this.getSuccess(o);
21248 if(vs === false || vs === 'false'){
21253 for(var i = 0; i < c; i++){
21256 var id = this.getId(n);
21257 for(var j = 0; j < fl; j++){
21259 var v = this.ef[j](n);
21261 Roo.log('missing convert for ' + f.name);
21265 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
21267 var record = new Record(values, id);
21269 records[i] = record;
21275 totalRecords : totalRecords
21280 * Ext JS Library 1.1.1
21281 * Copyright(c) 2006-2007, Ext JS, LLC.
21283 * Originally Released Under LGPL - original licence link has changed is not relivant.
21286 * <script type="text/javascript">
21290 * @class Roo.data.XmlReader
21291 * @extends Roo.data.DataReader
21292 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
21293 * based on mappings in a provided Roo.data.Record constructor.<br><br>
21295 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
21296 * header in the HTTP response must be set to "text/xml".</em>
21300 var RecordDef = Roo.data.Record.create([
21301 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21302 {name: 'occupation'} // This field will use "occupation" as the mapping.
21304 var myReader = new Roo.data.XmlReader({
21305 totalRecords: "results", // The element which contains the total dataset size (optional)
21306 record: "row", // The repeated element which contains row information
21307 id: "id" // The element within the row that provides an ID for the record (optional)
21311 * This would consume an XML file like this:
21315 <results>2</results>
21318 <name>Bill</name>
21319 <occupation>Gardener</occupation>
21323 <name>Ben</name>
21324 <occupation>Horticulturalist</occupation>
21328 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
21329 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21330 * paged from the remote server.
21331 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
21332 * @cfg {String} success The DomQuery path to the success attribute used by forms.
21333 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
21334 * a record identifier value.
21336 * Create a new XmlReader
21337 * @param {Object} meta Metadata configuration options
21338 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
21339 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
21340 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
21342 Roo.data.XmlReader = function(meta, recordType){
21344 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21346 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
21348 * This method is only used by a DataProxy which has retrieved data from a remote server.
21349 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
21350 * to contain a method called 'responseXML' that returns an XML document object.
21351 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21352 * a cache of Roo.data.Records.
21354 read : function(response){
21355 var doc = response.responseXML;
21357 throw {message: "XmlReader.read: XML Document not available"};
21359 return this.readRecords(doc);
21363 * Create a data block containing Roo.data.Records from an XML document.
21364 * @param {Object} doc A parsed XML document.
21365 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21366 * a cache of Roo.data.Records.
21368 readRecords : function(doc){
21370 * After any data loads/reads, the raw XML Document is available for further custom processing.
21371 * @type XMLDocument
21373 this.xmlData = doc;
21374 var root = doc.documentElement || doc;
21375 var q = Roo.DomQuery;
21376 var recordType = this.recordType, fields = recordType.prototype.fields;
21377 var sid = this.meta.id;
21378 var totalRecords = 0, success = true;
21379 if(this.meta.totalRecords){
21380 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
21383 if(this.meta.success){
21384 var sv = q.selectValue(this.meta.success, root, true);
21385 success = sv !== false && sv !== 'false';
21388 var ns = q.select(this.meta.record, root);
21389 for(var i = 0, len = ns.length; i < len; i++) {
21392 var id = sid ? q.selectValue(sid, n) : undefined;
21393 for(var j = 0, jlen = fields.length; j < jlen; j++){
21394 var f = fields.items[j];
21395 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
21397 values[f.name] = v;
21399 var record = new recordType(values, id);
21401 records[records.length] = record;
21407 totalRecords : totalRecords || records.length
21412 * Ext JS Library 1.1.1
21413 * Copyright(c) 2006-2007, Ext JS, LLC.
21415 * Originally Released Under LGPL - original licence link has changed is not relivant.
21418 * <script type="text/javascript">
21422 * @class Roo.data.ArrayReader
21423 * @extends Roo.data.DataReader
21424 * Data reader class to create an Array of Roo.data.Record objects from an Array.
21425 * Each element of that Array represents a row of data fields. The
21426 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
21427 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
21431 var RecordDef = Roo.data.Record.create([
21432 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
21433 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
21435 var myReader = new Roo.data.ArrayReader({
21436 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
21440 * This would consume an Array like this:
21442 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
21444 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
21446 * Create a new JsonReader
21447 * @param {Object} meta Metadata configuration options.
21448 * @param {Object} recordType Either an Array of field definition objects
21449 * as specified to {@link Roo.data.Record#create},
21450 * or an {@link Roo.data.Record} object
21451 * created using {@link Roo.data.Record#create}.
21453 Roo.data.ArrayReader = function(meta, recordType){
21454 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
21457 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
21459 * Create a data block containing Roo.data.Records from an XML document.
21460 * @param {Object} o An Array of row objects which represents the dataset.
21461 * @return {Object} data A data block which is used by an Roo.data.Store object as
21462 * a cache of Roo.data.Records.
21464 readRecords : function(o){
21465 var sid = this.meta ? this.meta.id : null;
21466 var recordType = this.recordType, fields = recordType.prototype.fields;
21469 for(var i = 0; i < root.length; i++){
21472 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
21473 for(var j = 0, jlen = fields.length; j < jlen; j++){
21474 var f = fields.items[j];
21475 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
21476 var v = n[k] !== undefined ? n[k] : f.defaultValue;
21478 values[f.name] = v;
21480 var record = new recordType(values, id);
21482 records[records.length] = record;
21486 totalRecords : records.length
21491 * Ext JS Library 1.1.1
21492 * Copyright(c) 2006-2007, Ext JS, LLC.
21494 * Originally Released Under LGPL - original licence link has changed is not relivant.
21497 * <script type="text/javascript">
21502 * @class Roo.data.Tree
21503 * @extends Roo.util.Observable
21504 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21505 * in the tree have most standard DOM functionality.
21507 * @param {Node} root (optional) The root node
21509 Roo.data.Tree = function(root){
21510 this.nodeHash = {};
21512 * The root node for this tree
21517 this.setRootNode(root);
21522 * Fires when a new child node is appended to a node in this tree.
21523 * @param {Tree} tree The owner tree
21524 * @param {Node} parent The parent node
21525 * @param {Node} node The newly appended node
21526 * @param {Number} index The index of the newly appended node
21531 * Fires when a child node is removed from a node in this tree.
21532 * @param {Tree} tree The owner tree
21533 * @param {Node} parent The parent node
21534 * @param {Node} node The child node removed
21539 * Fires when a node is moved to a new location in the tree
21540 * @param {Tree} tree The owner tree
21541 * @param {Node} node The node moved
21542 * @param {Node} oldParent The old parent of this node
21543 * @param {Node} newParent The new parent of this node
21544 * @param {Number} index The index it was moved to
21549 * Fires when a new child node is inserted in a node in this tree.
21550 * @param {Tree} tree The owner tree
21551 * @param {Node} parent The parent node
21552 * @param {Node} node The child node inserted
21553 * @param {Node} refNode The child node the node was inserted before
21557 * @event beforeappend
21558 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21559 * @param {Tree} tree The owner tree
21560 * @param {Node} parent The parent node
21561 * @param {Node} node The child node to be appended
21563 "beforeappend" : true,
21565 * @event beforeremove
21566 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21567 * @param {Tree} tree The owner tree
21568 * @param {Node} parent The parent node
21569 * @param {Node} node The child node to be removed
21571 "beforeremove" : true,
21573 * @event beforemove
21574 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21575 * @param {Tree} tree The owner tree
21576 * @param {Node} node The node being moved
21577 * @param {Node} oldParent The parent of the node
21578 * @param {Node} newParent The new parent the node is moving to
21579 * @param {Number} index The index it is being moved to
21581 "beforemove" : true,
21583 * @event beforeinsert
21584 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21585 * @param {Tree} tree The owner tree
21586 * @param {Node} parent The parent node
21587 * @param {Node} node The child node to be inserted
21588 * @param {Node} refNode The child node the node is being inserted before
21590 "beforeinsert" : true
21593 Roo.data.Tree.superclass.constructor.call(this);
21596 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21597 pathSeparator: "/",
21599 proxyNodeEvent : function(){
21600 return this.fireEvent.apply(this, arguments);
21604 * Returns the root node for this tree.
21607 getRootNode : function(){
21612 * Sets the root node for this tree.
21613 * @param {Node} node
21616 setRootNode : function(node){
21618 node.ownerTree = this;
21619 node.isRoot = true;
21620 this.registerNode(node);
21625 * Gets a node in this tree by its id.
21626 * @param {String} id
21629 getNodeById : function(id){
21630 return this.nodeHash[id];
21633 registerNode : function(node){
21634 this.nodeHash[node.id] = node;
21637 unregisterNode : function(node){
21638 delete this.nodeHash[node.id];
21641 toString : function(){
21642 return "[Tree"+(this.id?" "+this.id:"")+"]";
21647 * @class Roo.data.Node
21648 * @extends Roo.util.Observable
21649 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21650 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21652 * @param {Object} attributes The attributes/config for the node
21654 Roo.data.Node = function(attributes){
21656 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21659 this.attributes = attributes || {};
21660 this.leaf = this.attributes.leaf;
21662 * The node id. @type String
21664 this.id = this.attributes.id;
21666 this.id = Roo.id(null, "ynode-");
21667 this.attributes.id = this.id;
21672 * All child nodes of this node. @type Array
21674 this.childNodes = [];
21675 if(!this.childNodes.indexOf){ // indexOf is a must
21676 this.childNodes.indexOf = function(o){
21677 for(var i = 0, len = this.length; i < len; i++){
21686 * The parent node for this node. @type Node
21688 this.parentNode = null;
21690 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21692 this.firstChild = null;
21694 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21696 this.lastChild = null;
21698 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21700 this.previousSibling = null;
21702 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21704 this.nextSibling = null;
21709 * Fires when a new child node is appended
21710 * @param {Tree} tree The owner tree
21711 * @param {Node} this This node
21712 * @param {Node} node The newly appended node
21713 * @param {Number} index The index of the newly appended node
21718 * Fires when a child node is removed
21719 * @param {Tree} tree The owner tree
21720 * @param {Node} this This node
21721 * @param {Node} node The removed node
21726 * Fires when this node is moved to a new location in the tree
21727 * @param {Tree} tree The owner tree
21728 * @param {Node} this This node
21729 * @param {Node} oldParent The old parent of this node
21730 * @param {Node} newParent The new parent of this node
21731 * @param {Number} index The index it was moved to
21736 * Fires when a new child node is inserted.
21737 * @param {Tree} tree The owner tree
21738 * @param {Node} this This node
21739 * @param {Node} node The child node inserted
21740 * @param {Node} refNode The child node the node was inserted before
21744 * @event beforeappend
21745 * Fires before a new child is appended, return false to cancel the append.
21746 * @param {Tree} tree The owner tree
21747 * @param {Node} this This node
21748 * @param {Node} node The child node to be appended
21750 "beforeappend" : true,
21752 * @event beforeremove
21753 * Fires before a child is removed, return false to cancel the remove.
21754 * @param {Tree} tree The owner tree
21755 * @param {Node} this This node
21756 * @param {Node} node The child node to be removed
21758 "beforeremove" : true,
21760 * @event beforemove
21761 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21762 * @param {Tree} tree The owner tree
21763 * @param {Node} this This node
21764 * @param {Node} oldParent The parent of this node
21765 * @param {Node} newParent The new parent this node is moving to
21766 * @param {Number} index The index it is being moved to
21768 "beforemove" : true,
21770 * @event beforeinsert
21771 * Fires before a new child is inserted, return false to cancel the insert.
21772 * @param {Tree} tree The owner tree
21773 * @param {Node} this This node
21774 * @param {Node} node The child node to be inserted
21775 * @param {Node} refNode The child node the node is being inserted before
21777 "beforeinsert" : true
21779 this.listeners = this.attributes.listeners;
21780 Roo.data.Node.superclass.constructor.call(this);
21783 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21784 fireEvent : function(evtName){
21785 // first do standard event for this node
21786 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21789 // then bubble it up to the tree if the event wasn't cancelled
21790 var ot = this.getOwnerTree();
21792 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21800 * Returns true if this node is a leaf
21801 * @return {Boolean}
21803 isLeaf : function(){
21804 return this.leaf === true;
21808 setFirstChild : function(node){
21809 this.firstChild = node;
21813 setLastChild : function(node){
21814 this.lastChild = node;
21819 * Returns true if this node is the last child of its parent
21820 * @return {Boolean}
21822 isLast : function(){
21823 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21827 * Returns true if this node is the first child of its parent
21828 * @return {Boolean}
21830 isFirst : function(){
21831 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21834 hasChildNodes : function(){
21835 return !this.isLeaf() && this.childNodes.length > 0;
21839 * Insert node(s) as the last child node of this node.
21840 * @param {Node/Array} node The node or Array of nodes to append
21841 * @return {Node} The appended node if single append, or null if an array was passed
21843 appendChild : function(node){
21845 if(node instanceof Array){
21847 }else if(arguments.length > 1){
21850 // if passed an array or multiple args do them one by one
21852 for(var i = 0, len = multi.length; i < len; i++) {
21853 this.appendChild(multi[i]);
21856 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21859 var index = this.childNodes.length;
21860 var oldParent = node.parentNode;
21861 // it's a move, make sure we move it cleanly
21863 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21866 oldParent.removeChild(node);
21868 index = this.childNodes.length;
21870 this.setFirstChild(node);
21872 this.childNodes.push(node);
21873 node.parentNode = this;
21874 var ps = this.childNodes[index-1];
21876 node.previousSibling = ps;
21877 ps.nextSibling = node;
21879 node.previousSibling = null;
21881 node.nextSibling = null;
21882 this.setLastChild(node);
21883 node.setOwnerTree(this.getOwnerTree());
21884 this.fireEvent("append", this.ownerTree, this, node, index);
21886 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21893 * Removes a child node from this node.
21894 * @param {Node} node The node to remove
21895 * @return {Node} The removed node
21897 removeChild : function(node){
21898 var index = this.childNodes.indexOf(node);
21902 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21906 // remove it from childNodes collection
21907 this.childNodes.splice(index, 1);
21910 if(node.previousSibling){
21911 node.previousSibling.nextSibling = node.nextSibling;
21913 if(node.nextSibling){
21914 node.nextSibling.previousSibling = node.previousSibling;
21917 // update child refs
21918 if(this.firstChild == node){
21919 this.setFirstChild(node.nextSibling);
21921 if(this.lastChild == node){
21922 this.setLastChild(node.previousSibling);
21925 node.setOwnerTree(null);
21926 // clear any references from the node
21927 node.parentNode = null;
21928 node.previousSibling = null;
21929 node.nextSibling = null;
21930 this.fireEvent("remove", this.ownerTree, this, node);
21935 * Inserts the first node before the second node in this nodes childNodes collection.
21936 * @param {Node} node The node to insert
21937 * @param {Node} refNode The node to insert before (if null the node is appended)
21938 * @return {Node} The inserted node
21940 insertBefore : function(node, refNode){
21941 if(!refNode){ // like standard Dom, refNode can be null for append
21942 return this.appendChild(node);
21945 if(node == refNode){
21949 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21952 var index = this.childNodes.indexOf(refNode);
21953 var oldParent = node.parentNode;
21954 var refIndex = index;
21956 // when moving internally, indexes will change after remove
21957 if(oldParent == this && this.childNodes.indexOf(node) < index){
21961 // it's a move, make sure we move it cleanly
21963 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21966 oldParent.removeChild(node);
21969 this.setFirstChild(node);
21971 this.childNodes.splice(refIndex, 0, node);
21972 node.parentNode = this;
21973 var ps = this.childNodes[refIndex-1];
21975 node.previousSibling = ps;
21976 ps.nextSibling = node;
21978 node.previousSibling = null;
21980 node.nextSibling = refNode;
21981 refNode.previousSibling = node;
21982 node.setOwnerTree(this.getOwnerTree());
21983 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21985 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21991 * Returns the child node at the specified index.
21992 * @param {Number} index
21995 item : function(index){
21996 return this.childNodes[index];
22000 * Replaces one child node in this node with another.
22001 * @param {Node} newChild The replacement node
22002 * @param {Node} oldChild The node to replace
22003 * @return {Node} The replaced node
22005 replaceChild : function(newChild, oldChild){
22006 this.insertBefore(newChild, oldChild);
22007 this.removeChild(oldChild);
22012 * Returns the index of a child node
22013 * @param {Node} node
22014 * @return {Number} The index of the node or -1 if it was not found
22016 indexOf : function(child){
22017 return this.childNodes.indexOf(child);
22021 * Returns the tree this node is in.
22024 getOwnerTree : function(){
22025 // if it doesn't have one, look for one
22026 if(!this.ownerTree){
22030 this.ownerTree = p.ownerTree;
22036 return this.ownerTree;
22040 * Returns depth of this node (the root node has a depth of 0)
22043 getDepth : function(){
22046 while(p.parentNode){
22054 setOwnerTree : function(tree){
22055 // if it's move, we need to update everyone
22056 if(tree != this.ownerTree){
22057 if(this.ownerTree){
22058 this.ownerTree.unregisterNode(this);
22060 this.ownerTree = tree;
22061 var cs = this.childNodes;
22062 for(var i = 0, len = cs.length; i < len; i++) {
22063 cs[i].setOwnerTree(tree);
22066 tree.registerNode(this);
22072 * Returns the path for this node. The path can be used to expand or select this node programmatically.
22073 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
22074 * @return {String} The path
22076 getPath : function(attr){
22077 attr = attr || "id";
22078 var p = this.parentNode;
22079 var b = [this.attributes[attr]];
22081 b.unshift(p.attributes[attr]);
22084 var sep = this.getOwnerTree().pathSeparator;
22085 return sep + b.join(sep);
22089 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22090 * function call will be the scope provided or the current node. The arguments to the function
22091 * will be the args provided or the current node. If the function returns false at any point,
22092 * the bubble is stopped.
22093 * @param {Function} fn The function to call
22094 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22095 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22097 bubble : function(fn, scope, args){
22100 if(fn.call(scope || p, args || p) === false){
22108 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22109 * function call will be the scope provided or the current node. The arguments to the function
22110 * will be the args provided or the current node. If the function returns false at any point,
22111 * the cascade is stopped on that branch.
22112 * @param {Function} fn The function to call
22113 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22114 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22116 cascade : function(fn, scope, args){
22117 if(fn.call(scope || this, args || this) !== false){
22118 var cs = this.childNodes;
22119 for(var i = 0, len = cs.length; i < len; i++) {
22120 cs[i].cascade(fn, scope, args);
22126 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
22127 * function call will be the scope provided or the current node. The arguments to the function
22128 * will be the args provided or the current node. If the function returns false at any point,
22129 * the iteration stops.
22130 * @param {Function} fn The function to call
22131 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22132 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22134 eachChild : function(fn, scope, args){
22135 var cs = this.childNodes;
22136 for(var i = 0, len = cs.length; i < len; i++) {
22137 if(fn.call(scope || this, args || cs[i]) === false){
22144 * Finds the first child that has the attribute with the specified value.
22145 * @param {String} attribute The attribute name
22146 * @param {Mixed} value The value to search for
22147 * @return {Node} The found child or null if none was found
22149 findChild : function(attribute, value){
22150 var cs = this.childNodes;
22151 for(var i = 0, len = cs.length; i < len; i++) {
22152 if(cs[i].attributes[attribute] == value){
22160 * Finds the first child by a custom function. The child matches if the function passed
22162 * @param {Function} fn
22163 * @param {Object} scope (optional)
22164 * @return {Node} The found child or null if none was found
22166 findChildBy : function(fn, scope){
22167 var cs = this.childNodes;
22168 for(var i = 0, len = cs.length; i < len; i++) {
22169 if(fn.call(scope||cs[i], cs[i]) === true){
22177 * Sorts this nodes children using the supplied sort function
22178 * @param {Function} fn
22179 * @param {Object} scope (optional)
22181 sort : function(fn, scope){
22182 var cs = this.childNodes;
22183 var len = cs.length;
22185 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
22187 for(var i = 0; i < len; i++){
22189 n.previousSibling = cs[i-1];
22190 n.nextSibling = cs[i+1];
22192 this.setFirstChild(n);
22195 this.setLastChild(n);
22202 * Returns true if this node is an ancestor (at any point) of the passed node.
22203 * @param {Node} node
22204 * @return {Boolean}
22206 contains : function(node){
22207 return node.isAncestor(this);
22211 * Returns true if the passed node is an ancestor (at any point) of this node.
22212 * @param {Node} node
22213 * @return {Boolean}
22215 isAncestor : function(node){
22216 var p = this.parentNode;
22226 toString : function(){
22227 return "[Node"+(this.id?" "+this.id:"")+"]";
22231 * Ext JS Library 1.1.1
22232 * Copyright(c) 2006-2007, Ext JS, LLC.
22234 * Originally Released Under LGPL - original licence link has changed is not relivant.
22237 * <script type="text/javascript">
22242 * @class Roo.ComponentMgr
22243 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
22246 Roo.ComponentMgr = function(){
22247 var all = new Roo.util.MixedCollection();
22251 * Registers a component.
22252 * @param {Roo.Component} c The component
22254 register : function(c){
22259 * Unregisters a component.
22260 * @param {Roo.Component} c The component
22262 unregister : function(c){
22267 * Returns a component by id
22268 * @param {String} id The component id
22270 get : function(id){
22271 return all.get(id);
22275 * Registers a function that will be called when a specified component is added to ComponentMgr
22276 * @param {String} id The component id
22277 * @param {Funtction} fn The callback function
22278 * @param {Object} scope The scope of the callback
22280 onAvailable : function(id, fn, scope){
22281 all.on("add", function(index, o){
22283 fn.call(scope || o, o);
22284 all.un("add", fn, scope);
22291 * Ext JS Library 1.1.1
22292 * Copyright(c) 2006-2007, Ext JS, LLC.
22294 * Originally Released Under LGPL - original licence link has changed is not relivant.
22297 * <script type="text/javascript">
22301 * @class Roo.Component
22302 * @extends Roo.util.Observable
22303 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
22304 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
22305 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
22306 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
22307 * All visual components (widgets) that require rendering into a layout should subclass Component.
22309 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
22310 * 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
22311 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
22313 Roo.Component = function(config){
22314 config = config || {};
22315 if(config.tagName || config.dom || typeof config == "string"){ // element object
22316 config = {el: config, id: config.id || config};
22318 this.initialConfig = config;
22320 Roo.apply(this, config);
22324 * Fires after the component is disabled.
22325 * @param {Roo.Component} this
22330 * Fires after the component is enabled.
22331 * @param {Roo.Component} this
22335 * @event beforeshow
22336 * Fires before the component is shown. Return false to stop the show.
22337 * @param {Roo.Component} this
22342 * Fires after the component is shown.
22343 * @param {Roo.Component} this
22347 * @event beforehide
22348 * Fires before the component is hidden. Return false to stop the hide.
22349 * @param {Roo.Component} this
22354 * Fires after the component is hidden.
22355 * @param {Roo.Component} this
22359 * @event beforerender
22360 * Fires before the component is rendered. Return false to stop the render.
22361 * @param {Roo.Component} this
22363 beforerender : true,
22366 * Fires after the component is rendered.
22367 * @param {Roo.Component} this
22371 * @event beforedestroy
22372 * Fires before the component is destroyed. Return false to stop the destroy.
22373 * @param {Roo.Component} this
22375 beforedestroy : true,
22378 * Fires after the component is destroyed.
22379 * @param {Roo.Component} this
22384 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
22386 Roo.ComponentMgr.register(this);
22387 Roo.Component.superclass.constructor.call(this);
22388 this.initComponent();
22389 if(this.renderTo){ // not supported by all components yet. use at your own risk!
22390 this.render(this.renderTo);
22391 delete this.renderTo;
22396 Roo.Component.AUTO_ID = 1000;
22398 Roo.extend(Roo.Component, Roo.util.Observable, {
22400 * @scope Roo.Component.prototype
22402 * true if this component is hidden. Read-only.
22407 * true if this component is disabled. Read-only.
22412 * true if this component has been rendered. Read-only.
22416 /** @cfg {String} disableClass
22417 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
22419 disabledClass : "x-item-disabled",
22420 /** @cfg {Boolean} allowDomMove
22421 * Whether the component can move the Dom node when rendering (defaults to true).
22423 allowDomMove : true,
22424 /** @cfg {String} hideMode
22425 * How this component should hidden. Supported values are
22426 * "visibility" (css visibility), "offsets" (negative offset position) and
22427 * "display" (css display) - defaults to "display".
22429 hideMode: 'display',
22432 ctype : "Roo.Component",
22435 * @cfg {String} actionMode
22436 * which property holds the element that used for hide() / show() / disable() / enable()
22442 getActionEl : function(){
22443 return this[this.actionMode];
22446 initComponent : Roo.emptyFn,
22448 * If this is a lazy rendering component, render it to its container element.
22449 * @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.
22451 render : function(container, position){
22452 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
22453 if(!container && this.el){
22454 this.el = Roo.get(this.el);
22455 container = this.el.dom.parentNode;
22456 this.allowDomMove = false;
22458 this.container = Roo.get(container);
22459 this.rendered = true;
22460 if(position !== undefined){
22461 if(typeof position == 'number'){
22462 position = this.container.dom.childNodes[position];
22464 position = Roo.getDom(position);
22467 this.onRender(this.container, position || null);
22469 this.el.addClass(this.cls);
22473 this.el.applyStyles(this.style);
22476 this.fireEvent("render", this);
22477 this.afterRender(this.container);
22489 // default function is not really useful
22490 onRender : function(ct, position){
22492 this.el = Roo.get(this.el);
22493 if(this.allowDomMove !== false){
22494 ct.dom.insertBefore(this.el.dom, position);
22500 getAutoCreate : function(){
22501 var cfg = typeof this.autoCreate == "object" ?
22502 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
22503 if(this.id && !cfg.id){
22510 afterRender : Roo.emptyFn,
22513 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22514 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22516 destroy : function(){
22517 if(this.fireEvent("beforedestroy", this) !== false){
22518 this.purgeListeners();
22519 this.beforeDestroy();
22521 this.el.removeAllListeners();
22523 if(this.actionMode == "container"){
22524 this.container.remove();
22528 Roo.ComponentMgr.unregister(this);
22529 this.fireEvent("destroy", this);
22534 beforeDestroy : function(){
22539 onDestroy : function(){
22544 * Returns the underlying {@link Roo.Element}.
22545 * @return {Roo.Element} The element
22547 getEl : function(){
22552 * Returns the id of this component.
22555 getId : function(){
22560 * Try to focus this component.
22561 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22562 * @return {Roo.Component} this
22564 focus : function(selectText){
22567 if(selectText === true){
22568 this.el.dom.select();
22583 * Disable this component.
22584 * @return {Roo.Component} this
22586 disable : function(){
22590 this.disabled = true;
22591 this.fireEvent("disable", this);
22596 onDisable : function(){
22597 this.getActionEl().addClass(this.disabledClass);
22598 this.el.dom.disabled = true;
22602 * Enable this component.
22603 * @return {Roo.Component} this
22605 enable : function(){
22609 this.disabled = false;
22610 this.fireEvent("enable", this);
22615 onEnable : function(){
22616 this.getActionEl().removeClass(this.disabledClass);
22617 this.el.dom.disabled = false;
22621 * Convenience function for setting disabled/enabled by boolean.
22622 * @param {Boolean} disabled
22624 setDisabled : function(disabled){
22625 this[disabled ? "disable" : "enable"]();
22629 * Show this component.
22630 * @return {Roo.Component} this
22633 if(this.fireEvent("beforeshow", this) !== false){
22634 this.hidden = false;
22638 this.fireEvent("show", this);
22644 onShow : function(){
22645 var ae = this.getActionEl();
22646 if(this.hideMode == 'visibility'){
22647 ae.dom.style.visibility = "visible";
22648 }else if(this.hideMode == 'offsets'){
22649 ae.removeClass('x-hidden');
22651 ae.dom.style.display = "";
22656 * Hide this component.
22657 * @return {Roo.Component} this
22660 if(this.fireEvent("beforehide", this) !== false){
22661 this.hidden = true;
22665 this.fireEvent("hide", this);
22671 onHide : function(){
22672 var ae = this.getActionEl();
22673 if(this.hideMode == 'visibility'){
22674 ae.dom.style.visibility = "hidden";
22675 }else if(this.hideMode == 'offsets'){
22676 ae.addClass('x-hidden');
22678 ae.dom.style.display = "none";
22683 * Convenience function to hide or show this component by boolean.
22684 * @param {Boolean} visible True to show, false to hide
22685 * @return {Roo.Component} this
22687 setVisible: function(visible){
22697 * Returns true if this component is visible.
22699 isVisible : function(){
22700 return this.getActionEl().isVisible();
22703 cloneConfig : function(overrides){
22704 overrides = overrides || {};
22705 var id = overrides.id || Roo.id();
22706 var cfg = Roo.applyIf(overrides, this.initialConfig);
22707 cfg.id = id; // prevent dup id
22708 return new this.constructor(cfg);
22712 * Ext JS Library 1.1.1
22713 * Copyright(c) 2006-2007, Ext JS, LLC.
22715 * Originally Released Under LGPL - original licence link has changed is not relivant.
22718 * <script type="text/javascript">
22723 * @extends Roo.Element
22724 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22725 * automatic maintaining of shadow/shim positions.
22726 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22727 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22728 * you can pass a string with a CSS class name. False turns off the shadow.
22729 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22730 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22731 * @cfg {String} cls CSS class to add to the element
22732 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22733 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22735 * @param {Object} config An object with config options.
22736 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22739 Roo.Layer = function(config, existingEl){
22740 config = config || {};
22741 var dh = Roo.DomHelper;
22742 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22744 this.dom = Roo.getDom(existingEl);
22747 var o = config.dh || {tag: "div", cls: "x-layer"};
22748 this.dom = dh.append(pel, o);
22751 this.addClass(config.cls);
22753 this.constrain = config.constrain !== false;
22754 this.visibilityMode = Roo.Element.VISIBILITY;
22756 this.id = this.dom.id = config.id;
22758 this.id = Roo.id(this.dom);
22760 this.zindex = config.zindex || this.getZIndex();
22761 this.position("absolute", this.zindex);
22763 this.shadowOffset = config.shadowOffset || 4;
22764 this.shadow = new Roo.Shadow({
22765 offset : this.shadowOffset,
22766 mode : config.shadow
22769 this.shadowOffset = 0;
22771 this.useShim = config.shim !== false && Roo.useShims;
22772 this.useDisplay = config.useDisplay;
22776 var supr = Roo.Element.prototype;
22778 // shims are shared among layer to keep from having 100 iframes
22781 Roo.extend(Roo.Layer, Roo.Element, {
22783 getZIndex : function(){
22784 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22787 getShim : function(){
22794 var shim = shims.shift();
22796 shim = this.createShim();
22797 shim.enableDisplayMode('block');
22798 shim.dom.style.display = 'none';
22799 shim.dom.style.visibility = 'visible';
22801 var pn = this.dom.parentNode;
22802 if(shim.dom.parentNode != pn){
22803 pn.insertBefore(shim.dom, this.dom);
22805 shim.setStyle('z-index', this.getZIndex()-2);
22810 hideShim : function(){
22812 this.shim.setDisplayed(false);
22813 shims.push(this.shim);
22818 disableShadow : function(){
22820 this.shadowDisabled = true;
22821 this.shadow.hide();
22822 this.lastShadowOffset = this.shadowOffset;
22823 this.shadowOffset = 0;
22827 enableShadow : function(show){
22829 this.shadowDisabled = false;
22830 this.shadowOffset = this.lastShadowOffset;
22831 delete this.lastShadowOffset;
22839 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22840 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22841 sync : function(doShow){
22842 var sw = this.shadow;
22843 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22844 var sh = this.getShim();
22846 var w = this.getWidth(),
22847 h = this.getHeight();
22849 var l = this.getLeft(true),
22850 t = this.getTop(true);
22852 if(sw && !this.shadowDisabled){
22853 if(doShow && !sw.isVisible()){
22856 sw.realign(l, t, w, h);
22862 // fit the shim behind the shadow, so it is shimmed too
22863 var a = sw.adjusts, s = sh.dom.style;
22864 s.left = (Math.min(l, l+a.l))+"px";
22865 s.top = (Math.min(t, t+a.t))+"px";
22866 s.width = (w+a.w)+"px";
22867 s.height = (h+a.h)+"px";
22874 sh.setLeftTop(l, t);
22881 destroy : function(){
22884 this.shadow.hide();
22886 this.removeAllListeners();
22887 var pn = this.dom.parentNode;
22889 pn.removeChild(this.dom);
22891 Roo.Element.uncache(this.id);
22894 remove : function(){
22899 beginUpdate : function(){
22900 this.updating = true;
22904 endUpdate : function(){
22905 this.updating = false;
22910 hideUnders : function(negOffset){
22912 this.shadow.hide();
22918 constrainXY : function(){
22919 if(this.constrain){
22920 var vw = Roo.lib.Dom.getViewWidth(),
22921 vh = Roo.lib.Dom.getViewHeight();
22922 var s = Roo.get(document).getScroll();
22924 var xy = this.getXY();
22925 var x = xy[0], y = xy[1];
22926 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22927 // only move it if it needs it
22929 // first validate right/bottom
22930 if((x + w) > vw+s.left){
22931 x = vw - w - this.shadowOffset;
22934 if((y + h) > vh+s.top){
22935 y = vh - h - this.shadowOffset;
22938 // then make sure top/left isn't negative
22949 var ay = this.avoidY;
22950 if(y <= ay && (y+h) >= ay){
22956 supr.setXY.call(this, xy);
22962 isVisible : function(){
22963 return this.visible;
22967 showAction : function(){
22968 this.visible = true; // track visibility to prevent getStyle calls
22969 if(this.useDisplay === true){
22970 this.setDisplayed("");
22971 }else if(this.lastXY){
22972 supr.setXY.call(this, this.lastXY);
22973 }else if(this.lastLT){
22974 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22979 hideAction : function(){
22980 this.visible = false;
22981 if(this.useDisplay === true){
22982 this.setDisplayed(false);
22984 this.setLeftTop(-10000,-10000);
22988 // overridden Element method
22989 setVisible : function(v, a, d, c, e){
22994 var cb = function(){
22999 }.createDelegate(this);
23000 supr.setVisible.call(this, true, true, d, cb, e);
23003 this.hideUnders(true);
23012 }.createDelegate(this);
23014 supr.setVisible.call(this, v, a, d, cb, e);
23023 storeXY : function(xy){
23024 delete this.lastLT;
23028 storeLeftTop : function(left, top){
23029 delete this.lastXY;
23030 this.lastLT = [left, top];
23034 beforeFx : function(){
23035 this.beforeAction();
23036 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23040 afterFx : function(){
23041 Roo.Layer.superclass.afterFx.apply(this, arguments);
23042 this.sync(this.isVisible());
23046 beforeAction : function(){
23047 if(!this.updating && this.shadow){
23048 this.shadow.hide();
23052 // overridden Element method
23053 setLeft : function(left){
23054 this.storeLeftTop(left, this.getTop(true));
23055 supr.setLeft.apply(this, arguments);
23059 setTop : function(top){
23060 this.storeLeftTop(this.getLeft(true), top);
23061 supr.setTop.apply(this, arguments);
23065 setLeftTop : function(left, top){
23066 this.storeLeftTop(left, top);
23067 supr.setLeftTop.apply(this, arguments);
23071 setXY : function(xy, a, d, c, e){
23073 this.beforeAction();
23075 var cb = this.createCB(c);
23076 supr.setXY.call(this, xy, a, d, cb, e);
23083 createCB : function(c){
23094 // overridden Element method
23095 setX : function(x, a, d, c, e){
23096 this.setXY([x, this.getY()], a, d, c, e);
23099 // overridden Element method
23100 setY : function(y, a, d, c, e){
23101 this.setXY([this.getX(), y], a, d, c, e);
23104 // overridden Element method
23105 setSize : function(w, h, a, d, c, e){
23106 this.beforeAction();
23107 var cb = this.createCB(c);
23108 supr.setSize.call(this, w, h, a, d, cb, e);
23114 // overridden Element method
23115 setWidth : function(w, a, d, c, e){
23116 this.beforeAction();
23117 var cb = this.createCB(c);
23118 supr.setWidth.call(this, w, a, d, cb, e);
23124 // overridden Element method
23125 setHeight : function(h, a, d, c, e){
23126 this.beforeAction();
23127 var cb = this.createCB(c);
23128 supr.setHeight.call(this, h, a, d, cb, e);
23134 // overridden Element method
23135 setBounds : function(x, y, w, h, a, d, c, e){
23136 this.beforeAction();
23137 var cb = this.createCB(c);
23139 this.storeXY([x, y]);
23140 supr.setXY.call(this, [x, y]);
23141 supr.setSize.call(this, w, h, a, d, cb, e);
23144 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
23150 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
23151 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
23152 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
23153 * @param {Number} zindex The new z-index to set
23154 * @return {this} The Layer
23156 setZIndex : function(zindex){
23157 this.zindex = zindex;
23158 this.setStyle("z-index", zindex + 2);
23160 this.shadow.setZIndex(zindex + 1);
23163 this.shim.setStyle("z-index", zindex);
23169 * Ext JS Library 1.1.1
23170 * Copyright(c) 2006-2007, Ext JS, LLC.
23172 * Originally Released Under LGPL - original licence link has changed is not relivant.
23175 * <script type="text/javascript">
23180 * @class Roo.Shadow
23181 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
23182 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
23183 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
23185 * Create a new Shadow
23186 * @param {Object} config The config object
23188 Roo.Shadow = function(config){
23189 Roo.apply(this, config);
23190 if(typeof this.mode != "string"){
23191 this.mode = this.defaultMode;
23193 var o = this.offset, a = {h: 0};
23194 var rad = Math.floor(this.offset/2);
23195 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
23201 a.l -= this.offset + rad;
23202 a.t -= this.offset + rad;
23213 a.l -= (this.offset - rad);
23214 a.t -= this.offset + rad;
23216 a.w -= (this.offset - rad)*2;
23227 a.l -= (this.offset - rad);
23228 a.t -= (this.offset - rad);
23230 a.w -= (this.offset + rad + 1);
23231 a.h -= (this.offset + rad);
23240 Roo.Shadow.prototype = {
23242 * @cfg {String} mode
23243 * The shadow display mode. Supports the following options:<br />
23244 * sides: Shadow displays on both sides and bottom only<br />
23245 * frame: Shadow displays equally on all four sides<br />
23246 * drop: Traditional bottom-right drop shadow (default)
23249 * @cfg {String} offset
23250 * The number of pixels to offset the shadow from the element (defaults to 4)
23255 defaultMode: "drop",
23258 * Displays the shadow under the target element
23259 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
23261 show : function(target){
23262 target = Roo.get(target);
23264 this.el = Roo.Shadow.Pool.pull();
23265 if(this.el.dom.nextSibling != target.dom){
23266 this.el.insertBefore(target);
23269 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
23271 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
23274 target.getLeft(true),
23275 target.getTop(true),
23279 this.el.dom.style.display = "block";
23283 * Returns true if the shadow is visible, else false
23285 isVisible : function(){
23286 return this.el ? true : false;
23290 * Direct alignment when values are already available. Show must be called at least once before
23291 * calling this method to ensure it is initialized.
23292 * @param {Number} left The target element left position
23293 * @param {Number} top The target element top position
23294 * @param {Number} width The target element width
23295 * @param {Number} height The target element height
23297 realign : function(l, t, w, h){
23301 var a = this.adjusts, d = this.el.dom, s = d.style;
23303 s.left = (l+a.l)+"px";
23304 s.top = (t+a.t)+"px";
23305 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
23307 if(s.width != sws || s.height != shs){
23311 var cn = d.childNodes;
23312 var sww = Math.max(0, (sw-12))+"px";
23313 cn[0].childNodes[1].style.width = sww;
23314 cn[1].childNodes[1].style.width = sww;
23315 cn[2].childNodes[1].style.width = sww;
23316 cn[1].style.height = Math.max(0, (sh-12))+"px";
23322 * Hides this shadow
23326 this.el.dom.style.display = "none";
23327 Roo.Shadow.Pool.push(this.el);
23333 * Adjust the z-index of this shadow
23334 * @param {Number} zindex The new z-index
23336 setZIndex : function(z){
23339 this.el.setStyle("z-index", z);
23344 // Private utility class that manages the internal Shadow cache
23345 Roo.Shadow.Pool = function(){
23347 var markup = Roo.isIE ?
23348 '<div class="x-ie-shadow"></div>' :
23349 '<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>';
23352 var sh = p.shift();
23354 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
23355 sh.autoBoxAdjust = false;
23360 push : function(sh){
23366 * Ext JS Library 1.1.1
23367 * Copyright(c) 2006-2007, Ext JS, LLC.
23369 * Originally Released Under LGPL - original licence link has changed is not relivant.
23372 * <script type="text/javascript">
23376 * @class Roo.BoxComponent
23377 * @extends Roo.Component
23378 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
23379 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
23380 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
23381 * layout containers.
23383 * @param {Roo.Element/String/Object} config The configuration options.
23385 Roo.BoxComponent = function(config){
23386 Roo.Component.call(this, config);
23390 * Fires after the component is resized.
23391 * @param {Roo.Component} this
23392 * @param {Number} adjWidth The box-adjusted width that was set
23393 * @param {Number} adjHeight The box-adjusted height that was set
23394 * @param {Number} rawWidth The width that was originally specified
23395 * @param {Number} rawHeight The height that was originally specified
23400 * Fires after the component is moved.
23401 * @param {Roo.Component} this
23402 * @param {Number} x The new x position
23403 * @param {Number} y The new y position
23409 Roo.extend(Roo.BoxComponent, Roo.Component, {
23410 // private, set in afterRender to signify that the component has been rendered
23412 // private, used to defer height settings to subclasses
23413 deferHeight: false,
23414 /** @cfg {Number} width
23415 * width (optional) size of component
23417 /** @cfg {Number} height
23418 * height (optional) size of component
23422 * Sets the width and height of the component. This method fires the resize event. This method can accept
23423 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
23424 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
23425 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
23426 * @return {Roo.BoxComponent} this
23428 setSize : function(w, h){
23429 // support for standard size objects
23430 if(typeof w == 'object'){
23435 if(!this.boxReady){
23441 // prevent recalcs when not needed
23442 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
23445 this.lastSize = {width: w, height: h};
23447 var adj = this.adjustSize(w, h);
23448 var aw = adj.width, ah = adj.height;
23449 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
23450 var rz = this.getResizeEl();
23451 if(!this.deferHeight && aw !== undefined && ah !== undefined){
23452 rz.setSize(aw, ah);
23453 }else if(!this.deferHeight && ah !== undefined){
23455 }else if(aw !== undefined){
23458 this.onResize(aw, ah, w, h);
23459 this.fireEvent('resize', this, aw, ah, w, h);
23465 * Gets the current size of the component's underlying element.
23466 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
23468 getSize : function(){
23469 return this.el.getSize();
23473 * Gets the current XY position of the component's underlying element.
23474 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23475 * @return {Array} The XY position of the element (e.g., [100, 200])
23477 getPosition : function(local){
23478 if(local === true){
23479 return [this.el.getLeft(true), this.el.getTop(true)];
23481 return this.xy || this.el.getXY();
23485 * Gets the current box measurements of the component's underlying element.
23486 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23487 * @returns {Object} box An object in the format {x, y, width, height}
23489 getBox : function(local){
23490 var s = this.el.getSize();
23492 s.x = this.el.getLeft(true);
23493 s.y = this.el.getTop(true);
23495 var xy = this.xy || this.el.getXY();
23503 * Sets the current box measurements of the component's underlying element.
23504 * @param {Object} box An object in the format {x, y, width, height}
23505 * @returns {Roo.BoxComponent} this
23507 updateBox : function(box){
23508 this.setSize(box.width, box.height);
23509 this.setPagePosition(box.x, box.y);
23514 getResizeEl : function(){
23515 return this.resizeEl || this.el;
23519 getPositionEl : function(){
23520 return this.positionEl || this.el;
23524 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23525 * This method fires the move event.
23526 * @param {Number} left The new left
23527 * @param {Number} top The new top
23528 * @returns {Roo.BoxComponent} this
23530 setPosition : function(x, y){
23533 if(!this.boxReady){
23536 var adj = this.adjustPosition(x, y);
23537 var ax = adj.x, ay = adj.y;
23539 var el = this.getPositionEl();
23540 if(ax !== undefined || ay !== undefined){
23541 if(ax !== undefined && ay !== undefined){
23542 el.setLeftTop(ax, ay);
23543 }else if(ax !== undefined){
23545 }else if(ay !== undefined){
23548 this.onPosition(ax, ay);
23549 this.fireEvent('move', this, ax, ay);
23555 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23556 * This method fires the move event.
23557 * @param {Number} x The new x position
23558 * @param {Number} y The new y position
23559 * @returns {Roo.BoxComponent} this
23561 setPagePosition : function(x, y){
23564 if(!this.boxReady){
23567 if(x === undefined || y === undefined){ // cannot translate undefined points
23570 var p = this.el.translatePoints(x, y);
23571 this.setPosition(p.left, p.top);
23576 onRender : function(ct, position){
23577 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23579 this.resizeEl = Roo.get(this.resizeEl);
23581 if(this.positionEl){
23582 this.positionEl = Roo.get(this.positionEl);
23587 afterRender : function(){
23588 Roo.BoxComponent.superclass.afterRender.call(this);
23589 this.boxReady = true;
23590 this.setSize(this.width, this.height);
23591 if(this.x || this.y){
23592 this.setPosition(this.x, this.y);
23594 if(this.pageX || this.pageY){
23595 this.setPagePosition(this.pageX, this.pageY);
23600 * Force the component's size to recalculate based on the underlying element's current height and width.
23601 * @returns {Roo.BoxComponent} this
23603 syncSize : function(){
23604 delete this.lastSize;
23605 this.setSize(this.el.getWidth(), this.el.getHeight());
23610 * Called after the component is resized, this method is empty by default but can be implemented by any
23611 * subclass that needs to perform custom logic after a resize occurs.
23612 * @param {Number} adjWidth The box-adjusted width that was set
23613 * @param {Number} adjHeight The box-adjusted height that was set
23614 * @param {Number} rawWidth The width that was originally specified
23615 * @param {Number} rawHeight The height that was originally specified
23617 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23622 * Called after the component is moved, this method is empty by default but can be implemented by any
23623 * subclass that needs to perform custom logic after a move occurs.
23624 * @param {Number} x The new x position
23625 * @param {Number} y The new y position
23627 onPosition : function(x, y){
23632 adjustSize : function(w, h){
23633 if(this.autoWidth){
23636 if(this.autoHeight){
23639 return {width : w, height: h};
23643 adjustPosition : function(x, y){
23644 return {x : x, y: y};
23648 * Ext JS Library 1.1.1
23649 * Copyright(c) 2006-2007, Ext JS, LLC.
23651 * Originally Released Under LGPL - original licence link has changed is not relivant.
23654 * <script type="text/javascript">
23659 * @class Roo.SplitBar
23660 * @extends Roo.util.Observable
23661 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23665 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23666 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23667 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23668 split.minSize = 100;
23669 split.maxSize = 600;
23670 split.animate = true;
23671 split.on('moved', splitterMoved);
23674 * Create a new SplitBar
23675 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23676 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23677 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23678 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23679 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23680 position of the SplitBar).
23682 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23685 this.el = Roo.get(dragElement, true);
23686 this.el.dom.unselectable = "on";
23688 this.resizingEl = Roo.get(resizingElement, true);
23692 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23693 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23696 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23699 * The minimum size of the resizing element. (Defaults to 0)
23705 * The maximum size of the resizing element. (Defaults to 2000)
23708 this.maxSize = 2000;
23711 * Whether to animate the transition to the new size
23714 this.animate = false;
23717 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23720 this.useShim = false;
23725 if(!existingProxy){
23727 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23729 this.proxy = Roo.get(existingProxy).dom;
23732 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23735 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23738 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23741 this.dragSpecs = {};
23744 * @private The adapter to use to positon and resize elements
23746 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23747 this.adapter.init(this);
23749 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23751 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23752 this.el.addClass("x-splitbar-h");
23755 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23756 this.el.addClass("x-splitbar-v");
23762 * Fires when the splitter is moved (alias for {@link #event-moved})
23763 * @param {Roo.SplitBar} this
23764 * @param {Number} newSize the new width or height
23769 * Fires when the splitter is moved
23770 * @param {Roo.SplitBar} this
23771 * @param {Number} newSize the new width or height
23775 * @event beforeresize
23776 * Fires before the splitter is dragged
23777 * @param {Roo.SplitBar} this
23779 "beforeresize" : true,
23781 "beforeapply" : true
23784 Roo.util.Observable.call(this);
23787 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23788 onStartProxyDrag : function(x, y){
23789 this.fireEvent("beforeresize", this);
23791 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23793 o.enableDisplayMode("block");
23794 // all splitbars share the same overlay
23795 Roo.SplitBar.prototype.overlay = o;
23797 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23798 this.overlay.show();
23799 Roo.get(this.proxy).setDisplayed("block");
23800 var size = this.adapter.getElementSize(this);
23801 this.activeMinSize = this.getMinimumSize();;
23802 this.activeMaxSize = this.getMaximumSize();;
23803 var c1 = size - this.activeMinSize;
23804 var c2 = Math.max(this.activeMaxSize - size, 0);
23805 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23806 this.dd.resetConstraints();
23807 this.dd.setXConstraint(
23808 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23809 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23811 this.dd.setYConstraint(0, 0);
23813 this.dd.resetConstraints();
23814 this.dd.setXConstraint(0, 0);
23815 this.dd.setYConstraint(
23816 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23817 this.placement == Roo.SplitBar.TOP ? c2 : c1
23820 this.dragSpecs.startSize = size;
23821 this.dragSpecs.startPoint = [x, y];
23822 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23826 * @private Called after the drag operation by the DDProxy
23828 onEndProxyDrag : function(e){
23829 Roo.get(this.proxy).setDisplayed(false);
23830 var endPoint = Roo.lib.Event.getXY(e);
23832 this.overlay.hide();
23835 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23836 newSize = this.dragSpecs.startSize +
23837 (this.placement == Roo.SplitBar.LEFT ?
23838 endPoint[0] - this.dragSpecs.startPoint[0] :
23839 this.dragSpecs.startPoint[0] - endPoint[0]
23842 newSize = this.dragSpecs.startSize +
23843 (this.placement == Roo.SplitBar.TOP ?
23844 endPoint[1] - this.dragSpecs.startPoint[1] :
23845 this.dragSpecs.startPoint[1] - endPoint[1]
23848 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23849 if(newSize != this.dragSpecs.startSize){
23850 if(this.fireEvent('beforeapply', this, newSize) !== false){
23851 this.adapter.setElementSize(this, newSize);
23852 this.fireEvent("moved", this, newSize);
23853 this.fireEvent("resize", this, newSize);
23859 * Get the adapter this SplitBar uses
23860 * @return The adapter object
23862 getAdapter : function(){
23863 return this.adapter;
23867 * Set the adapter this SplitBar uses
23868 * @param {Object} adapter A SplitBar adapter object
23870 setAdapter : function(adapter){
23871 this.adapter = adapter;
23872 this.adapter.init(this);
23876 * Gets the minimum size for the resizing element
23877 * @return {Number} The minimum size
23879 getMinimumSize : function(){
23880 return this.minSize;
23884 * Sets the minimum size for the resizing element
23885 * @param {Number} minSize The minimum size
23887 setMinimumSize : function(minSize){
23888 this.minSize = minSize;
23892 * Gets the maximum size for the resizing element
23893 * @return {Number} The maximum size
23895 getMaximumSize : function(){
23896 return this.maxSize;
23900 * Sets the maximum size for the resizing element
23901 * @param {Number} maxSize The maximum size
23903 setMaximumSize : function(maxSize){
23904 this.maxSize = maxSize;
23908 * Sets the initialize size for the resizing element
23909 * @param {Number} size The initial size
23911 setCurrentSize : function(size){
23912 var oldAnimate = this.animate;
23913 this.animate = false;
23914 this.adapter.setElementSize(this, size);
23915 this.animate = oldAnimate;
23919 * Destroy this splitbar.
23920 * @param {Boolean} removeEl True to remove the element
23922 destroy : function(removeEl){
23924 this.shim.remove();
23927 this.proxy.parentNode.removeChild(this.proxy);
23935 * @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.
23937 Roo.SplitBar.createProxy = function(dir){
23938 var proxy = new Roo.Element(document.createElement("div"));
23939 proxy.unselectable();
23940 var cls = 'x-splitbar-proxy';
23941 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23942 document.body.appendChild(proxy.dom);
23947 * @class Roo.SplitBar.BasicLayoutAdapter
23948 * Default Adapter. It assumes the splitter and resizing element are not positioned
23949 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23951 Roo.SplitBar.BasicLayoutAdapter = function(){
23954 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23955 // do nothing for now
23956 init : function(s){
23960 * Called before drag operations to get the current size of the resizing element.
23961 * @param {Roo.SplitBar} s The SplitBar using this adapter
23963 getElementSize : function(s){
23964 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23965 return s.resizingEl.getWidth();
23967 return s.resizingEl.getHeight();
23972 * Called after drag operations to set the size of the resizing element.
23973 * @param {Roo.SplitBar} s The SplitBar using this adapter
23974 * @param {Number} newSize The new size to set
23975 * @param {Function} onComplete A function to be invoked when resizing is complete
23977 setElementSize : function(s, newSize, onComplete){
23978 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23980 s.resizingEl.setWidth(newSize);
23982 onComplete(s, newSize);
23985 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23990 s.resizingEl.setHeight(newSize);
23992 onComplete(s, newSize);
23995 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24002 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24003 * @extends Roo.SplitBar.BasicLayoutAdapter
24004 * Adapter that moves the splitter element to align with the resized sizing element.
24005 * Used with an absolute positioned SplitBar.
24006 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24007 * document.body, make sure you assign an id to the body element.
24009 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24010 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24011 this.container = Roo.get(container);
24014 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24015 init : function(s){
24016 this.basic.init(s);
24019 getElementSize : function(s){
24020 return this.basic.getElementSize(s);
24023 setElementSize : function(s, newSize, onComplete){
24024 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24027 moveSplitter : function(s){
24028 var yes = Roo.SplitBar;
24029 switch(s.placement){
24031 s.el.setX(s.resizingEl.getRight());
24034 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24037 s.el.setY(s.resizingEl.getBottom());
24040 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24047 * Orientation constant - Create a vertical SplitBar
24051 Roo.SplitBar.VERTICAL = 1;
24054 * Orientation constant - Create a horizontal SplitBar
24058 Roo.SplitBar.HORIZONTAL = 2;
24061 * Placement constant - The resizing element is to the left of the splitter element
24065 Roo.SplitBar.LEFT = 1;
24068 * Placement constant - The resizing element is to the right of the splitter element
24072 Roo.SplitBar.RIGHT = 2;
24075 * Placement constant - The resizing element is positioned above the splitter element
24079 Roo.SplitBar.TOP = 3;
24082 * Placement constant - The resizing element is positioned under splitter element
24086 Roo.SplitBar.BOTTOM = 4;
24089 * Ext JS Library 1.1.1
24090 * Copyright(c) 2006-2007, Ext JS, LLC.
24092 * Originally Released Under LGPL - original licence link has changed is not relivant.
24095 * <script type="text/javascript">
24100 * @extends Roo.util.Observable
24101 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24102 * This class also supports single and multi selection modes. <br>
24103 * Create a data model bound view:
24105 var store = new Roo.data.Store(...);
24107 var view = new Roo.View({
24109 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24111 singleSelect: true,
24112 selectedClass: "ydataview-selected",
24116 // listen for node click?
24117 view.on("click", function(vw, index, node, e){
24118 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24122 dataModel.load("foobar.xml");
24124 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24126 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24127 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24129 * Note: old style constructor is still suported (container, template, config)
24132 * Create a new View
24133 * @param {Object} config The config object
24136 Roo.View = function(config, depreciated_tpl, depreciated_config){
24138 if (typeof(depreciated_tpl) == 'undefined') {
24139 // new way.. - universal constructor.
24140 Roo.apply(this, config);
24141 this.el = Roo.get(this.el);
24144 this.el = Roo.get(config);
24145 this.tpl = depreciated_tpl;
24146 Roo.apply(this, depreciated_config);
24148 this.wrapEl = this.el.wrap().wrap();
24149 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24152 if(typeof(this.tpl) == "string"){
24153 this.tpl = new Roo.Template(this.tpl);
24155 // support xtype ctors..
24156 this.tpl = new Roo.factory(this.tpl, Roo);
24160 this.tpl.compile();
24168 * @event beforeclick
24169 * Fires before a click is processed. Returns false to cancel the default action.
24170 * @param {Roo.View} this
24171 * @param {Number} index The index of the target node
24172 * @param {HTMLElement} node The target node
24173 * @param {Roo.EventObject} e The raw event object
24175 "beforeclick" : true,
24178 * Fires when a template node is clicked.
24179 * @param {Roo.View} this
24180 * @param {Number} index The index of the target node
24181 * @param {HTMLElement} node The target node
24182 * @param {Roo.EventObject} e The raw event object
24187 * Fires when a template node is double clicked.
24188 * @param {Roo.View} this
24189 * @param {Number} index The index of the target node
24190 * @param {HTMLElement} node The target node
24191 * @param {Roo.EventObject} e The raw event object
24195 * @event contextmenu
24196 * Fires when a template node is right clicked.
24197 * @param {Roo.View} this
24198 * @param {Number} index The index of the target node
24199 * @param {HTMLElement} node The target node
24200 * @param {Roo.EventObject} e The raw event object
24202 "contextmenu" : true,
24204 * @event selectionchange
24205 * Fires when the selected nodes change.
24206 * @param {Roo.View} this
24207 * @param {Array} selections Array of the selected nodes
24209 "selectionchange" : true,
24212 * @event beforeselect
24213 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24214 * @param {Roo.View} this
24215 * @param {HTMLElement} node The node to be selected
24216 * @param {Array} selections Array of currently selected nodes
24218 "beforeselect" : true,
24220 * @event preparedata
24221 * Fires on every row to render, to allow you to change the data.
24222 * @param {Roo.View} this
24223 * @param {Object} data to be rendered (change this)
24225 "preparedata" : true
24233 "click": this.onClick,
24234 "dblclick": this.onDblClick,
24235 "contextmenu": this.onContextMenu,
24239 this.selections = [];
24241 this.cmp = new Roo.CompositeElementLite([]);
24243 this.store = Roo.factory(this.store, Roo.data);
24244 this.setStore(this.store, true);
24247 if ( this.footer && this.footer.xtype) {
24249 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24251 this.footer.dataSource = this.store
24252 this.footer.container = fctr;
24253 this.footer = Roo.factory(this.footer, Roo);
24254 fctr.insertFirst(this.el);
24256 // this is a bit insane - as the paging toolbar seems to detach the el..
24257 // dom.parentNode.parentNode.parentNode
24258 // they get detached?
24262 Roo.View.superclass.constructor.call(this);
24267 Roo.extend(Roo.View, Roo.util.Observable, {
24270 * @cfg {Roo.data.Store} store Data store to load data from.
24275 * @cfg {String|Roo.Element} el The container element.
24280 * @cfg {String|Roo.Template} tpl The template used by this View
24284 * @cfg {String} dataName the named area of the template to use as the data area
24285 * Works with domtemplates roo-name="name"
24289 * @cfg {String} selectedClass The css class to add to selected nodes
24291 selectedClass : "x-view-selected",
24293 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24298 * @cfg {String} text to display on mask (default Loading)
24302 * @cfg {Boolean} multiSelect Allow multiple selection
24304 multiSelect : false,
24306 * @cfg {Boolean} singleSelect Allow single selection
24308 singleSelect: false,
24311 * @cfg {Boolean} toggleSelect - selecting
24313 toggleSelect : false,
24316 * Returns the element this view is bound to.
24317 * @return {Roo.Element}
24319 getEl : function(){
24320 return this.wrapEl;
24326 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24328 refresh : function(){
24331 // if we are using something like 'domtemplate', then
24332 // the what gets used is:
24333 // t.applySubtemplate(NAME, data, wrapping data..)
24334 // the outer template then get' applied with
24335 // the store 'extra data'
24336 // and the body get's added to the
24337 // roo-name="data" node?
24338 // <span class='roo-tpl-{name}'></span> ?????
24342 this.clearSelections();
24343 this.el.update("");
24345 var records = this.store.getRange();
24346 if(records.length < 1) {
24348 // is this valid?? = should it render a template??
24350 this.el.update(this.emptyText);
24354 if (this.dataName) {
24355 this.el.update(t.apply(this.store.meta)); //????
24356 el = this.el.child('.roo-tpl-' + this.dataName);
24359 for(var i = 0, len = records.length; i < len; i++){
24360 var data = this.prepareData(records[i].data, i, records[i]);
24361 this.fireEvent("preparedata", this, data, i, records[i]);
24362 html[html.length] = Roo.util.Format.trim(
24364 t.applySubtemplate(this.dataName, data, this.store.meta) :
24371 el.update(html.join(""));
24372 this.nodes = el.dom.childNodes;
24373 this.updateIndexes(0);
24377 * Function to override to reformat the data that is sent to
24378 * the template for each node.
24379 * DEPRICATED - use the preparedata event handler.
24380 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24381 * a JSON object for an UpdateManager bound view).
24383 prepareData : function(data, index, record)
24385 this.fireEvent("preparedata", this, data, index, record);
24389 onUpdate : function(ds, record){
24390 this.clearSelections();
24391 var index = this.store.indexOf(record);
24392 var n = this.nodes[index];
24393 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24394 n.parentNode.removeChild(n);
24395 this.updateIndexes(index, index);
24401 onAdd : function(ds, records, index)
24403 this.clearSelections();
24404 if(this.nodes.length == 0){
24408 var n = this.nodes[index];
24409 for(var i = 0, len = records.length; i < len; i++){
24410 var d = this.prepareData(records[i].data, i, records[i]);
24412 this.tpl.insertBefore(n, d);
24415 this.tpl.append(this.el, d);
24418 this.updateIndexes(index);
24421 onRemove : function(ds, record, index){
24422 this.clearSelections();
24423 var el = this.dataName ?
24424 this.el.child('.roo-tpl-' + this.dataName) :
24426 el.dom.removeChild(this.nodes[index]);
24427 this.updateIndexes(index);
24431 * Refresh an individual node.
24432 * @param {Number} index
24434 refreshNode : function(index){
24435 this.onUpdate(this.store, this.store.getAt(index));
24438 updateIndexes : function(startIndex, endIndex){
24439 var ns = this.nodes;
24440 startIndex = startIndex || 0;
24441 endIndex = endIndex || ns.length - 1;
24442 for(var i = startIndex; i <= endIndex; i++){
24443 ns[i].nodeIndex = i;
24448 * Changes the data store this view uses and refresh the view.
24449 * @param {Store} store
24451 setStore : function(store, initial){
24452 if(!initial && this.store){
24453 this.store.un("datachanged", this.refresh);
24454 this.store.un("add", this.onAdd);
24455 this.store.un("remove", this.onRemove);
24456 this.store.un("update", this.onUpdate);
24457 this.store.un("clear", this.refresh);
24458 this.store.un("beforeload", this.onBeforeLoad);
24459 this.store.un("load", this.onLoad);
24460 this.store.un("loadexception", this.onLoad);
24464 store.on("datachanged", this.refresh, this);
24465 store.on("add", this.onAdd, this);
24466 store.on("remove", this.onRemove, this);
24467 store.on("update", this.onUpdate, this);
24468 store.on("clear", this.refresh, this);
24469 store.on("beforeload", this.onBeforeLoad, this);
24470 store.on("load", this.onLoad, this);
24471 store.on("loadexception", this.onLoad, this);
24479 * onbeforeLoad - masks the loading area.
24482 onBeforeLoad : function()
24484 this.el.update("");
24485 this.el.mask(this.mask ? this.mask : "Loading" );
24487 onLoad : function ()
24494 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
24495 * @param {HTMLElement} node
24496 * @return {HTMLElement} The template node
24498 findItemFromChild : function(node){
24499 var el = this.dataName ?
24500 this.el.child('.roo-tpl-' + this.dataName,true) :
24503 if(!node || node.parentNode == el){
24506 var p = node.parentNode;
24507 while(p && p != el){
24508 if(p.parentNode == el){
24517 onClick : function(e){
24518 var item = this.findItemFromChild(e.getTarget());
24520 var index = this.indexOf(item);
24521 if(this.onItemClick(item, index, e) !== false){
24522 this.fireEvent("click", this, index, item, e);
24525 this.clearSelections();
24530 onContextMenu : function(e){
24531 var item = this.findItemFromChild(e.getTarget());
24533 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
24538 onDblClick : function(e){
24539 var item = this.findItemFromChild(e.getTarget());
24541 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
24545 onItemClick : function(item, index, e)
24547 if(this.fireEvent("beforeclick", this, index, item, e) === false){
24550 if (this.toggleSelect) {
24551 var m = this.isSelected(item) ? 'unselect' : 'select';
24554 _t[m](item, true, false);
24557 if(this.multiSelect || this.singleSelect){
24558 if(this.multiSelect && e.shiftKey && this.lastSelection){
24559 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
24561 this.select(item, this.multiSelect && e.ctrlKey);
24562 this.lastSelection = item;
24564 e.preventDefault();
24570 * Get the number of selected nodes.
24573 getSelectionCount : function(){
24574 return this.selections.length;
24578 * Get the currently selected nodes.
24579 * @return {Array} An array of HTMLElements
24581 getSelectedNodes : function(){
24582 return this.selections;
24586 * Get the indexes of the selected nodes.
24589 getSelectedIndexes : function(){
24590 var indexes = [], s = this.selections;
24591 for(var i = 0, len = s.length; i < len; i++){
24592 indexes.push(s[i].nodeIndex);
24598 * Clear all selections
24599 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
24601 clearSelections : function(suppressEvent){
24602 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24603 this.cmp.elements = this.selections;
24604 this.cmp.removeClass(this.selectedClass);
24605 this.selections = [];
24606 if(!suppressEvent){
24607 this.fireEvent("selectionchange", this, this.selections);
24613 * Returns true if the passed node is selected
24614 * @param {HTMLElement/Number} node The node or node index
24615 * @return {Boolean}
24617 isSelected : function(node){
24618 var s = this.selections;
24622 node = this.getNode(node);
24623 return s.indexOf(node) !== -1;
24628 * @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
24629 * @param {Boolean} keepExisting (optional) true to keep existing selections
24630 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24632 select : function(nodeInfo, keepExisting, suppressEvent){
24633 if(nodeInfo instanceof Array){
24635 this.clearSelections(true);
24637 for(var i = 0, len = nodeInfo.length; i < len; i++){
24638 this.select(nodeInfo[i], true, true);
24642 var node = this.getNode(nodeInfo);
24643 if(!node || this.isSelected(node)){
24644 return; // already selected.
24647 this.clearSelections(true);
24649 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24650 Roo.fly(node).addClass(this.selectedClass);
24651 this.selections.push(node);
24652 if(!suppressEvent){
24653 this.fireEvent("selectionchange", this, this.selections);
24661 * @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
24662 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24663 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24665 unselect : function(nodeInfo, keepExisting, suppressEvent)
24667 if(nodeInfo instanceof Array){
24668 Roo.each(this.selections, function(s) {
24669 this.unselect(s, nodeInfo);
24673 var node = this.getNode(nodeInfo);
24674 if(!node || !this.isSelected(node)){
24675 Roo.log("not selected");
24676 return; // not selected.
24680 Roo.each(this.selections, function(s) {
24682 Roo.fly(node).removeClass(this.selectedClass);
24689 this.selections= ns;
24690 this.fireEvent("selectionchange", this, this.selections);
24694 * Gets a template node.
24695 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24696 * @return {HTMLElement} The node or null if it wasn't found
24698 getNode : function(nodeInfo){
24699 if(typeof nodeInfo == "string"){
24700 return document.getElementById(nodeInfo);
24701 }else if(typeof nodeInfo == "number"){
24702 return this.nodes[nodeInfo];
24708 * Gets a range template nodes.
24709 * @param {Number} startIndex
24710 * @param {Number} endIndex
24711 * @return {Array} An array of nodes
24713 getNodes : function(start, end){
24714 var ns = this.nodes;
24715 start = start || 0;
24716 end = typeof end == "undefined" ? ns.length - 1 : end;
24719 for(var i = start; i <= end; i++){
24723 for(var i = start; i >= end; i--){
24731 * Finds the index of the passed node
24732 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24733 * @return {Number} The index of the node or -1
24735 indexOf : function(node){
24736 node = this.getNode(node);
24737 if(typeof node.nodeIndex == "number"){
24738 return node.nodeIndex;
24740 var ns = this.nodes;
24741 for(var i = 0, len = ns.length; i < len; i++){
24751 * Ext JS Library 1.1.1
24752 * Copyright(c) 2006-2007, Ext JS, LLC.
24754 * Originally Released Under LGPL - original licence link has changed is not relivant.
24757 * <script type="text/javascript">
24761 * @class Roo.JsonView
24762 * @extends Roo.View
24763 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24765 var view = new Roo.JsonView({
24766 container: "my-element",
24767 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24772 // listen for node click?
24773 view.on("click", function(vw, index, node, e){
24774 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24777 // direct load of JSON data
24778 view.load("foobar.php");
24780 // Example from my blog list
24781 var tpl = new Roo.Template(
24782 '<div class="entry">' +
24783 '<a class="entry-title" href="{link}">{title}</a>' +
24784 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24785 "</div><hr />"
24788 var moreView = new Roo.JsonView({
24789 container : "entry-list",
24793 moreView.on("beforerender", this.sortEntries, this);
24795 url: "/blog/get-posts.php",
24796 params: "allposts=true",
24797 text: "Loading Blog Entries..."
24801 * Note: old code is supported with arguments : (container, template, config)
24805 * Create a new JsonView
24807 * @param {Object} config The config object
24810 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24813 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24815 var um = this.el.getUpdateManager();
24816 um.setRenderer(this);
24817 um.on("update", this.onLoad, this);
24818 um.on("failure", this.onLoadException, this);
24821 * @event beforerender
24822 * Fires before rendering of the downloaded JSON data.
24823 * @param {Roo.JsonView} this
24824 * @param {Object} data The JSON data loaded
24828 * Fires when data is loaded.
24829 * @param {Roo.JsonView} this
24830 * @param {Object} data The JSON data loaded
24831 * @param {Object} response The raw Connect response object
24834 * @event loadexception
24835 * Fires when loading fails.
24836 * @param {Roo.JsonView} this
24837 * @param {Object} response The raw Connect response object
24840 'beforerender' : true,
24842 'loadexception' : true
24845 Roo.extend(Roo.JsonView, Roo.View, {
24847 * @type {String} The root property in the loaded JSON object that contains the data
24852 * Refreshes the view.
24854 refresh : function(){
24855 this.clearSelections();
24856 this.el.update("");
24858 var o = this.jsonData;
24859 if(o && o.length > 0){
24860 for(var i = 0, len = o.length; i < len; i++){
24861 var data = this.prepareData(o[i], i, o);
24862 html[html.length] = this.tpl.apply(data);
24865 html.push(this.emptyText);
24867 this.el.update(html.join(""));
24868 this.nodes = this.el.dom.childNodes;
24869 this.updateIndexes(0);
24873 * 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.
24874 * @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:
24877 url: "your-url.php",
24878 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24879 callback: yourFunction,
24880 scope: yourObject, //(optional scope)
24883 text: "Loading...",
24888 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24889 * 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.
24890 * @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}
24891 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24892 * @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.
24895 var um = this.el.getUpdateManager();
24896 um.update.apply(um, arguments);
24899 render : function(el, response){
24900 this.clearSelections();
24901 this.el.update("");
24904 o = Roo.util.JSON.decode(response.responseText);
24907 o = o[this.jsonRoot];
24912 * The current JSON data or null
24915 this.beforeRender();
24920 * Get the number of records in the current JSON dataset
24923 getCount : function(){
24924 return this.jsonData ? this.jsonData.length : 0;
24928 * Returns the JSON object for the specified node(s)
24929 * @param {HTMLElement/Array} node The node or an array of nodes
24930 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24931 * you get the JSON object for the node
24933 getNodeData : function(node){
24934 if(node instanceof Array){
24936 for(var i = 0, len = node.length; i < len; i++){
24937 data.push(this.getNodeData(node[i]));
24941 return this.jsonData[this.indexOf(node)] || null;
24944 beforeRender : function(){
24945 this.snapshot = this.jsonData;
24947 this.sort.apply(this, this.sortInfo);
24949 this.fireEvent("beforerender", this, this.jsonData);
24952 onLoad : function(el, o){
24953 this.fireEvent("load", this, this.jsonData, o);
24956 onLoadException : function(el, o){
24957 this.fireEvent("loadexception", this, o);
24961 * Filter the data by a specific property.
24962 * @param {String} property A property on your JSON objects
24963 * @param {String/RegExp} value Either string that the property values
24964 * should start with, or a RegExp to test against the property
24966 filter : function(property, value){
24969 var ss = this.snapshot;
24970 if(typeof value == "string"){
24971 var vlen = value.length;
24973 this.clearFilter();
24976 value = value.toLowerCase();
24977 for(var i = 0, len = ss.length; i < len; i++){
24979 if(o[property].substr(0, vlen).toLowerCase() == value){
24983 } else if(value.exec){ // regex?
24984 for(var i = 0, len = ss.length; i < len; i++){
24986 if(value.test(o[property])){
24993 this.jsonData = data;
24999 * Filter by a function. The passed function will be called with each
25000 * object in the current dataset. If the function returns true the value is kept,
25001 * otherwise it is filtered.
25002 * @param {Function} fn
25003 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25005 filterBy : function(fn, scope){
25008 var ss = this.snapshot;
25009 for(var i = 0, len = ss.length; i < len; i++){
25011 if(fn.call(scope || this, o)){
25015 this.jsonData = data;
25021 * Clears the current filter.
25023 clearFilter : function(){
25024 if(this.snapshot && this.jsonData != this.snapshot){
25025 this.jsonData = this.snapshot;
25032 * Sorts the data for this view and refreshes it.
25033 * @param {String} property A property on your JSON objects to sort on
25034 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25035 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25037 sort : function(property, dir, sortType){
25038 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25041 var dsc = dir && dir.toLowerCase() == "desc";
25042 var f = function(o1, o2){
25043 var v1 = sortType ? sortType(o1[p]) : o1[p];
25044 var v2 = sortType ? sortType(o2[p]) : o2[p];
25047 return dsc ? +1 : -1;
25048 } else if(v1 > v2){
25049 return dsc ? -1 : +1;
25054 this.jsonData.sort(f);
25056 if(this.jsonData != this.snapshot){
25057 this.snapshot.sort(f);
25063 * Ext JS Library 1.1.1
25064 * Copyright(c) 2006-2007, Ext JS, LLC.
25066 * Originally Released Under LGPL - original licence link has changed is not relivant.
25069 * <script type="text/javascript">
25074 * @class Roo.ColorPalette
25075 * @extends Roo.Component
25076 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25077 * Here's an example of typical usage:
25079 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25080 cp.render('my-div');
25082 cp.on('select', function(palette, selColor){
25083 // do something with selColor
25087 * Create a new ColorPalette
25088 * @param {Object} config The config object
25090 Roo.ColorPalette = function(config){
25091 Roo.ColorPalette.superclass.constructor.call(this, config);
25095 * Fires when a color is selected
25096 * @param {ColorPalette} this
25097 * @param {String} color The 6-digit color hex code (without the # symbol)
25103 this.on("select", this.handler, this.scope, true);
25106 Roo.extend(Roo.ColorPalette, Roo.Component, {
25108 * @cfg {String} itemCls
25109 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25111 itemCls : "x-color-palette",
25113 * @cfg {String} value
25114 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25115 * the hex codes are case-sensitive.
25118 clickEvent:'click',
25120 ctype: "Roo.ColorPalette",
25123 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25125 allowReselect : false,
25128 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25129 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25130 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25131 * of colors with the width setting until the box is symmetrical.</p>
25132 * <p>You can override individual colors if needed:</p>
25134 var cp = new Roo.ColorPalette();
25135 cp.colors[0] = "FF0000"; // change the first box to red
25138 Or you can provide a custom array of your own for complete control:
25140 var cp = new Roo.ColorPalette();
25141 cp.colors = ["000000", "993300", "333300"];
25146 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25147 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25148 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25149 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25150 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25154 onRender : function(container, position){
25155 var t = new Roo.MasterTemplate(
25156 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25158 var c = this.colors;
25159 for(var i = 0, len = c.length; i < len; i++){
25162 var el = document.createElement("div");
25163 el.className = this.itemCls;
25165 container.dom.insertBefore(el, position);
25166 this.el = Roo.get(el);
25167 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25168 if(this.clickEvent != 'click'){
25169 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25174 afterRender : function(){
25175 Roo.ColorPalette.superclass.afterRender.call(this);
25177 var s = this.value;
25184 handleClick : function(e, t){
25185 e.preventDefault();
25186 if(!this.disabled){
25187 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25188 this.select(c.toUpperCase());
25193 * Selects the specified color in the palette (fires the select event)
25194 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25196 select : function(color){
25197 color = color.replace("#", "");
25198 if(color != this.value || this.allowReselect){
25201 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25203 el.child("a.color-"+color).addClass("x-color-palette-sel");
25204 this.value = color;
25205 this.fireEvent("select", this, color);
25210 * Ext JS Library 1.1.1
25211 * Copyright(c) 2006-2007, Ext JS, LLC.
25213 * Originally Released Under LGPL - original licence link has changed is not relivant.
25216 * <script type="text/javascript">
25220 * @class Roo.DatePicker
25221 * @extends Roo.Component
25222 * Simple date picker class.
25224 * Create a new DatePicker
25225 * @param {Object} config The config object
25227 Roo.DatePicker = function(config){
25228 Roo.DatePicker.superclass.constructor.call(this, config);
25230 this.value = config && config.value ?
25231 config.value.clearTime() : new Date().clearTime();
25236 * Fires when a date is selected
25237 * @param {DatePicker} this
25238 * @param {Date} date The selected date
25242 * @event monthchange
25243 * Fires when the displayed month changes
25244 * @param {DatePicker} this
25245 * @param {Date} date The selected month
25247 'monthchange': true
25251 this.on("select", this.handler, this.scope || this);
25253 // build the disabledDatesRE
25254 if(!this.disabledDatesRE && this.disabledDates){
25255 var dd = this.disabledDates;
25257 for(var i = 0; i < dd.length; i++){
25259 if(i != dd.length-1) re += "|";
25261 this.disabledDatesRE = new RegExp(re + ")");
25265 Roo.extend(Roo.DatePicker, Roo.Component, {
25267 * @cfg {String} todayText
25268 * The text to display on the button that selects the current date (defaults to "Today")
25270 todayText : "Today",
25272 * @cfg {String} okText
25273 * The text to display on the ok button
25275 okText : " OK ", //   to give the user extra clicking room
25277 * @cfg {String} cancelText
25278 * The text to display on the cancel button
25280 cancelText : "Cancel",
25282 * @cfg {String} todayTip
25283 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25285 todayTip : "{0} (Spacebar)",
25287 * @cfg {Date} minDate
25288 * Minimum allowable date (JavaScript date object, defaults to null)
25292 * @cfg {Date} maxDate
25293 * Maximum allowable date (JavaScript date object, defaults to null)
25297 * @cfg {String} minText
25298 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25300 minText : "This date is before the minimum date",
25302 * @cfg {String} maxText
25303 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25305 maxText : "This date is after the maximum date",
25307 * @cfg {String} format
25308 * The default date format string which can be overriden for localization support. The format must be
25309 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25313 * @cfg {Array} disabledDays
25314 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25316 disabledDays : null,
25318 * @cfg {String} disabledDaysText
25319 * The tooltip to display when the date falls on a disabled day (defaults to "")
25321 disabledDaysText : "",
25323 * @cfg {RegExp} disabledDatesRE
25324 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25326 disabledDatesRE : null,
25328 * @cfg {String} disabledDatesText
25329 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25331 disabledDatesText : "",
25333 * @cfg {Boolean} constrainToViewport
25334 * True to constrain the date picker to the viewport (defaults to true)
25336 constrainToViewport : true,
25338 * @cfg {Array} monthNames
25339 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25341 monthNames : Date.monthNames,
25343 * @cfg {Array} dayNames
25344 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25346 dayNames : Date.dayNames,
25348 * @cfg {String} nextText
25349 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25351 nextText: 'Next Month (Control+Right)',
25353 * @cfg {String} prevText
25354 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25356 prevText: 'Previous Month (Control+Left)',
25358 * @cfg {String} monthYearText
25359 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25361 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25363 * @cfg {Number} startDay
25364 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25368 * @cfg {Bool} showClear
25369 * Show a clear button (usefull for date form elements that can be blank.)
25375 * Sets the value of the date field
25376 * @param {Date} value The date to set
25378 setValue : function(value){
25379 var old = this.value;
25381 if (typeof(value) == 'string') {
25383 value = Date.parseDate(value, this.format);
25386 value = new Date();
25389 this.value = value.clearTime(true);
25391 this.update(this.value);
25396 * Gets the current selected value of the date field
25397 * @return {Date} The selected date
25399 getValue : function(){
25404 focus : function(){
25406 this.update(this.activeDate);
25411 onRender : function(container, position){
25414 '<table cellspacing="0">',
25415 '<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>',
25416 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
25417 var dn = this.dayNames;
25418 for(var i = 0; i < 7; i++){
25419 var d = this.startDay+i;
25423 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
25425 m[m.length] = "</tr></thead><tbody><tr>";
25426 for(var i = 0; i < 42; i++) {
25427 if(i % 7 == 0 && i != 0){
25428 m[m.length] = "</tr><tr>";
25430 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
25432 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
25433 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
25435 var el = document.createElement("div");
25436 el.className = "x-date-picker";
25437 el.innerHTML = m.join("");
25439 container.dom.insertBefore(el, position);
25441 this.el = Roo.get(el);
25442 this.eventEl = Roo.get(el.firstChild);
25444 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
25445 handler: this.showPrevMonth,
25447 preventDefault:true,
25451 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
25452 handler: this.showNextMonth,
25454 preventDefault:true,
25458 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
25460 this.monthPicker = this.el.down('div.x-date-mp');
25461 this.monthPicker.enableDisplayMode('block');
25463 var kn = new Roo.KeyNav(this.eventEl, {
25464 "left" : function(e){
25466 this.showPrevMonth() :
25467 this.update(this.activeDate.add("d", -1));
25470 "right" : function(e){
25472 this.showNextMonth() :
25473 this.update(this.activeDate.add("d", 1));
25476 "up" : function(e){
25478 this.showNextYear() :
25479 this.update(this.activeDate.add("d", -7));
25482 "down" : function(e){
25484 this.showPrevYear() :
25485 this.update(this.activeDate.add("d", 7));
25488 "pageUp" : function(e){
25489 this.showNextMonth();
25492 "pageDown" : function(e){
25493 this.showPrevMonth();
25496 "enter" : function(e){
25497 e.stopPropagation();
25504 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
25506 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
25508 this.el.unselectable();
25510 this.cells = this.el.select("table.x-date-inner tbody td");
25511 this.textNodes = this.el.query("table.x-date-inner tbody span");
25513 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
25515 tooltip: this.monthYearText
25518 this.mbtn.on('click', this.showMonthPicker, this);
25519 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
25522 var today = (new Date()).dateFormat(this.format);
25524 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
25525 if (this.showClear) {
25526 baseTb.add( new Roo.Toolbar.Fill());
25529 text: String.format(this.todayText, today),
25530 tooltip: String.format(this.todayTip, today),
25531 handler: this.selectToday,
25535 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
25538 if (this.showClear) {
25540 baseTb.add( new Roo.Toolbar.Fill());
25543 cls: 'x-btn-icon x-btn-clear',
25544 handler: function() {
25546 this.fireEvent("select", this, '');
25556 this.update(this.value);
25559 createMonthPicker : function(){
25560 if(!this.monthPicker.dom.firstChild){
25561 var buf = ['<table border="0" cellspacing="0">'];
25562 for(var i = 0; i < 6; i++){
25564 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
25565 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
25567 '<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>' :
25568 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
25572 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
25574 '</button><button type="button" class="x-date-mp-cancel">',
25576 '</button></td></tr>',
25579 this.monthPicker.update(buf.join(''));
25580 this.monthPicker.on('click', this.onMonthClick, this);
25581 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
25583 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
25584 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
25586 this.mpMonths.each(function(m, a, i){
25589 m.dom.xmonth = 5 + Math.round(i * .5);
25591 m.dom.xmonth = Math.round((i-1) * .5);
25597 showMonthPicker : function(){
25598 this.createMonthPicker();
25599 var size = this.el.getSize();
25600 this.monthPicker.setSize(size);
25601 this.monthPicker.child('table').setSize(size);
25603 this.mpSelMonth = (this.activeDate || this.value).getMonth();
25604 this.updateMPMonth(this.mpSelMonth);
25605 this.mpSelYear = (this.activeDate || this.value).getFullYear();
25606 this.updateMPYear(this.mpSelYear);
25608 this.monthPicker.slideIn('t', {duration:.2});
25611 updateMPYear : function(y){
25613 var ys = this.mpYears.elements;
25614 for(var i = 1; i <= 10; i++){
25615 var td = ys[i-1], y2;
25617 y2 = y + Math.round(i * .5);
25618 td.firstChild.innerHTML = y2;
25621 y2 = y - (5-Math.round(i * .5));
25622 td.firstChild.innerHTML = y2;
25625 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25629 updateMPMonth : function(sm){
25630 this.mpMonths.each(function(m, a, i){
25631 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25635 selectMPMonth: function(m){
25639 onMonthClick : function(e, t){
25641 var el = new Roo.Element(t), pn;
25642 if(el.is('button.x-date-mp-cancel')){
25643 this.hideMonthPicker();
25645 else if(el.is('button.x-date-mp-ok')){
25646 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25647 this.hideMonthPicker();
25649 else if(pn = el.up('td.x-date-mp-month', 2)){
25650 this.mpMonths.removeClass('x-date-mp-sel');
25651 pn.addClass('x-date-mp-sel');
25652 this.mpSelMonth = pn.dom.xmonth;
25654 else if(pn = el.up('td.x-date-mp-year', 2)){
25655 this.mpYears.removeClass('x-date-mp-sel');
25656 pn.addClass('x-date-mp-sel');
25657 this.mpSelYear = pn.dom.xyear;
25659 else if(el.is('a.x-date-mp-prev')){
25660 this.updateMPYear(this.mpyear-10);
25662 else if(el.is('a.x-date-mp-next')){
25663 this.updateMPYear(this.mpyear+10);
25667 onMonthDblClick : function(e, t){
25669 var el = new Roo.Element(t), pn;
25670 if(pn = el.up('td.x-date-mp-month', 2)){
25671 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25672 this.hideMonthPicker();
25674 else if(pn = el.up('td.x-date-mp-year', 2)){
25675 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25676 this.hideMonthPicker();
25680 hideMonthPicker : function(disableAnim){
25681 if(this.monthPicker){
25682 if(disableAnim === true){
25683 this.monthPicker.hide();
25685 this.monthPicker.slideOut('t', {duration:.2});
25691 showPrevMonth : function(e){
25692 this.update(this.activeDate.add("mo", -1));
25696 showNextMonth : function(e){
25697 this.update(this.activeDate.add("mo", 1));
25701 showPrevYear : function(){
25702 this.update(this.activeDate.add("y", -1));
25706 showNextYear : function(){
25707 this.update(this.activeDate.add("y", 1));
25711 handleMouseWheel : function(e){
25712 var delta = e.getWheelDelta();
25714 this.showPrevMonth();
25716 } else if(delta < 0){
25717 this.showNextMonth();
25723 handleDateClick : function(e, t){
25725 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25726 this.setValue(new Date(t.dateValue));
25727 this.fireEvent("select", this, this.value);
25732 selectToday : function(){
25733 this.setValue(new Date().clearTime());
25734 this.fireEvent("select", this, this.value);
25738 update : function(date)
25740 var vd = this.activeDate;
25741 this.activeDate = date;
25743 var t = date.getTime();
25744 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25745 this.cells.removeClass("x-date-selected");
25746 this.cells.each(function(c){
25747 if(c.dom.firstChild.dateValue == t){
25748 c.addClass("x-date-selected");
25749 setTimeout(function(){
25750 try{c.dom.firstChild.focus();}catch(e){}
25759 var days = date.getDaysInMonth();
25760 var firstOfMonth = date.getFirstDateOfMonth();
25761 var startingPos = firstOfMonth.getDay()-this.startDay;
25763 if(startingPos <= this.startDay){
25767 var pm = date.add("mo", -1);
25768 var prevStart = pm.getDaysInMonth()-startingPos;
25770 var cells = this.cells.elements;
25771 var textEls = this.textNodes;
25772 days += startingPos;
25774 // convert everything to numbers so it's fast
25775 var day = 86400000;
25776 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25777 var today = new Date().clearTime().getTime();
25778 var sel = date.clearTime().getTime();
25779 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25780 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25781 var ddMatch = this.disabledDatesRE;
25782 var ddText = this.disabledDatesText;
25783 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25784 var ddaysText = this.disabledDaysText;
25785 var format = this.format;
25787 var setCellClass = function(cal, cell){
25789 var t = d.getTime();
25790 cell.firstChild.dateValue = t;
25792 cell.className += " x-date-today";
25793 cell.title = cal.todayText;
25796 cell.className += " x-date-selected";
25797 setTimeout(function(){
25798 try{cell.firstChild.focus();}catch(e){}
25803 cell.className = " x-date-disabled";
25804 cell.title = cal.minText;
25808 cell.className = " x-date-disabled";
25809 cell.title = cal.maxText;
25813 if(ddays.indexOf(d.getDay()) != -1){
25814 cell.title = ddaysText;
25815 cell.className = " x-date-disabled";
25818 if(ddMatch && format){
25819 var fvalue = d.dateFormat(format);
25820 if(ddMatch.test(fvalue)){
25821 cell.title = ddText.replace("%0", fvalue);
25822 cell.className = " x-date-disabled";
25828 for(; i < startingPos; i++) {
25829 textEls[i].innerHTML = (++prevStart);
25830 d.setDate(d.getDate()+1);
25831 cells[i].className = "x-date-prevday";
25832 setCellClass(this, cells[i]);
25834 for(; i < days; i++){
25835 intDay = i - startingPos + 1;
25836 textEls[i].innerHTML = (intDay);
25837 d.setDate(d.getDate()+1);
25838 cells[i].className = "x-date-active";
25839 setCellClass(this, cells[i]);
25842 for(; i < 42; i++) {
25843 textEls[i].innerHTML = (++extraDays);
25844 d.setDate(d.getDate()+1);
25845 cells[i].className = "x-date-nextday";
25846 setCellClass(this, cells[i]);
25849 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25850 this.fireEvent('monthchange', this, date);
25852 if(!this.internalRender){
25853 var main = this.el.dom.firstChild;
25854 var w = main.offsetWidth;
25855 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25856 Roo.fly(main).setWidth(w);
25857 this.internalRender = true;
25858 // opera does not respect the auto grow header center column
25859 // then, after it gets a width opera refuses to recalculate
25860 // without a second pass
25861 if(Roo.isOpera && !this.secondPass){
25862 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25863 this.secondPass = true;
25864 this.update.defer(10, this, [date]);
25872 * Ext JS Library 1.1.1
25873 * Copyright(c) 2006-2007, Ext JS, LLC.
25875 * Originally Released Under LGPL - original licence link has changed is not relivant.
25878 * <script type="text/javascript">
25881 * @class Roo.TabPanel
25882 * @extends Roo.util.Observable
25883 * A lightweight tab container.
25887 // basic tabs 1, built from existing content
25888 var tabs = new Roo.TabPanel("tabs1");
25889 tabs.addTab("script", "View Script");
25890 tabs.addTab("markup", "View Markup");
25891 tabs.activate("script");
25893 // more advanced tabs, built from javascript
25894 var jtabs = new Roo.TabPanel("jtabs");
25895 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25897 // set up the UpdateManager
25898 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25899 var updater = tab2.getUpdateManager();
25900 updater.setDefaultUrl("ajax1.htm");
25901 tab2.on('activate', updater.refresh, updater, true);
25903 // Use setUrl for Ajax loading
25904 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25905 tab3.setUrl("ajax2.htm", null, true);
25908 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25911 jtabs.activate("jtabs-1");
25914 * Create a new TabPanel.
25915 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25916 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25918 Roo.TabPanel = function(container, config){
25920 * The container element for this TabPanel.
25921 * @type Roo.Element
25923 this.el = Roo.get(container, true);
25925 if(typeof config == "boolean"){
25926 this.tabPosition = config ? "bottom" : "top";
25928 Roo.apply(this, config);
25931 if(this.tabPosition == "bottom"){
25932 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25933 this.el.addClass("x-tabs-bottom");
25935 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25936 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25937 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25939 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25941 if(this.tabPosition != "bottom"){
25942 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25943 * @type Roo.Element
25945 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25946 this.el.addClass("x-tabs-top");
25950 this.bodyEl.setStyle("position", "relative");
25952 this.active = null;
25953 this.activateDelegate = this.activate.createDelegate(this);
25958 * Fires when the active tab changes
25959 * @param {Roo.TabPanel} this
25960 * @param {Roo.TabPanelItem} activePanel The new active tab
25964 * @event beforetabchange
25965 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25966 * @param {Roo.TabPanel} this
25967 * @param {Object} e Set cancel to true on this object to cancel the tab change
25968 * @param {Roo.TabPanelItem} tab The tab being changed to
25970 "beforetabchange" : true
25973 Roo.EventManager.onWindowResize(this.onResize, this);
25974 this.cpad = this.el.getPadding("lr");
25975 this.hiddenCount = 0;
25978 // toolbar on the tabbar support...
25979 if (this.toolbar) {
25980 var tcfg = this.toolbar;
25981 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25982 this.toolbar = new Roo.Toolbar(tcfg);
25983 if (Roo.isSafari) {
25984 var tbl = tcfg.container.child('table', true);
25985 tbl.setAttribute('width', '100%');
25992 Roo.TabPanel.superclass.constructor.call(this);
25995 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25997 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25999 tabPosition : "top",
26001 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26003 currentTabWidth : 0,
26005 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26009 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26013 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26015 preferredTabWidth : 175,
26017 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26019 resizeTabs : false,
26021 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26023 monitorResize : true,
26025 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26030 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26031 * @param {String} id The id of the div to use <b>or create</b>
26032 * @param {String} text The text for the tab
26033 * @param {String} content (optional) Content to put in the TabPanelItem body
26034 * @param {Boolean} closable (optional) True to create a close icon on the tab
26035 * @return {Roo.TabPanelItem} The created TabPanelItem
26037 addTab : function(id, text, content, closable){
26038 var item = new Roo.TabPanelItem(this, id, text, closable);
26039 this.addTabItem(item);
26041 item.setContent(content);
26047 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26048 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26049 * @return {Roo.TabPanelItem}
26051 getTab : function(id){
26052 return this.items[id];
26056 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26057 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26059 hideTab : function(id){
26060 var t = this.items[id];
26063 this.hiddenCount++;
26064 this.autoSizeTabs();
26069 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26070 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26072 unhideTab : function(id){
26073 var t = this.items[id];
26075 t.setHidden(false);
26076 this.hiddenCount--;
26077 this.autoSizeTabs();
26082 * Adds an existing {@link Roo.TabPanelItem}.
26083 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26085 addTabItem : function(item){
26086 this.items[item.id] = item;
26087 this.items.push(item);
26088 if(this.resizeTabs){
26089 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26090 this.autoSizeTabs();
26097 * Removes a {@link Roo.TabPanelItem}.
26098 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26100 removeTab : function(id){
26101 var items = this.items;
26102 var tab = items[id];
26103 if(!tab) { return; }
26104 var index = items.indexOf(tab);
26105 if(this.active == tab && items.length > 1){
26106 var newTab = this.getNextAvailable(index);
26111 this.stripEl.dom.removeChild(tab.pnode.dom);
26112 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26113 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26115 items.splice(index, 1);
26116 delete this.items[tab.id];
26117 tab.fireEvent("close", tab);
26118 tab.purgeListeners();
26119 this.autoSizeTabs();
26122 getNextAvailable : function(start){
26123 var items = this.items;
26125 // look for a next tab that will slide over to
26126 // replace the one being removed
26127 while(index < items.length){
26128 var item = items[++index];
26129 if(item && !item.isHidden()){
26133 // if one isn't found select the previous tab (on the left)
26136 var item = items[--index];
26137 if(item && !item.isHidden()){
26145 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26146 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26148 disableTab : function(id){
26149 var tab = this.items[id];
26150 if(tab && this.active != tab){
26156 * Enables a {@link Roo.TabPanelItem} that is disabled.
26157 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26159 enableTab : function(id){
26160 var tab = this.items[id];
26165 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26166 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26167 * @return {Roo.TabPanelItem} The TabPanelItem.
26169 activate : function(id){
26170 var tab = this.items[id];
26174 if(tab == this.active || tab.disabled){
26178 this.fireEvent("beforetabchange", this, e, tab);
26179 if(e.cancel !== true && !tab.disabled){
26181 this.active.hide();
26183 this.active = this.items[id];
26184 this.active.show();
26185 this.fireEvent("tabchange", this, this.active);
26191 * Gets the active {@link Roo.TabPanelItem}.
26192 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26194 getActiveTab : function(){
26195 return this.active;
26199 * Updates the tab body element to fit the height of the container element
26200 * for overflow scrolling
26201 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26203 syncHeight : function(targetHeight){
26204 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26205 var bm = this.bodyEl.getMargins();
26206 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26207 this.bodyEl.setHeight(newHeight);
26211 onResize : function(){
26212 if(this.monitorResize){
26213 this.autoSizeTabs();
26218 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26220 beginUpdate : function(){
26221 this.updating = true;
26225 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26227 endUpdate : function(){
26228 this.updating = false;
26229 this.autoSizeTabs();
26233 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26235 autoSizeTabs : function(){
26236 var count = this.items.length;
26237 var vcount = count - this.hiddenCount;
26238 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26239 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26240 var availWidth = Math.floor(w / vcount);
26241 var b = this.stripBody;
26242 if(b.getWidth() > w){
26243 var tabs = this.items;
26244 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26245 if(availWidth < this.minTabWidth){
26246 /*if(!this.sleft){ // incomplete scrolling code
26247 this.createScrollButtons();
26250 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26253 if(this.currentTabWidth < this.preferredTabWidth){
26254 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26260 * Returns the number of tabs in this TabPanel.
26263 getCount : function(){
26264 return this.items.length;
26268 * Resizes all the tabs to the passed width
26269 * @param {Number} The new width
26271 setTabWidth : function(width){
26272 this.currentTabWidth = width;
26273 for(var i = 0, len = this.items.length; i < len; i++) {
26274 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26279 * Destroys this TabPanel
26280 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26282 destroy : function(removeEl){
26283 Roo.EventManager.removeResizeListener(this.onResize, this);
26284 for(var i = 0, len = this.items.length; i < len; i++){
26285 this.items[i].purgeListeners();
26287 if(removeEl === true){
26288 this.el.update("");
26295 * @class Roo.TabPanelItem
26296 * @extends Roo.util.Observable
26297 * Represents an individual item (tab plus body) in a TabPanel.
26298 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26299 * @param {String} id The id of this TabPanelItem
26300 * @param {String} text The text for the tab of this TabPanelItem
26301 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26303 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26305 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26306 * @type Roo.TabPanel
26308 this.tabPanel = tabPanel;
26310 * The id for this TabPanelItem
26315 this.disabled = false;
26319 this.loaded = false;
26320 this.closable = closable;
26323 * The body element for this TabPanelItem.
26324 * @type Roo.Element
26326 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26327 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26328 this.bodyEl.setStyle("display", "block");
26329 this.bodyEl.setStyle("zoom", "1");
26332 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26334 this.el = Roo.get(els.el, true);
26335 this.inner = Roo.get(els.inner, true);
26336 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26337 this.pnode = Roo.get(els.el.parentNode, true);
26338 this.el.on("mousedown", this.onTabMouseDown, this);
26339 this.el.on("click", this.onTabClick, this);
26342 var c = Roo.get(els.close, true);
26343 c.dom.title = this.closeText;
26344 c.addClassOnOver("close-over");
26345 c.on("click", this.closeClick, this);
26351 * Fires when this tab becomes the active tab.
26352 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26353 * @param {Roo.TabPanelItem} this
26357 * @event beforeclose
26358 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26359 * @param {Roo.TabPanelItem} this
26360 * @param {Object} e Set cancel to true on this object to cancel the close.
26362 "beforeclose": true,
26365 * Fires when this tab is closed.
26366 * @param {Roo.TabPanelItem} this
26370 * @event deactivate
26371 * Fires when this tab is no longer the active tab.
26372 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26373 * @param {Roo.TabPanelItem} this
26375 "deactivate" : true
26377 this.hidden = false;
26379 Roo.TabPanelItem.superclass.constructor.call(this);
26382 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26383 purgeListeners : function(){
26384 Roo.util.Observable.prototype.purgeListeners.call(this);
26385 this.el.removeAllListeners();
26388 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26391 this.pnode.addClass("on");
26394 this.tabPanel.stripWrap.repaint();
26396 this.fireEvent("activate", this.tabPanel, this);
26400 * Returns true if this tab is the active tab.
26401 * @return {Boolean}
26403 isActive : function(){
26404 return this.tabPanel.getActiveTab() == this;
26408 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
26411 this.pnode.removeClass("on");
26413 this.fireEvent("deactivate", this.tabPanel, this);
26416 hideAction : function(){
26417 this.bodyEl.hide();
26418 this.bodyEl.setStyle("position", "absolute");
26419 this.bodyEl.setLeft("-20000px");
26420 this.bodyEl.setTop("-20000px");
26423 showAction : function(){
26424 this.bodyEl.setStyle("position", "relative");
26425 this.bodyEl.setTop("");
26426 this.bodyEl.setLeft("");
26427 this.bodyEl.show();
26431 * Set the tooltip for the tab.
26432 * @param {String} tooltip The tab's tooltip
26434 setTooltip : function(text){
26435 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
26436 this.textEl.dom.qtip = text;
26437 this.textEl.dom.removeAttribute('title');
26439 this.textEl.dom.title = text;
26443 onTabClick : function(e){
26444 e.preventDefault();
26445 this.tabPanel.activate(this.id);
26448 onTabMouseDown : function(e){
26449 e.preventDefault();
26450 this.tabPanel.activate(this.id);
26453 getWidth : function(){
26454 return this.inner.getWidth();
26457 setWidth : function(width){
26458 var iwidth = width - this.pnode.getPadding("lr");
26459 this.inner.setWidth(iwidth);
26460 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
26461 this.pnode.setWidth(width);
26465 * Show or hide the tab
26466 * @param {Boolean} hidden True to hide or false to show.
26468 setHidden : function(hidden){
26469 this.hidden = hidden;
26470 this.pnode.setStyle("display", hidden ? "none" : "");
26474 * Returns true if this tab is "hidden"
26475 * @return {Boolean}
26477 isHidden : function(){
26478 return this.hidden;
26482 * Returns the text for this tab
26485 getText : function(){
26489 autoSize : function(){
26490 //this.el.beginMeasure();
26491 this.textEl.setWidth(1);
26492 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
26493 //this.el.endMeasure();
26497 * Sets the text for the tab (Note: this also sets the tooltip text)
26498 * @param {String} text The tab's text and tooltip
26500 setText : function(text){
26502 this.textEl.update(text);
26503 this.setTooltip(text);
26504 if(!this.tabPanel.resizeTabs){
26509 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
26511 activate : function(){
26512 this.tabPanel.activate(this.id);
26516 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
26518 disable : function(){
26519 if(this.tabPanel.active != this){
26520 this.disabled = true;
26521 this.pnode.addClass("disabled");
26526 * Enables this TabPanelItem if it was previously disabled.
26528 enable : function(){
26529 this.disabled = false;
26530 this.pnode.removeClass("disabled");
26534 * Sets the content for this TabPanelItem.
26535 * @param {String} content The content
26536 * @param {Boolean} loadScripts true to look for and load scripts
26538 setContent : function(content, loadScripts){
26539 this.bodyEl.update(content, loadScripts);
26543 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
26544 * @return {Roo.UpdateManager} The UpdateManager
26546 getUpdateManager : function(){
26547 return this.bodyEl.getUpdateManager();
26551 * Set a URL to be used to load the content for this TabPanelItem.
26552 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
26553 * @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)
26554 * @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)
26555 * @return {Roo.UpdateManager} The UpdateManager
26557 setUrl : function(url, params, loadOnce){
26558 if(this.refreshDelegate){
26559 this.un('activate', this.refreshDelegate);
26561 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
26562 this.on("activate", this.refreshDelegate);
26563 return this.bodyEl.getUpdateManager();
26567 _handleRefresh : function(url, params, loadOnce){
26568 if(!loadOnce || !this.loaded){
26569 var updater = this.bodyEl.getUpdateManager();
26570 updater.update(url, params, this._setLoaded.createDelegate(this));
26575 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
26576 * Will fail silently if the setUrl method has not been called.
26577 * This does not activate the panel, just updates its content.
26579 refresh : function(){
26580 if(this.refreshDelegate){
26581 this.loaded = false;
26582 this.refreshDelegate();
26587 _setLoaded : function(){
26588 this.loaded = true;
26592 closeClick : function(e){
26595 this.fireEvent("beforeclose", this, o);
26596 if(o.cancel !== true){
26597 this.tabPanel.removeTab(this.id);
26601 * The text displayed in the tooltip for the close icon.
26604 closeText : "Close this tab"
26608 Roo.TabPanel.prototype.createStrip = function(container){
26609 var strip = document.createElement("div");
26610 strip.className = "x-tabs-wrap";
26611 container.appendChild(strip);
26615 Roo.TabPanel.prototype.createStripList = function(strip){
26616 // div wrapper for retard IE
26617 // returns the "tr" element.
26618 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26619 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26620 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26621 return strip.firstChild.firstChild.firstChild.firstChild;
26624 Roo.TabPanel.prototype.createBody = function(container){
26625 var body = document.createElement("div");
26626 Roo.id(body, "tab-body");
26627 Roo.fly(body).addClass("x-tabs-body");
26628 container.appendChild(body);
26632 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26633 var body = Roo.getDom(id);
26635 body = document.createElement("div");
26638 Roo.fly(body).addClass("x-tabs-item-body");
26639 bodyEl.insertBefore(body, bodyEl.firstChild);
26643 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26644 var td = document.createElement("td");
26645 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26646 //stripEl.appendChild(td);
26648 td.className = "x-tabs-closable";
26649 if(!this.closeTpl){
26650 this.closeTpl = new Roo.Template(
26651 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26652 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26653 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26656 var el = this.closeTpl.overwrite(td, {"text": text});
26657 var close = el.getElementsByTagName("div")[0];
26658 var inner = el.getElementsByTagName("em")[0];
26659 return {"el": el, "close": close, "inner": inner};
26662 this.tabTpl = new Roo.Template(
26663 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26664 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26667 var el = this.tabTpl.overwrite(td, {"text": text});
26668 var inner = el.getElementsByTagName("em")[0];
26669 return {"el": el, "inner": inner};
26673 * Ext JS Library 1.1.1
26674 * Copyright(c) 2006-2007, Ext JS, LLC.
26676 * Originally Released Under LGPL - original licence link has changed is not relivant.
26679 * <script type="text/javascript">
26683 * @class Roo.Button
26684 * @extends Roo.util.Observable
26685 * Simple Button class
26686 * @cfg {String} text The button text
26687 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26688 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26689 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26690 * @cfg {Object} scope The scope of the handler
26691 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26692 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26693 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26694 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26695 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26696 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26697 applies if enableToggle = true)
26698 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26699 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26700 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26702 * Create a new button
26703 * @param {Object} config The config object
26705 Roo.Button = function(renderTo, config)
26709 renderTo = config.renderTo || false;
26712 Roo.apply(this, config);
26716 * Fires when this button is clicked
26717 * @param {Button} this
26718 * @param {EventObject} e The click event
26723 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26724 * @param {Button} this
26725 * @param {Boolean} pressed
26730 * Fires when the mouse hovers over the button
26731 * @param {Button} this
26732 * @param {Event} e The event object
26734 'mouseover' : true,
26737 * Fires when the mouse exits the button
26738 * @param {Button} this
26739 * @param {Event} e The event object
26744 * Fires when the button is rendered
26745 * @param {Button} this
26750 this.menu = Roo.menu.MenuMgr.get(this.menu);
26752 // register listeners first!! - so render can be captured..
26753 Roo.util.Observable.call(this);
26755 this.render(renderTo);
26761 Roo.extend(Roo.Button, Roo.util.Observable, {
26767 * Read-only. True if this button is hidden
26772 * Read-only. True if this button is disabled
26777 * Read-only. True if this button is pressed (only if enableToggle = true)
26783 * @cfg {Number} tabIndex
26784 * The DOM tabIndex for this button (defaults to undefined)
26786 tabIndex : undefined,
26789 * @cfg {Boolean} enableToggle
26790 * True to enable pressed/not pressed toggling (defaults to false)
26792 enableToggle: false,
26794 * @cfg {Mixed} menu
26795 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26799 * @cfg {String} menuAlign
26800 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26802 menuAlign : "tl-bl?",
26805 * @cfg {String} iconCls
26806 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26808 iconCls : undefined,
26810 * @cfg {String} type
26811 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26816 menuClassTarget: 'tr',
26819 * @cfg {String} clickEvent
26820 * The type of event to map to the button's event handler (defaults to 'click')
26822 clickEvent : 'click',
26825 * @cfg {Boolean} handleMouseEvents
26826 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26828 handleMouseEvents : true,
26831 * @cfg {String} tooltipType
26832 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26834 tooltipType : 'qtip',
26837 * @cfg {String} cls
26838 * A CSS class to apply to the button's main element.
26842 * @cfg {Roo.Template} template (Optional)
26843 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26844 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26845 * require code modifications if required elements (e.g. a button) aren't present.
26849 render : function(renderTo){
26851 if(this.hideParent){
26852 this.parentEl = Roo.get(renderTo);
26854 if(!this.dhconfig){
26855 if(!this.template){
26856 if(!Roo.Button.buttonTemplate){
26857 // hideous table template
26858 Roo.Button.buttonTemplate = new Roo.Template(
26859 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26860 '<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>',
26861 "</tr></tbody></table>");
26863 this.template = Roo.Button.buttonTemplate;
26865 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26866 var btnEl = btn.child("button:first");
26867 btnEl.on('focus', this.onFocus, this);
26868 btnEl.on('blur', this.onBlur, this);
26870 btn.addClass(this.cls);
26873 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26876 btnEl.addClass(this.iconCls);
26878 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26881 if(this.tabIndex !== undefined){
26882 btnEl.dom.tabIndex = this.tabIndex;
26885 if(typeof this.tooltip == 'object'){
26886 Roo.QuickTips.tips(Roo.apply({
26890 btnEl.dom[this.tooltipType] = this.tooltip;
26894 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26898 this.el.dom.id = this.el.id = this.id;
26901 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26902 this.menu.on("show", this.onMenuShow, this);
26903 this.menu.on("hide", this.onMenuHide, this);
26905 btn.addClass("x-btn");
26906 if(Roo.isIE && !Roo.isIE7){
26907 this.autoWidth.defer(1, this);
26911 if(this.handleMouseEvents){
26912 btn.on("mouseover", this.onMouseOver, this);
26913 btn.on("mouseout", this.onMouseOut, this);
26914 btn.on("mousedown", this.onMouseDown, this);
26916 btn.on(this.clickEvent, this.onClick, this);
26917 //btn.on("mouseup", this.onMouseUp, this);
26924 Roo.ButtonToggleMgr.register(this);
26926 this.el.addClass("x-btn-pressed");
26929 var repeater = new Roo.util.ClickRepeater(btn,
26930 typeof this.repeat == "object" ? this.repeat : {}
26932 repeater.on("click", this.onClick, this);
26935 this.fireEvent('render', this);
26939 * Returns the button's underlying element
26940 * @return {Roo.Element} The element
26942 getEl : function(){
26947 * Destroys this Button and removes any listeners.
26949 destroy : function(){
26950 Roo.ButtonToggleMgr.unregister(this);
26951 this.el.removeAllListeners();
26952 this.purgeListeners();
26957 autoWidth : function(){
26959 this.el.setWidth("auto");
26960 if(Roo.isIE7 && Roo.isStrict){
26961 var ib = this.el.child('button');
26962 if(ib && ib.getWidth() > 20){
26964 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26969 this.el.beginMeasure();
26971 if(this.el.getWidth() < this.minWidth){
26972 this.el.setWidth(this.minWidth);
26975 this.el.endMeasure();
26982 * Assigns this button's click handler
26983 * @param {Function} handler The function to call when the button is clicked
26984 * @param {Object} scope (optional) Scope for the function passed in
26986 setHandler : function(handler, scope){
26987 this.handler = handler;
26988 this.scope = scope;
26992 * Sets this button's text
26993 * @param {String} text The button text
26995 setText : function(text){
26998 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27004 * Gets the text for this button
27005 * @return {String} The button text
27007 getText : function(){
27015 this.hidden = false;
27017 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27025 this.hidden = true;
27027 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27032 * Convenience function for boolean show/hide
27033 * @param {Boolean} visible True to show, false to hide
27035 setVisible: function(visible){
27044 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27045 * @param {Boolean} state (optional) Force a particular state
27047 toggle : function(state){
27048 state = state === undefined ? !this.pressed : state;
27049 if(state != this.pressed){
27051 this.el.addClass("x-btn-pressed");
27052 this.pressed = true;
27053 this.fireEvent("toggle", this, true);
27055 this.el.removeClass("x-btn-pressed");
27056 this.pressed = false;
27057 this.fireEvent("toggle", this, false);
27059 if(this.toggleHandler){
27060 this.toggleHandler.call(this.scope || this, this, state);
27068 focus : function(){
27069 this.el.child('button:first').focus();
27073 * Disable this button
27075 disable : function(){
27077 this.el.addClass("x-btn-disabled");
27079 this.disabled = true;
27083 * Enable this button
27085 enable : function(){
27087 this.el.removeClass("x-btn-disabled");
27089 this.disabled = false;
27093 * Convenience function for boolean enable/disable
27094 * @param {Boolean} enabled True to enable, false to disable
27096 setDisabled : function(v){
27097 this[v !== true ? "enable" : "disable"]();
27101 onClick : function(e){
27103 e.preventDefault();
27108 if(!this.disabled){
27109 if(this.enableToggle){
27112 if(this.menu && !this.menu.isVisible()){
27113 this.menu.show(this.el, this.menuAlign);
27115 this.fireEvent("click", this, e);
27117 this.el.removeClass("x-btn-over");
27118 this.handler.call(this.scope || this, this, e);
27123 onMouseOver : function(e){
27124 if(!this.disabled){
27125 this.el.addClass("x-btn-over");
27126 this.fireEvent('mouseover', this, e);
27130 onMouseOut : function(e){
27131 if(!e.within(this.el, true)){
27132 this.el.removeClass("x-btn-over");
27133 this.fireEvent('mouseout', this, e);
27137 onFocus : function(e){
27138 if(!this.disabled){
27139 this.el.addClass("x-btn-focus");
27143 onBlur : function(e){
27144 this.el.removeClass("x-btn-focus");
27147 onMouseDown : function(e){
27148 if(!this.disabled && e.button == 0){
27149 this.el.addClass("x-btn-click");
27150 Roo.get(document).on('mouseup', this.onMouseUp, this);
27154 onMouseUp : function(e){
27156 this.el.removeClass("x-btn-click");
27157 Roo.get(document).un('mouseup', this.onMouseUp, this);
27161 onMenuShow : function(e){
27162 this.el.addClass("x-btn-menu-active");
27165 onMenuHide : function(e){
27166 this.el.removeClass("x-btn-menu-active");
27170 // Private utility class used by Button
27171 Roo.ButtonToggleMgr = function(){
27174 function toggleGroup(btn, state){
27176 var g = groups[btn.toggleGroup];
27177 for(var i = 0, l = g.length; i < l; i++){
27179 g[i].toggle(false);
27186 register : function(btn){
27187 if(!btn.toggleGroup){
27190 var g = groups[btn.toggleGroup];
27192 g = groups[btn.toggleGroup] = [];
27195 btn.on("toggle", toggleGroup);
27198 unregister : function(btn){
27199 if(!btn.toggleGroup){
27202 var g = groups[btn.toggleGroup];
27205 btn.un("toggle", toggleGroup);
27211 * Ext JS Library 1.1.1
27212 * Copyright(c) 2006-2007, Ext JS, LLC.
27214 * Originally Released Under LGPL - original licence link has changed is not relivant.
27217 * <script type="text/javascript">
27221 * @class Roo.SplitButton
27222 * @extends Roo.Button
27223 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27224 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27225 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27226 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27227 * @cfg {String} arrowTooltip The title attribute of the arrow
27229 * Create a new menu button
27230 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27231 * @param {Object} config The config object
27233 Roo.SplitButton = function(renderTo, config){
27234 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27236 * @event arrowclick
27237 * Fires when this button's arrow is clicked
27238 * @param {SplitButton} this
27239 * @param {EventObject} e The click event
27241 this.addEvents({"arrowclick":true});
27244 Roo.extend(Roo.SplitButton, Roo.Button, {
27245 render : function(renderTo){
27246 // this is one sweet looking template!
27247 var tpl = new Roo.Template(
27248 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27249 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27250 '<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>',
27251 "</tbody></table></td><td>",
27252 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27253 '<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>',
27254 "</tbody></table></td></tr></table>"
27256 var btn = tpl.append(renderTo, [this.text, this.type], true);
27257 var btnEl = btn.child("button");
27259 btn.addClass(this.cls);
27262 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27265 btnEl.addClass(this.iconCls);
27267 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27271 if(this.handleMouseEvents){
27272 btn.on("mouseover", this.onMouseOver, this);
27273 btn.on("mouseout", this.onMouseOut, this);
27274 btn.on("mousedown", this.onMouseDown, this);
27275 btn.on("mouseup", this.onMouseUp, this);
27277 btn.on(this.clickEvent, this.onClick, this);
27279 if(typeof this.tooltip == 'object'){
27280 Roo.QuickTips.tips(Roo.apply({
27284 btnEl.dom[this.tooltipType] = this.tooltip;
27287 if(this.arrowTooltip){
27288 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27297 this.el.addClass("x-btn-pressed");
27299 if(Roo.isIE && !Roo.isIE7){
27300 this.autoWidth.defer(1, this);
27305 this.menu.on("show", this.onMenuShow, this);
27306 this.menu.on("hide", this.onMenuHide, this);
27308 this.fireEvent('render', this);
27312 autoWidth : function(){
27314 var tbl = this.el.child("table:first");
27315 var tbl2 = this.el.child("table:last");
27316 this.el.setWidth("auto");
27317 tbl.setWidth("auto");
27318 if(Roo.isIE7 && Roo.isStrict){
27319 var ib = this.el.child('button:first');
27320 if(ib && ib.getWidth() > 20){
27322 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27327 this.el.beginMeasure();
27329 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27330 tbl.setWidth(this.minWidth-tbl2.getWidth());
27333 this.el.endMeasure();
27336 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27340 * Sets this button's click handler
27341 * @param {Function} handler The function to call when the button is clicked
27342 * @param {Object} scope (optional) Scope for the function passed above
27344 setHandler : function(handler, scope){
27345 this.handler = handler;
27346 this.scope = scope;
27350 * Sets this button's arrow click handler
27351 * @param {Function} handler The function to call when the arrow is clicked
27352 * @param {Object} scope (optional) Scope for the function passed above
27354 setArrowHandler : function(handler, scope){
27355 this.arrowHandler = handler;
27356 this.scope = scope;
27362 focus : function(){
27364 this.el.child("button:first").focus();
27369 onClick : function(e){
27370 e.preventDefault();
27371 if(!this.disabled){
27372 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27373 if(this.menu && !this.menu.isVisible()){
27374 this.menu.show(this.el, this.menuAlign);
27376 this.fireEvent("arrowclick", this, e);
27377 if(this.arrowHandler){
27378 this.arrowHandler.call(this.scope || this, this, e);
27381 this.fireEvent("click", this, e);
27383 this.handler.call(this.scope || this, this, e);
27389 onMouseDown : function(e){
27390 if(!this.disabled){
27391 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27395 onMouseUp : function(e){
27396 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27401 // backwards compat
27402 Roo.MenuButton = Roo.SplitButton;/*
27404 * Ext JS Library 1.1.1
27405 * Copyright(c) 2006-2007, Ext JS, LLC.
27407 * Originally Released Under LGPL - original licence link has changed is not relivant.
27410 * <script type="text/javascript">
27414 * @class Roo.Toolbar
27415 * Basic Toolbar class.
27417 * Creates a new Toolbar
27418 * @param {Object} container The config object
27420 Roo.Toolbar = function(container, buttons, config)
27422 /// old consturctor format still supported..
27423 if(container instanceof Array){ // omit the container for later rendering
27424 buttons = container;
27428 if (typeof(container) == 'object' && container.xtype) {
27429 config = container;
27430 container = config.container;
27431 buttons = config.buttons || []; // not really - use items!!
27434 if (config && config.items) {
27435 xitems = config.items;
27436 delete config.items;
27438 Roo.apply(this, config);
27439 this.buttons = buttons;
27442 this.render(container);
27444 this.xitems = xitems;
27445 Roo.each(xitems, function(b) {
27451 Roo.Toolbar.prototype = {
27453 * @cfg {Array} items
27454 * array of button configs or elements to add (will be converted to a MixedCollection)
27458 * @cfg {String/HTMLElement/Element} container
27459 * The id or element that will contain the toolbar
27462 render : function(ct){
27463 this.el = Roo.get(ct);
27465 this.el.addClass(this.cls);
27467 // using a table allows for vertical alignment
27468 // 100% width is needed by Safari...
27469 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
27470 this.tr = this.el.child("tr", true);
27472 this.items = new Roo.util.MixedCollection(false, function(o){
27473 return o.id || ("item" + (++autoId));
27476 this.add.apply(this, this.buttons);
27477 delete this.buttons;
27482 * Adds element(s) to the toolbar -- this function takes a variable number of
27483 * arguments of mixed type and adds them to the toolbar.
27484 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
27486 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
27487 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
27488 * <li>Field: Any form field (equivalent to {@link #addField})</li>
27489 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
27490 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
27491 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
27492 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
27493 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
27494 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
27496 * @param {Mixed} arg2
27497 * @param {Mixed} etc.
27500 var a = arguments, l = a.length;
27501 for(var i = 0; i < l; i++){
27506 _add : function(el) {
27509 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
27512 if (el.applyTo){ // some kind of form field
27513 return this.addField(el);
27515 if (el.render){ // some kind of Toolbar.Item
27516 return this.addItem(el);
27518 if (typeof el == "string"){ // string
27519 if(el == "separator" || el == "-"){
27520 return this.addSeparator();
27523 return this.addSpacer();
27526 return this.addFill();
27528 return this.addText(el);
27531 if(el.tagName){ // element
27532 return this.addElement(el);
27534 if(typeof el == "object"){ // must be button config?
27535 return this.addButton(el);
27537 // and now what?!?!
27543 * Add an Xtype element
27544 * @param {Object} xtype Xtype Object
27545 * @return {Object} created Object
27547 addxtype : function(e){
27548 return this.add(e);
27552 * Returns the Element for this toolbar.
27553 * @return {Roo.Element}
27555 getEl : function(){
27561 * @return {Roo.Toolbar.Item} The separator item
27563 addSeparator : function(){
27564 return this.addItem(new Roo.Toolbar.Separator());
27568 * Adds a spacer element
27569 * @return {Roo.Toolbar.Spacer} The spacer item
27571 addSpacer : function(){
27572 return this.addItem(new Roo.Toolbar.Spacer());
27576 * Adds a fill element that forces subsequent additions to the right side of the toolbar
27577 * @return {Roo.Toolbar.Fill} The fill item
27579 addFill : function(){
27580 return this.addItem(new Roo.Toolbar.Fill());
27584 * Adds any standard HTML element to the toolbar
27585 * @param {String/HTMLElement/Element} el The element or id of the element to add
27586 * @return {Roo.Toolbar.Item} The element's item
27588 addElement : function(el){
27589 return this.addItem(new Roo.Toolbar.Item(el));
27592 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
27593 * @type Roo.util.MixedCollection
27598 * Adds any Toolbar.Item or subclass
27599 * @param {Roo.Toolbar.Item} item
27600 * @return {Roo.Toolbar.Item} The item
27602 addItem : function(item){
27603 var td = this.nextBlock();
27605 this.items.add(item);
27610 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
27611 * @param {Object/Array} config A button config or array of configs
27612 * @return {Roo.Toolbar.Button/Array}
27614 addButton : function(config){
27615 if(config instanceof Array){
27617 for(var i = 0, len = config.length; i < len; i++) {
27618 buttons.push(this.addButton(config[i]));
27623 if(!(config instanceof Roo.Toolbar.Button)){
27625 new Roo.Toolbar.SplitButton(config) :
27626 new Roo.Toolbar.Button(config);
27628 var td = this.nextBlock();
27635 * Adds text to the toolbar
27636 * @param {String} text The text to add
27637 * @return {Roo.Toolbar.Item} The element's item
27639 addText : function(text){
27640 return this.addItem(new Roo.Toolbar.TextItem(text));
27644 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27645 * @param {Number} index The index where the item is to be inserted
27646 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27647 * @return {Roo.Toolbar.Button/Item}
27649 insertButton : function(index, item){
27650 if(item instanceof Array){
27652 for(var i = 0, len = item.length; i < len; i++) {
27653 buttons.push(this.insertButton(index + i, item[i]));
27657 if (!(item instanceof Roo.Toolbar.Button)){
27658 item = new Roo.Toolbar.Button(item);
27660 var td = document.createElement("td");
27661 this.tr.insertBefore(td, this.tr.childNodes[index]);
27663 this.items.insert(index, item);
27668 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27669 * @param {Object} config
27670 * @return {Roo.Toolbar.Item} The element's item
27672 addDom : function(config, returnEl){
27673 var td = this.nextBlock();
27674 Roo.DomHelper.overwrite(td, config);
27675 var ti = new Roo.Toolbar.Item(td.firstChild);
27677 this.items.add(ti);
27682 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27683 * @type Roo.util.MixedCollection
27688 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27689 * Note: the field should not have been rendered yet. For a field that has already been
27690 * rendered, use {@link #addElement}.
27691 * @param {Roo.form.Field} field
27692 * @return {Roo.ToolbarItem}
27696 addField : function(field) {
27697 if (!this.fields) {
27699 this.fields = new Roo.util.MixedCollection(false, function(o){
27700 return o.id || ("item" + (++autoId));
27705 var td = this.nextBlock();
27707 var ti = new Roo.Toolbar.Item(td.firstChild);
27709 this.items.add(ti);
27710 this.fields.add(field);
27721 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27722 this.el.child('div').hide();
27730 this.el.child('div').show();
27734 nextBlock : function(){
27735 var td = document.createElement("td");
27736 this.tr.appendChild(td);
27741 destroy : function(){
27742 if(this.items){ // rendered?
27743 Roo.destroy.apply(Roo, this.items.items);
27745 if(this.fields){ // rendered?
27746 Roo.destroy.apply(Roo, this.fields.items);
27748 Roo.Element.uncache(this.el, this.tr);
27753 * @class Roo.Toolbar.Item
27754 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27756 * Creates a new Item
27757 * @param {HTMLElement} el
27759 Roo.Toolbar.Item = function(el){
27760 this.el = Roo.getDom(el);
27761 this.id = Roo.id(this.el);
27762 this.hidden = false;
27765 Roo.Toolbar.Item.prototype = {
27768 * Get this item's HTML Element
27769 * @return {HTMLElement}
27771 getEl : function(){
27776 render : function(td){
27778 td.appendChild(this.el);
27782 * Removes and destroys this item.
27784 destroy : function(){
27785 this.td.parentNode.removeChild(this.td);
27792 this.hidden = false;
27793 this.td.style.display = "";
27800 this.hidden = true;
27801 this.td.style.display = "none";
27805 * Convenience function for boolean show/hide.
27806 * @param {Boolean} visible true to show/false to hide
27808 setVisible: function(visible){
27817 * Try to focus this item.
27819 focus : function(){
27820 Roo.fly(this.el).focus();
27824 * Disables this item.
27826 disable : function(){
27827 Roo.fly(this.td).addClass("x-item-disabled");
27828 this.disabled = true;
27829 this.el.disabled = true;
27833 * Enables this item.
27835 enable : function(){
27836 Roo.fly(this.td).removeClass("x-item-disabled");
27837 this.disabled = false;
27838 this.el.disabled = false;
27844 * @class Roo.Toolbar.Separator
27845 * @extends Roo.Toolbar.Item
27846 * A simple toolbar separator class
27848 * Creates a new Separator
27850 Roo.Toolbar.Separator = function(){
27851 var s = document.createElement("span");
27852 s.className = "ytb-sep";
27853 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27855 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27856 enable:Roo.emptyFn,
27857 disable:Roo.emptyFn,
27862 * @class Roo.Toolbar.Spacer
27863 * @extends Roo.Toolbar.Item
27864 * A simple element that adds extra horizontal space to a toolbar.
27866 * Creates a new Spacer
27868 Roo.Toolbar.Spacer = function(){
27869 var s = document.createElement("div");
27870 s.className = "ytb-spacer";
27871 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27873 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27874 enable:Roo.emptyFn,
27875 disable:Roo.emptyFn,
27880 * @class Roo.Toolbar.Fill
27881 * @extends Roo.Toolbar.Spacer
27882 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27884 * Creates a new Spacer
27886 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27888 render : function(td){
27889 td.style.width = '100%';
27890 Roo.Toolbar.Fill.superclass.render.call(this, td);
27895 * @class Roo.Toolbar.TextItem
27896 * @extends Roo.Toolbar.Item
27897 * A simple class that renders text directly into a toolbar.
27899 * Creates a new TextItem
27900 * @param {String} text
27902 Roo.Toolbar.TextItem = function(text){
27903 if (typeof(text) == 'object') {
27906 var s = document.createElement("span");
27907 s.className = "ytb-text";
27908 s.innerHTML = text;
27909 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27911 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27912 enable:Roo.emptyFn,
27913 disable:Roo.emptyFn,
27918 * @class Roo.Toolbar.Button
27919 * @extends Roo.Button
27920 * A button that renders into a toolbar.
27922 * Creates a new Button
27923 * @param {Object} config A standard {@link Roo.Button} config object
27925 Roo.Toolbar.Button = function(config){
27926 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27928 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27929 render : function(td){
27931 Roo.Toolbar.Button.superclass.render.call(this, td);
27935 * Removes and destroys this button
27937 destroy : function(){
27938 Roo.Toolbar.Button.superclass.destroy.call(this);
27939 this.td.parentNode.removeChild(this.td);
27943 * Shows this button
27946 this.hidden = false;
27947 this.td.style.display = "";
27951 * Hides this button
27954 this.hidden = true;
27955 this.td.style.display = "none";
27959 * Disables this item
27961 disable : function(){
27962 Roo.fly(this.td).addClass("x-item-disabled");
27963 this.disabled = true;
27967 * Enables this item
27969 enable : function(){
27970 Roo.fly(this.td).removeClass("x-item-disabled");
27971 this.disabled = false;
27974 // backwards compat
27975 Roo.ToolbarButton = Roo.Toolbar.Button;
27978 * @class Roo.Toolbar.SplitButton
27979 * @extends Roo.SplitButton
27980 * A menu button that renders into a toolbar.
27982 * Creates a new SplitButton
27983 * @param {Object} config A standard {@link Roo.SplitButton} config object
27985 Roo.Toolbar.SplitButton = function(config){
27986 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27988 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27989 render : function(td){
27991 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27995 * Removes and destroys this button
27997 destroy : function(){
27998 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27999 this.td.parentNode.removeChild(this.td);
28003 * Shows this button
28006 this.hidden = false;
28007 this.td.style.display = "";
28011 * Hides this button
28014 this.hidden = true;
28015 this.td.style.display = "none";
28019 // backwards compat
28020 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28022 * Ext JS Library 1.1.1
28023 * Copyright(c) 2006-2007, Ext JS, LLC.
28025 * Originally Released Under LGPL - original licence link has changed is not relivant.
28028 * <script type="text/javascript">
28032 * @class Roo.PagingToolbar
28033 * @extends Roo.Toolbar
28034 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28036 * Create a new PagingToolbar
28037 * @param {Object} config The config object
28039 Roo.PagingToolbar = function(el, ds, config)
28041 // old args format still supported... - xtype is prefered..
28042 if (typeof(el) == 'object' && el.xtype) {
28043 // created from xtype...
28045 ds = el.dataSource;
28046 el = config.container;
28049 if (config.items) {
28050 items = config.items;
28054 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28057 this.renderButtons(this.el);
28060 // supprot items array.
28062 Roo.each(items, function(e) {
28063 this.add(Roo.factory(e));
28068 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28070 * @cfg {Roo.data.Store} dataSource
28071 * The underlying data store providing the paged data
28074 * @cfg {String/HTMLElement/Element} container
28075 * container The id or element that will contain the toolbar
28078 * @cfg {Boolean} displayInfo
28079 * True to display the displayMsg (defaults to false)
28082 * @cfg {Number} pageSize
28083 * The number of records to display per page (defaults to 20)
28087 * @cfg {String} displayMsg
28088 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28090 displayMsg : 'Displaying {0} - {1} of {2}',
28092 * @cfg {String} emptyMsg
28093 * The message to display when no records are found (defaults to "No data to display")
28095 emptyMsg : 'No data to display',
28097 * Customizable piece of the default paging text (defaults to "Page")
28100 beforePageText : "Page",
28102 * Customizable piece of the default paging text (defaults to "of %0")
28105 afterPageText : "of {0}",
28107 * Customizable piece of the default paging text (defaults to "First Page")
28110 firstText : "First Page",
28112 * Customizable piece of the default paging text (defaults to "Previous Page")
28115 prevText : "Previous Page",
28117 * Customizable piece of the default paging text (defaults to "Next Page")
28120 nextText : "Next Page",
28122 * Customizable piece of the default paging text (defaults to "Last Page")
28125 lastText : "Last Page",
28127 * Customizable piece of the default paging text (defaults to "Refresh")
28130 refreshText : "Refresh",
28133 renderButtons : function(el){
28134 Roo.PagingToolbar.superclass.render.call(this, el);
28135 this.first = this.addButton({
28136 tooltip: this.firstText,
28137 cls: "x-btn-icon x-grid-page-first",
28139 handler: this.onClick.createDelegate(this, ["first"])
28141 this.prev = this.addButton({
28142 tooltip: this.prevText,
28143 cls: "x-btn-icon x-grid-page-prev",
28145 handler: this.onClick.createDelegate(this, ["prev"])
28147 //this.addSeparator();
28148 this.add(this.beforePageText);
28149 this.field = Roo.get(this.addDom({
28154 cls: "x-grid-page-number"
28156 this.field.on("keydown", this.onPagingKeydown, this);
28157 this.field.on("focus", function(){this.dom.select();});
28158 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28159 this.field.setHeight(18);
28160 //this.addSeparator();
28161 this.next = this.addButton({
28162 tooltip: this.nextText,
28163 cls: "x-btn-icon x-grid-page-next",
28165 handler: this.onClick.createDelegate(this, ["next"])
28167 this.last = this.addButton({
28168 tooltip: this.lastText,
28169 cls: "x-btn-icon x-grid-page-last",
28171 handler: this.onClick.createDelegate(this, ["last"])
28173 //this.addSeparator();
28174 this.loading = this.addButton({
28175 tooltip: this.refreshText,
28176 cls: "x-btn-icon x-grid-loading",
28177 handler: this.onClick.createDelegate(this, ["refresh"])
28180 if(this.displayInfo){
28181 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28186 updateInfo : function(){
28187 if(this.displayEl){
28188 var count = this.ds.getCount();
28189 var msg = count == 0 ?
28193 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28195 this.displayEl.update(msg);
28200 onLoad : function(ds, r, o){
28201 this.cursor = o.params ? o.params.start : 0;
28202 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28204 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28205 this.field.dom.value = ap;
28206 this.first.setDisabled(ap == 1);
28207 this.prev.setDisabled(ap == 1);
28208 this.next.setDisabled(ap == ps);
28209 this.last.setDisabled(ap == ps);
28210 this.loading.enable();
28215 getPageData : function(){
28216 var total = this.ds.getTotalCount();
28219 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28220 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28225 onLoadError : function(){
28226 this.loading.enable();
28230 onPagingKeydown : function(e){
28231 var k = e.getKey();
28232 var d = this.getPageData();
28234 var v = this.field.dom.value, pageNum;
28235 if(!v || isNaN(pageNum = parseInt(v, 10))){
28236 this.field.dom.value = d.activePage;
28239 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28240 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28243 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))
28245 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28246 this.field.dom.value = pageNum;
28247 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28250 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28252 var v = this.field.dom.value, pageNum;
28253 var increment = (e.shiftKey) ? 10 : 1;
28254 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28256 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28257 this.field.dom.value = d.activePage;
28260 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28262 this.field.dom.value = parseInt(v, 10) + increment;
28263 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28264 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28271 beforeLoad : function(){
28273 this.loading.disable();
28278 onClick : function(which){
28282 ds.load({params:{start: 0, limit: this.pageSize}});
28285 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28288 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28291 var total = ds.getTotalCount();
28292 var extra = total % this.pageSize;
28293 var lastStart = extra ? (total - extra) : total-this.pageSize;
28294 ds.load({params:{start: lastStart, limit: this.pageSize}});
28297 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28303 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28304 * @param {Roo.data.Store} store The data store to unbind
28306 unbind : function(ds){
28307 ds.un("beforeload", this.beforeLoad, this);
28308 ds.un("load", this.onLoad, this);
28309 ds.un("loadexception", this.onLoadError, this);
28310 ds.un("remove", this.updateInfo, this);
28311 ds.un("add", this.updateInfo, this);
28312 this.ds = undefined;
28316 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28317 * @param {Roo.data.Store} store The data store to bind
28319 bind : function(ds){
28320 ds.on("beforeload", this.beforeLoad, this);
28321 ds.on("load", this.onLoad, this);
28322 ds.on("loadexception", this.onLoadError, this);
28323 ds.on("remove", this.updateInfo, this);
28324 ds.on("add", this.updateInfo, this);
28329 * Ext JS Library 1.1.1
28330 * Copyright(c) 2006-2007, Ext JS, LLC.
28332 * Originally Released Under LGPL - original licence link has changed is not relivant.
28335 * <script type="text/javascript">
28339 * @class Roo.Resizable
28340 * @extends Roo.util.Observable
28341 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28342 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28343 * 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
28344 * the element will be wrapped for you automatically.</p>
28345 * <p>Here is the list of valid resize handles:</p>
28348 ------ -------------------
28357 'hd' horizontal drag
28360 * <p>Here's an example showing the creation of a typical Resizable:</p>
28362 var resizer = new Roo.Resizable("element-id", {
28370 resizer.on("resize", myHandler);
28372 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28373 * resizer.east.setDisplayed(false);</p>
28374 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28375 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28376 * resize operation's new size (defaults to [0, 0])
28377 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28378 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28379 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28380 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28381 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28382 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28383 * @cfg {Number} width The width of the element in pixels (defaults to null)
28384 * @cfg {Number} height The height of the element in pixels (defaults to null)
28385 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28386 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28387 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28388 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28389 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28390 * in favor of the handles config option (defaults to false)
28391 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28392 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28393 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28394 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28395 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28396 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28397 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28398 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28399 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28400 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28401 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28403 * Create a new resizable component
28404 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28405 * @param {Object} config configuration options
28407 Roo.Resizable = function(el, config)
28409 this.el = Roo.get(el);
28411 if(config && config.wrap){
28412 config.resizeChild = this.el;
28413 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
28414 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
28415 this.el.setStyle("overflow", "hidden");
28416 this.el.setPositioning(config.resizeChild.getPositioning());
28417 config.resizeChild.clearPositioning();
28418 if(!config.width || !config.height){
28419 var csize = config.resizeChild.getSize();
28420 this.el.setSize(csize.width, csize.height);
28422 if(config.pinned && !config.adjustments){
28423 config.adjustments = "auto";
28427 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
28428 this.proxy.unselectable();
28429 this.proxy.enableDisplayMode('block');
28431 Roo.apply(this, config);
28434 this.disableTrackOver = true;
28435 this.el.addClass("x-resizable-pinned");
28437 // if the element isn't positioned, make it relative
28438 var position = this.el.getStyle("position");
28439 if(position != "absolute" && position != "fixed"){
28440 this.el.setStyle("position", "relative");
28442 if(!this.handles){ // no handles passed, must be legacy style
28443 this.handles = 's,e,se';
28444 if(this.multiDirectional){
28445 this.handles += ',n,w';
28448 if(this.handles == "all"){
28449 this.handles = "n s e w ne nw se sw";
28451 var hs = this.handles.split(/\s*?[,;]\s*?| /);
28452 var ps = Roo.Resizable.positions;
28453 for(var i = 0, len = hs.length; i < len; i++){
28454 if(hs[i] && ps[hs[i]]){
28455 var pos = ps[hs[i]];
28456 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
28460 this.corner = this.southeast;
28462 // updateBox = the box can move..
28463 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
28464 this.updateBox = true;
28467 this.activeHandle = null;
28469 if(this.resizeChild){
28470 if(typeof this.resizeChild == "boolean"){
28471 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
28473 this.resizeChild = Roo.get(this.resizeChild, true);
28477 if(this.adjustments == "auto"){
28478 var rc = this.resizeChild;
28479 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
28480 if(rc && (hw || hn)){
28481 rc.position("relative");
28482 rc.setLeft(hw ? hw.el.getWidth() : 0);
28483 rc.setTop(hn ? hn.el.getHeight() : 0);
28485 this.adjustments = [
28486 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
28487 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
28491 if(this.draggable){
28492 this.dd = this.dynamic ?
28493 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
28494 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
28500 * @event beforeresize
28501 * Fired before resize is allowed. Set enabled to false to cancel resize.
28502 * @param {Roo.Resizable} this
28503 * @param {Roo.EventObject} e The mousedown event
28505 "beforeresize" : true,
28508 * Fired a resizing.
28509 * @param {Roo.Resizable} this
28510 * @param {Number} x The new x position
28511 * @param {Number} y The new y position
28512 * @param {Number} w The new w width
28513 * @param {Number} h The new h hight
28514 * @param {Roo.EventObject} e The mouseup event
28519 * Fired after a resize.
28520 * @param {Roo.Resizable} this
28521 * @param {Number} width The new width
28522 * @param {Number} height The new height
28523 * @param {Roo.EventObject} e The mouseup event
28528 if(this.width !== null && this.height !== null){
28529 this.resizeTo(this.width, this.height);
28531 this.updateChildSize();
28534 this.el.dom.style.zoom = 1;
28536 Roo.Resizable.superclass.constructor.call(this);
28539 Roo.extend(Roo.Resizable, Roo.util.Observable, {
28540 resizeChild : false,
28541 adjustments : [0, 0],
28551 multiDirectional : false,
28552 disableTrackOver : false,
28553 easing : 'easeOutStrong',
28554 widthIncrement : 0,
28555 heightIncrement : 0,
28559 preserveRatio : false,
28560 transparent: false,
28566 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
28568 constrainTo: undefined,
28570 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
28572 resizeRegion: undefined,
28576 * Perform a manual resize
28577 * @param {Number} width
28578 * @param {Number} height
28580 resizeTo : function(width, height){
28581 this.el.setSize(width, height);
28582 this.updateChildSize();
28583 this.fireEvent("resize", this, width, height, null);
28587 startSizing : function(e, handle){
28588 this.fireEvent("beforeresize", this, e);
28589 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
28592 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
28593 this.overlay.unselectable();
28594 this.overlay.enableDisplayMode("block");
28595 this.overlay.on("mousemove", this.onMouseMove, this);
28596 this.overlay.on("mouseup", this.onMouseUp, this);
28598 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
28600 this.resizing = true;
28601 this.startBox = this.el.getBox();
28602 this.startPoint = e.getXY();
28603 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
28604 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
28606 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28607 this.overlay.show();
28609 if(this.constrainTo) {
28610 var ct = Roo.get(this.constrainTo);
28611 this.resizeRegion = ct.getRegion().adjust(
28612 ct.getFrameWidth('t'),
28613 ct.getFrameWidth('l'),
28614 -ct.getFrameWidth('b'),
28615 -ct.getFrameWidth('r')
28619 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
28621 this.proxy.setBox(this.startBox);
28623 this.proxy.setStyle('visibility', 'visible');
28629 onMouseDown : function(handle, e){
28632 this.activeHandle = handle;
28633 this.startSizing(e, handle);
28638 onMouseUp : function(e){
28639 var size = this.resizeElement();
28640 this.resizing = false;
28642 this.overlay.hide();
28644 this.fireEvent("resize", this, size.width, size.height, e);
28648 updateChildSize : function(){
28650 if(this.resizeChild){
28652 var child = this.resizeChild;
28653 var adj = this.adjustments;
28654 if(el.dom.offsetWidth){
28655 var b = el.getSize(true);
28656 child.setSize(b.width+adj[0], b.height+adj[1]);
28658 // Second call here for IE
28659 // The first call enables instant resizing and
28660 // the second call corrects scroll bars if they
28663 setTimeout(function(){
28664 if(el.dom.offsetWidth){
28665 var b = el.getSize(true);
28666 child.setSize(b.width+adj[0], b.height+adj[1]);
28674 snap : function(value, inc, min){
28675 if(!inc || !value) return value;
28676 var newValue = value;
28677 var m = value % inc;
28680 newValue = value + (inc-m);
28682 newValue = value - m;
28685 return Math.max(min, newValue);
28689 resizeElement : function(){
28690 var box = this.proxy.getBox();
28691 if(this.updateBox){
28692 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28694 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28696 this.updateChildSize();
28704 constrain : function(v, diff, m, mx){
28707 }else if(v - diff > mx){
28714 onMouseMove : function(e){
28717 try{// try catch so if something goes wrong the user doesn't get hung
28719 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28723 //var curXY = this.startPoint;
28724 var curSize = this.curSize || this.startBox;
28725 var x = this.startBox.x, y = this.startBox.y;
28726 var ox = x, oy = y;
28727 var w = curSize.width, h = curSize.height;
28728 var ow = w, oh = h;
28729 var mw = this.minWidth, mh = this.minHeight;
28730 var mxw = this.maxWidth, mxh = this.maxHeight;
28731 var wi = this.widthIncrement;
28732 var hi = this.heightIncrement;
28734 var eventXY = e.getXY();
28735 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28736 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28738 var pos = this.activeHandle.position;
28743 w = Math.min(Math.max(mw, w), mxw);
28748 h = Math.min(Math.max(mh, h), mxh);
28753 w = Math.min(Math.max(mw, w), mxw);
28754 h = Math.min(Math.max(mh, h), mxh);
28757 diffY = this.constrain(h, diffY, mh, mxh);
28764 var adiffX = Math.abs(diffX);
28765 var sub = (adiffX % wi); // how much
28766 if (sub > (wi/2)) { // far enough to snap
28767 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28769 // remove difference..
28770 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28774 x = Math.max(this.minX, x);
28777 diffX = this.constrain(w, diffX, mw, mxw);
28783 w = Math.min(Math.max(mw, w), mxw);
28784 diffY = this.constrain(h, diffY, mh, mxh);
28789 diffX = this.constrain(w, diffX, mw, mxw);
28790 diffY = this.constrain(h, diffY, mh, mxh);
28797 diffX = this.constrain(w, diffX, mw, mxw);
28799 h = Math.min(Math.max(mh, h), mxh);
28805 var sw = this.snap(w, wi, mw);
28806 var sh = this.snap(h, hi, mh);
28807 if(sw != w || sh != h){
28830 if(this.preserveRatio){
28835 h = Math.min(Math.max(mh, h), mxh);
28840 w = Math.min(Math.max(mw, w), mxw);
28845 w = Math.min(Math.max(mw, w), mxw);
28851 w = Math.min(Math.max(mw, w), mxw);
28857 h = Math.min(Math.max(mh, h), mxh);
28865 h = Math.min(Math.max(mh, h), mxh);
28875 h = Math.min(Math.max(mh, h), mxh);
28883 if (pos == 'hdrag') {
28886 this.proxy.setBounds(x, y, w, h);
28888 this.resizeElement();
28892 this.fireEvent("resizing", this, x, y, w, h, e);
28896 handleOver : function(){
28898 this.el.addClass("x-resizable-over");
28903 handleOut : function(){
28904 if(!this.resizing){
28905 this.el.removeClass("x-resizable-over");
28910 * Returns the element this component is bound to.
28911 * @return {Roo.Element}
28913 getEl : function(){
28918 * Returns the resizeChild element (or null).
28919 * @return {Roo.Element}
28921 getResizeChild : function(){
28922 return this.resizeChild;
28924 groupHandler : function()
28929 * Destroys this resizable. If the element was wrapped and
28930 * removeEl is not true then the element remains.
28931 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28933 destroy : function(removeEl){
28934 this.proxy.remove();
28936 this.overlay.removeAllListeners();
28937 this.overlay.remove();
28939 var ps = Roo.Resizable.positions;
28941 if(typeof ps[k] != "function" && this[ps[k]]){
28942 var h = this[ps[k]];
28943 h.el.removeAllListeners();
28948 this.el.update("");
28955 // hash to map config positions to true positions
28956 Roo.Resizable.positions = {
28957 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28962 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28964 // only initialize the template if resizable is used
28965 var tpl = Roo.DomHelper.createTemplate(
28966 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28969 Roo.Resizable.Handle.prototype.tpl = tpl;
28971 this.position = pos;
28973 // show north drag fro topdra
28974 var handlepos = pos == 'hdrag' ? 'north' : pos;
28976 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28977 if (pos == 'hdrag') {
28978 this.el.setStyle('cursor', 'pointer');
28980 this.el.unselectable();
28982 this.el.setOpacity(0);
28984 this.el.on("mousedown", this.onMouseDown, this);
28985 if(!disableTrackOver){
28986 this.el.on("mouseover", this.onMouseOver, this);
28987 this.el.on("mouseout", this.onMouseOut, this);
28992 Roo.Resizable.Handle.prototype = {
28993 afterResize : function(rz){
28997 onMouseDown : function(e){
28998 this.rz.onMouseDown(this, e);
29001 onMouseOver : function(e){
29002 this.rz.handleOver(this, e);
29005 onMouseOut : function(e){
29006 this.rz.handleOut(this, e);
29010 * Ext JS Library 1.1.1
29011 * Copyright(c) 2006-2007, Ext JS, LLC.
29013 * Originally Released Under LGPL - original licence link has changed is not relivant.
29016 * <script type="text/javascript">
29020 * @class Roo.Editor
29021 * @extends Roo.Component
29022 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29024 * Create a new Editor
29025 * @param {Roo.form.Field} field The Field object (or descendant)
29026 * @param {Object} config The config object
29028 Roo.Editor = function(field, config){
29029 Roo.Editor.superclass.constructor.call(this, config);
29030 this.field = field;
29033 * @event beforestartedit
29034 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29035 * false from the handler of this event.
29036 * @param {Editor} this
29037 * @param {Roo.Element} boundEl The underlying element bound to this editor
29038 * @param {Mixed} value The field value being set
29040 "beforestartedit" : true,
29043 * Fires when this editor is displayed
29044 * @param {Roo.Element} boundEl The underlying element bound to this editor
29045 * @param {Mixed} value The starting field value
29047 "startedit" : true,
29049 * @event beforecomplete
29050 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29051 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29052 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29053 * event will not fire since no edit actually occurred.
29054 * @param {Editor} this
29055 * @param {Mixed} value The current field value
29056 * @param {Mixed} startValue The original field value
29058 "beforecomplete" : true,
29061 * Fires after editing is complete and any changed value has been written to the underlying field.
29062 * @param {Editor} this
29063 * @param {Mixed} value The current field value
29064 * @param {Mixed} startValue The original field value
29068 * @event specialkey
29069 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29070 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29071 * @param {Roo.form.Field} this
29072 * @param {Roo.EventObject} e The event object
29074 "specialkey" : true
29078 Roo.extend(Roo.Editor, Roo.Component, {
29080 * @cfg {Boolean/String} autosize
29081 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29082 * or "height" to adopt the height only (defaults to false)
29085 * @cfg {Boolean} revertInvalid
29086 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29087 * validation fails (defaults to true)
29090 * @cfg {Boolean} ignoreNoChange
29091 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29092 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29093 * will never be ignored.
29096 * @cfg {Boolean} hideEl
29097 * False to keep the bound element visible while the editor is displayed (defaults to true)
29100 * @cfg {Mixed} value
29101 * The data value of the underlying field (defaults to "")
29105 * @cfg {String} alignment
29106 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29110 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29111 * for bottom-right shadow (defaults to "frame")
29115 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29119 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29121 completeOnEnter : false,
29123 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29125 cancelOnEsc : false,
29127 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29132 onRender : function(ct, position){
29133 this.el = new Roo.Layer({
29134 shadow: this.shadow,
29140 constrain: this.constrain
29142 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29143 if(this.field.msgTarget != 'title'){
29144 this.field.msgTarget = 'qtip';
29146 this.field.render(this.el);
29148 this.field.el.dom.setAttribute('autocomplete', 'off');
29150 this.field.on("specialkey", this.onSpecialKey, this);
29151 if(this.swallowKeys){
29152 this.field.el.swallowEvent(['keydown','keypress']);
29155 this.field.on("blur", this.onBlur, this);
29156 if(this.field.grow){
29157 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29161 onSpecialKey : function(field, e)
29163 //Roo.log('editor onSpecialKey');
29164 if(this.completeOnEnter && e.getKey() == e.ENTER){
29166 this.completeEdit();
29169 // do not fire special key otherwise it might hide close the editor...
29170 if(e.getKey() == e.ENTER){
29173 if(this.cancelOnEsc && e.getKey() == e.ESC){
29177 this.fireEvent('specialkey', field, e);
29182 * Starts the editing process and shows the editor.
29183 * @param {String/HTMLElement/Element} el The element to edit
29184 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29185 * to the innerHTML of el.
29187 startEdit : function(el, value){
29189 this.completeEdit();
29191 this.boundEl = Roo.get(el);
29192 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29193 if(!this.rendered){
29194 this.render(this.parentEl || document.body);
29196 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29199 this.startValue = v;
29200 this.field.setValue(v);
29202 var sz = this.boundEl.getSize();
29203 switch(this.autoSize){
29205 this.setSize(sz.width, "");
29208 this.setSize("", sz.height);
29211 this.setSize(sz.width, sz.height);
29214 this.el.alignTo(this.boundEl, this.alignment);
29215 this.editing = true;
29217 Roo.QuickTips.disable();
29223 * Sets the height and width of this editor.
29224 * @param {Number} width The new width
29225 * @param {Number} height The new height
29227 setSize : function(w, h){
29228 this.field.setSize(w, h);
29235 * Realigns the editor to the bound field based on the current alignment config value.
29237 realign : function(){
29238 this.el.alignTo(this.boundEl, this.alignment);
29242 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29243 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29245 completeEdit : function(remainVisible){
29249 var v = this.getValue();
29250 if(this.revertInvalid !== false && !this.field.isValid()){
29251 v = this.startValue;
29252 this.cancelEdit(true);
29254 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29255 this.editing = false;
29259 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29260 this.editing = false;
29261 if(this.updateEl && this.boundEl){
29262 this.boundEl.update(v);
29264 if(remainVisible !== true){
29267 this.fireEvent("complete", this, v, this.startValue);
29272 onShow : function(){
29274 if(this.hideEl !== false){
29275 this.boundEl.hide();
29278 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29279 this.fixIEFocus = true;
29280 this.deferredFocus.defer(50, this);
29282 this.field.focus();
29284 this.fireEvent("startedit", this.boundEl, this.startValue);
29287 deferredFocus : function(){
29289 this.field.focus();
29294 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29295 * reverted to the original starting value.
29296 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29297 * cancel (defaults to false)
29299 cancelEdit : function(remainVisible){
29301 this.setValue(this.startValue);
29302 if(remainVisible !== true){
29309 onBlur : function(){
29310 if(this.allowBlur !== true && this.editing){
29311 this.completeEdit();
29316 onHide : function(){
29318 this.completeEdit();
29322 if(this.field.collapse){
29323 this.field.collapse();
29326 if(this.hideEl !== false){
29327 this.boundEl.show();
29330 Roo.QuickTips.enable();
29335 * Sets the data value of the editor
29336 * @param {Mixed} value Any valid value supported by the underlying field
29338 setValue : function(v){
29339 this.field.setValue(v);
29343 * Gets the data value of the editor
29344 * @return {Mixed} The data value
29346 getValue : function(){
29347 return this.field.getValue();
29351 * Ext JS Library 1.1.1
29352 * Copyright(c) 2006-2007, Ext JS, LLC.
29354 * Originally Released Under LGPL - original licence link has changed is not relivant.
29357 * <script type="text/javascript">
29361 * @class Roo.BasicDialog
29362 * @extends Roo.util.Observable
29363 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29365 var dlg = new Roo.BasicDialog("my-dlg", {
29374 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29375 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29376 dlg.addButton('Cancel', dlg.hide, dlg);
29379 <b>A Dialog should always be a direct child of the body element.</b>
29380 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29381 * @cfg {String} title Default text to display in the title bar (defaults to null)
29382 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29383 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29384 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29385 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29386 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29387 * (defaults to null with no animation)
29388 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29389 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29390 * property for valid values (defaults to 'all')
29391 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29392 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29393 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29394 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29395 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29396 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29397 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29398 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29399 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29400 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29401 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29402 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29403 * draggable = true (defaults to false)
29404 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29405 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29406 * shadow (defaults to false)
29407 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29408 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29409 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
29410 * @cfg {Array} buttons Array of buttons
29411 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
29413 * Create a new BasicDialog.
29414 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
29415 * @param {Object} config Configuration options
29417 Roo.BasicDialog = function(el, config){
29418 this.el = Roo.get(el);
29419 var dh = Roo.DomHelper;
29420 if(!this.el && config && config.autoCreate){
29421 if(typeof config.autoCreate == "object"){
29422 if(!config.autoCreate.id){
29423 config.autoCreate.id = el;
29425 this.el = dh.append(document.body,
29426 config.autoCreate, true);
29428 this.el = dh.append(document.body,
29429 {tag: "div", id: el, style:'visibility:hidden;'}, true);
29433 el.setDisplayed(true);
29434 el.hide = this.hideAction;
29436 el.addClass("x-dlg");
29438 Roo.apply(this, config);
29440 this.proxy = el.createProxy("x-dlg-proxy");
29441 this.proxy.hide = this.hideAction;
29442 this.proxy.setOpacity(.5);
29446 el.setWidth(config.width);
29449 el.setHeight(config.height);
29451 this.size = el.getSize();
29452 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
29453 this.xy = [config.x,config.y];
29455 this.xy = el.getCenterXY(true);
29457 /** The header element @type Roo.Element */
29458 this.header = el.child("> .x-dlg-hd");
29459 /** The body element @type Roo.Element */
29460 this.body = el.child("> .x-dlg-bd");
29461 /** The footer element @type Roo.Element */
29462 this.footer = el.child("> .x-dlg-ft");
29465 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
29468 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
29471 this.header.unselectable();
29473 this.header.update(this.title);
29475 // this element allows the dialog to be focused for keyboard event
29476 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
29477 this.focusEl.swallowEvent("click", true);
29479 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
29481 // wrap the body and footer for special rendering
29482 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
29484 this.bwrap.dom.appendChild(this.footer.dom);
29487 this.bg = this.el.createChild({
29488 tag: "div", cls:"x-dlg-bg",
29489 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
29491 this.centerBg = this.bg.child("div.x-dlg-bg-center");
29494 if(this.autoScroll !== false && !this.autoTabs){
29495 this.body.setStyle("overflow", "auto");
29498 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
29500 if(this.closable !== false){
29501 this.el.addClass("x-dlg-closable");
29502 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
29503 this.close.on("click", this.closeClick, this);
29504 this.close.addClassOnOver("x-dlg-close-over");
29506 if(this.collapsible !== false){
29507 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
29508 this.collapseBtn.on("click", this.collapseClick, this);
29509 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
29510 this.header.on("dblclick", this.collapseClick, this);
29512 if(this.resizable !== false){
29513 this.el.addClass("x-dlg-resizable");
29514 this.resizer = new Roo.Resizable(el, {
29515 minWidth: this.minWidth || 80,
29516 minHeight:this.minHeight || 80,
29517 handles: this.resizeHandles || "all",
29520 this.resizer.on("beforeresize", this.beforeResize, this);
29521 this.resizer.on("resize", this.onResize, this);
29523 if(this.draggable !== false){
29524 el.addClass("x-dlg-draggable");
29525 if (!this.proxyDrag) {
29526 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
29529 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
29531 dd.setHandleElId(this.header.id);
29532 dd.endDrag = this.endMove.createDelegate(this);
29533 dd.startDrag = this.startMove.createDelegate(this);
29534 dd.onDrag = this.onDrag.createDelegate(this);
29539 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
29540 this.mask.enableDisplayMode("block");
29542 this.el.addClass("x-dlg-modal");
29545 this.shadow = new Roo.Shadow({
29546 mode : typeof this.shadow == "string" ? this.shadow : "sides",
29547 offset : this.shadowOffset
29550 this.shadowOffset = 0;
29552 if(Roo.useShims && this.shim !== false){
29553 this.shim = this.el.createShim();
29554 this.shim.hide = this.hideAction;
29562 if (this.buttons) {
29563 var bts= this.buttons;
29565 Roo.each(bts, function(b) {
29574 * Fires when a key is pressed
29575 * @param {Roo.BasicDialog} this
29576 * @param {Roo.EventObject} e
29581 * Fires when this dialog is moved by the user.
29582 * @param {Roo.BasicDialog} this
29583 * @param {Number} x The new page X
29584 * @param {Number} y The new page Y
29589 * Fires when this dialog is resized by the user.
29590 * @param {Roo.BasicDialog} this
29591 * @param {Number} width The new width
29592 * @param {Number} height The new height
29596 * @event beforehide
29597 * Fires before this dialog is hidden.
29598 * @param {Roo.BasicDialog} this
29600 "beforehide" : true,
29603 * Fires when this dialog is hidden.
29604 * @param {Roo.BasicDialog} this
29608 * @event beforeshow
29609 * Fires before this dialog is shown.
29610 * @param {Roo.BasicDialog} this
29612 "beforeshow" : true,
29615 * Fires when this dialog is shown.
29616 * @param {Roo.BasicDialog} this
29620 el.on("keydown", this.onKeyDown, this);
29621 el.on("mousedown", this.toFront, this);
29622 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
29624 Roo.DialogManager.register(this);
29625 Roo.BasicDialog.superclass.constructor.call(this);
29628 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
29629 shadowOffset: Roo.isIE ? 6 : 5,
29632 minButtonWidth: 75,
29633 defaultButton: null,
29634 buttonAlign: "right",
29639 * Sets the dialog title text
29640 * @param {String} text The title text to display
29641 * @return {Roo.BasicDialog} this
29643 setTitle : function(text){
29644 this.header.update(text);
29649 closeClick : function(){
29654 collapseClick : function(){
29655 this[this.collapsed ? "expand" : "collapse"]();
29659 * Collapses the dialog to its minimized state (only the title bar is visible).
29660 * Equivalent to the user clicking the collapse dialog button.
29662 collapse : function(){
29663 if(!this.collapsed){
29664 this.collapsed = true;
29665 this.el.addClass("x-dlg-collapsed");
29666 this.restoreHeight = this.el.getHeight();
29667 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29672 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29673 * clicking the expand dialog button.
29675 expand : function(){
29676 if(this.collapsed){
29677 this.collapsed = false;
29678 this.el.removeClass("x-dlg-collapsed");
29679 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29684 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29685 * @return {Roo.TabPanel} The tabs component
29687 initTabs : function(){
29688 var tabs = this.getTabs();
29689 while(tabs.getTab(0)){
29692 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29694 tabs.addTab(Roo.id(dom), dom.title);
29702 beforeResize : function(){
29703 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29707 onResize : function(){
29708 this.refreshSize();
29709 this.syncBodyHeight();
29710 this.adjustAssets();
29712 this.fireEvent("resize", this, this.size.width, this.size.height);
29716 onKeyDown : function(e){
29717 if(this.isVisible()){
29718 this.fireEvent("keydown", this, e);
29723 * Resizes the dialog.
29724 * @param {Number} width
29725 * @param {Number} height
29726 * @return {Roo.BasicDialog} this
29728 resizeTo : function(width, height){
29729 this.el.setSize(width, height);
29730 this.size = {width: width, height: height};
29731 this.syncBodyHeight();
29732 if(this.fixedcenter){
29735 if(this.isVisible()){
29736 this.constrainXY();
29737 this.adjustAssets();
29739 this.fireEvent("resize", this, width, height);
29745 * Resizes the dialog to fit the specified content size.
29746 * @param {Number} width
29747 * @param {Number} height
29748 * @return {Roo.BasicDialog} this
29750 setContentSize : function(w, h){
29751 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29752 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29753 //if(!this.el.isBorderBox()){
29754 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29755 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29758 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29759 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29761 this.resizeTo(w, h);
29766 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29767 * executed in response to a particular key being pressed while the dialog is active.
29768 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29769 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29770 * @param {Function} fn The function to call
29771 * @param {Object} scope (optional) The scope of the function
29772 * @return {Roo.BasicDialog} this
29774 addKeyListener : function(key, fn, scope){
29775 var keyCode, shift, ctrl, alt;
29776 if(typeof key == "object" && !(key instanceof Array)){
29777 keyCode = key["key"];
29778 shift = key["shift"];
29779 ctrl = key["ctrl"];
29784 var handler = function(dlg, e){
29785 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29786 var k = e.getKey();
29787 if(keyCode instanceof Array){
29788 for(var i = 0, len = keyCode.length; i < len; i++){
29789 if(keyCode[i] == k){
29790 fn.call(scope || window, dlg, k, e);
29796 fn.call(scope || window, dlg, k, e);
29801 this.on("keydown", handler);
29806 * Returns the TabPanel component (creates it if it doesn't exist).
29807 * Note: If you wish to simply check for the existence of tabs without creating them,
29808 * check for a null 'tabs' property.
29809 * @return {Roo.TabPanel} The tabs component
29811 getTabs : function(){
29813 this.el.addClass("x-dlg-auto-tabs");
29814 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29815 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29821 * Adds a button to the footer section of the dialog.
29822 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29823 * object or a valid Roo.DomHelper element config
29824 * @param {Function} handler The function called when the button is clicked
29825 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29826 * @return {Roo.Button} The new button
29828 addButton : function(config, handler, scope){
29829 var dh = Roo.DomHelper;
29831 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29833 if(!this.btnContainer){
29834 var tb = this.footer.createChild({
29836 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29837 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29839 this.btnContainer = tb.firstChild.firstChild.firstChild;
29844 minWidth: this.minButtonWidth,
29847 if(typeof config == "string"){
29848 bconfig.text = config;
29851 bconfig.dhconfig = config;
29853 Roo.apply(bconfig, config);
29857 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29858 bconfig.position = Math.max(0, bconfig.position);
29859 fc = this.btnContainer.childNodes[bconfig.position];
29862 var btn = new Roo.Button(
29864 this.btnContainer.insertBefore(document.createElement("td"),fc)
29865 : this.btnContainer.appendChild(document.createElement("td")),
29866 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29869 this.syncBodyHeight();
29872 * Array of all the buttons that have been added to this dialog via addButton
29877 this.buttons.push(btn);
29882 * Sets the default button to be focused when the dialog is displayed.
29883 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29884 * @return {Roo.BasicDialog} this
29886 setDefaultButton : function(btn){
29887 this.defaultButton = btn;
29892 getHeaderFooterHeight : function(safe){
29895 height += this.header.getHeight();
29898 var fm = this.footer.getMargins();
29899 height += (this.footer.getHeight()+fm.top+fm.bottom);
29901 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29902 height += this.centerBg.getPadding("tb");
29907 syncBodyHeight : function()
29909 var bd = this.body, // the text
29910 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
29912 var height = this.size.height - this.getHeaderFooterHeight(false);
29913 bd.setHeight(height-bd.getMargins("tb"));
29914 var hh = this.header.getHeight();
29915 var h = this.size.height-hh;
29918 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29919 bw.setHeight(h-cb.getPadding("tb"));
29921 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29922 bd.setWidth(bw.getWidth(true));
29924 this.tabs.syncHeight();
29926 this.tabs.el.repaint();
29932 * Restores the previous state of the dialog if Roo.state is configured.
29933 * @return {Roo.BasicDialog} this
29935 restoreState : function(){
29936 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29937 if(box && box.width){
29938 this.xy = [box.x, box.y];
29939 this.resizeTo(box.width, box.height);
29945 beforeShow : function(){
29947 if(this.fixedcenter){
29948 this.xy = this.el.getCenterXY(true);
29951 Roo.get(document.body).addClass("x-body-masked");
29952 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29955 this.constrainXY();
29959 animShow : function(){
29960 var b = Roo.get(this.animateTarget).getBox();
29961 this.proxy.setSize(b.width, b.height);
29962 this.proxy.setLocation(b.x, b.y);
29964 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29965 true, .35, this.showEl.createDelegate(this));
29969 * Shows the dialog.
29970 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29971 * @return {Roo.BasicDialog} this
29973 show : function(animateTarget){
29974 if (this.fireEvent("beforeshow", this) === false){
29977 if(this.syncHeightBeforeShow){
29978 this.syncBodyHeight();
29979 }else if(this.firstShow){
29980 this.firstShow = false;
29981 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29983 this.animateTarget = animateTarget || this.animateTarget;
29984 if(!this.el.isVisible()){
29986 if(this.animateTarget && Roo.get(this.animateTarget)){
29996 showEl : function(){
29998 this.el.setXY(this.xy);
30000 this.adjustAssets(true);
30003 // IE peekaboo bug - fix found by Dave Fenwick
30007 this.fireEvent("show", this);
30011 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30012 * dialog itself will receive focus.
30014 focus : function(){
30015 if(this.defaultButton){
30016 this.defaultButton.focus();
30018 this.focusEl.focus();
30023 constrainXY : function(){
30024 if(this.constraintoviewport !== false){
30025 if(!this.viewSize){
30026 if(this.container){
30027 var s = this.container.getSize();
30028 this.viewSize = [s.width, s.height];
30030 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30033 var s = Roo.get(this.container||document).getScroll();
30035 var x = this.xy[0], y = this.xy[1];
30036 var w = this.size.width, h = this.size.height;
30037 var vw = this.viewSize[0], vh = this.viewSize[1];
30038 // only move it if it needs it
30040 // first validate right/bottom
30041 if(x + w > vw+s.left){
30045 if(y + h > vh+s.top){
30049 // then make sure top/left isn't negative
30061 if(this.isVisible()){
30062 this.el.setLocation(x, y);
30063 this.adjustAssets();
30070 onDrag : function(){
30071 if(!this.proxyDrag){
30072 this.xy = this.el.getXY();
30073 this.adjustAssets();
30078 adjustAssets : function(doShow){
30079 var x = this.xy[0], y = this.xy[1];
30080 var w = this.size.width, h = this.size.height;
30081 if(doShow === true){
30083 this.shadow.show(this.el);
30089 if(this.shadow && this.shadow.isVisible()){
30090 this.shadow.show(this.el);
30092 if(this.shim && this.shim.isVisible()){
30093 this.shim.setBounds(x, y, w, h);
30098 adjustViewport : function(w, h){
30100 w = Roo.lib.Dom.getViewWidth();
30101 h = Roo.lib.Dom.getViewHeight();
30104 this.viewSize = [w, h];
30105 if(this.modal && this.mask.isVisible()){
30106 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30107 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30109 if(this.isVisible()){
30110 this.constrainXY();
30115 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30116 * shadow, proxy, mask, etc.) Also removes all event listeners.
30117 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30119 destroy : function(removeEl){
30120 if(this.isVisible()){
30121 this.animateTarget = null;
30124 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30126 this.tabs.destroy(removeEl);
30139 for(var i = 0, len = this.buttons.length; i < len; i++){
30140 this.buttons[i].destroy();
30143 this.el.removeAllListeners();
30144 if(removeEl === true){
30145 this.el.update("");
30148 Roo.DialogManager.unregister(this);
30152 startMove : function(){
30153 if(this.proxyDrag){
30156 if(this.constraintoviewport !== false){
30157 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30162 endMove : function(){
30163 if(!this.proxyDrag){
30164 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30166 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30169 this.refreshSize();
30170 this.adjustAssets();
30172 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30176 * Brings this dialog to the front of any other visible dialogs
30177 * @return {Roo.BasicDialog} this
30179 toFront : function(){
30180 Roo.DialogManager.bringToFront(this);
30185 * Sends this dialog to the back (under) of any other visible dialogs
30186 * @return {Roo.BasicDialog} this
30188 toBack : function(){
30189 Roo.DialogManager.sendToBack(this);
30194 * Centers this dialog in the viewport
30195 * @return {Roo.BasicDialog} this
30197 center : function(){
30198 var xy = this.el.getCenterXY(true);
30199 this.moveTo(xy[0], xy[1]);
30204 * Moves the dialog's top-left corner to the specified point
30205 * @param {Number} x
30206 * @param {Number} y
30207 * @return {Roo.BasicDialog} this
30209 moveTo : function(x, y){
30211 if(this.isVisible()){
30212 this.el.setXY(this.xy);
30213 this.adjustAssets();
30219 * Aligns the dialog to the specified element
30220 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30221 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30222 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30223 * @return {Roo.BasicDialog} this
30225 alignTo : function(element, position, offsets){
30226 this.xy = this.el.getAlignToXY(element, position, offsets);
30227 if(this.isVisible()){
30228 this.el.setXY(this.xy);
30229 this.adjustAssets();
30235 * Anchors an element to another element and realigns it when the window is resized.
30236 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30237 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30238 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30239 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30240 * is a number, it is used as the buffer delay (defaults to 50ms).
30241 * @return {Roo.BasicDialog} this
30243 anchorTo : function(el, alignment, offsets, monitorScroll){
30244 var action = function(){
30245 this.alignTo(el, alignment, offsets);
30247 Roo.EventManager.onWindowResize(action, this);
30248 var tm = typeof monitorScroll;
30249 if(tm != 'undefined'){
30250 Roo.EventManager.on(window, 'scroll', action, this,
30251 {buffer: tm == 'number' ? monitorScroll : 50});
30258 * Returns true if the dialog is visible
30259 * @return {Boolean}
30261 isVisible : function(){
30262 return this.el.isVisible();
30266 animHide : function(callback){
30267 var b = Roo.get(this.animateTarget).getBox();
30269 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30271 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30272 this.hideEl.createDelegate(this, [callback]));
30276 * Hides the dialog.
30277 * @param {Function} callback (optional) Function to call when the dialog is hidden
30278 * @return {Roo.BasicDialog} this
30280 hide : function(callback){
30281 if (this.fireEvent("beforehide", this) === false){
30285 this.shadow.hide();
30290 // sometimes animateTarget seems to get set.. causing problems...
30291 // this just double checks..
30292 if(this.animateTarget && Roo.get(this.animateTarget)) {
30293 this.animHide(callback);
30296 this.hideEl(callback);
30302 hideEl : function(callback){
30306 Roo.get(document.body).removeClass("x-body-masked");
30308 this.fireEvent("hide", this);
30309 if(typeof callback == "function"){
30315 hideAction : function(){
30316 this.setLeft("-10000px");
30317 this.setTop("-10000px");
30318 this.setStyle("visibility", "hidden");
30322 refreshSize : function(){
30323 this.size = this.el.getSize();
30324 this.xy = this.el.getXY();
30325 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30329 // z-index is managed by the DialogManager and may be overwritten at any time
30330 setZIndex : function(index){
30332 this.mask.setStyle("z-index", index);
30335 this.shim.setStyle("z-index", ++index);
30338 this.shadow.setZIndex(++index);
30340 this.el.setStyle("z-index", ++index);
30342 this.proxy.setStyle("z-index", ++index);
30345 this.resizer.proxy.setStyle("z-index", ++index);
30348 this.lastZIndex = index;
30352 * Returns the element for this dialog
30353 * @return {Roo.Element} The underlying dialog Element
30355 getEl : function(){
30361 * @class Roo.DialogManager
30362 * Provides global access to BasicDialogs that have been created and
30363 * support for z-indexing (layering) multiple open dialogs.
30365 Roo.DialogManager = function(){
30367 var accessList = [];
30371 var sortDialogs = function(d1, d2){
30372 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30376 var orderDialogs = function(){
30377 accessList.sort(sortDialogs);
30378 var seed = Roo.DialogManager.zseed;
30379 for(var i = 0, len = accessList.length; i < len; i++){
30380 var dlg = accessList[i];
30382 dlg.setZIndex(seed + (i*10));
30389 * The starting z-index for BasicDialogs (defaults to 9000)
30390 * @type Number The z-index value
30395 register : function(dlg){
30396 list[dlg.id] = dlg;
30397 accessList.push(dlg);
30401 unregister : function(dlg){
30402 delete list[dlg.id];
30405 if(!accessList.indexOf){
30406 for( i = 0, len = accessList.length; i < len; i++){
30407 if(accessList[i] == dlg){
30408 accessList.splice(i, 1);
30413 i = accessList.indexOf(dlg);
30415 accessList.splice(i, 1);
30421 * Gets a registered dialog by id
30422 * @param {String/Object} id The id of the dialog or a dialog
30423 * @return {Roo.BasicDialog} this
30425 get : function(id){
30426 return typeof id == "object" ? id : list[id];
30430 * Brings the specified dialog to the front
30431 * @param {String/Object} dlg The id of the dialog or a dialog
30432 * @return {Roo.BasicDialog} this
30434 bringToFront : function(dlg){
30435 dlg = this.get(dlg);
30438 dlg._lastAccess = new Date().getTime();
30445 * Sends the specified dialog to the back
30446 * @param {String/Object} dlg The id of the dialog or a dialog
30447 * @return {Roo.BasicDialog} this
30449 sendToBack : function(dlg){
30450 dlg = this.get(dlg);
30451 dlg._lastAccess = -(new Date().getTime());
30457 * Hides all dialogs
30459 hideAll : function(){
30460 for(var id in list){
30461 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
30470 * @class Roo.LayoutDialog
30471 * @extends Roo.BasicDialog
30472 * Dialog which provides adjustments for working with a layout in a Dialog.
30473 * Add your necessary layout config options to the dialog's config.<br>
30474 * Example usage (including a nested layout):
30477 dialog = new Roo.LayoutDialog("download-dlg", {
30486 // layout config merges with the dialog config
30488 tabPosition: "top",
30489 alwaysShowTabs: true
30492 dialog.addKeyListener(27, dialog.hide, dialog);
30493 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
30494 dialog.addButton("Build It!", this.getDownload, this);
30496 // we can even add nested layouts
30497 var innerLayout = new Roo.BorderLayout("dl-inner", {
30507 innerLayout.beginUpdate();
30508 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
30509 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
30510 innerLayout.endUpdate(true);
30512 var layout = dialog.getLayout();
30513 layout.beginUpdate();
30514 layout.add("center", new Roo.ContentPanel("standard-panel",
30515 {title: "Download the Source", fitToFrame:true}));
30516 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
30517 {title: "Build your own roo.js"}));
30518 layout.getRegion("center").showPanel(sp);
30519 layout.endUpdate();
30523 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
30524 * @param {Object} config configuration options
30526 Roo.LayoutDialog = function(el, cfg){
30529 if (typeof(cfg) == 'undefined') {
30530 config = Roo.apply({}, el);
30531 // not sure why we use documentElement here.. - it should always be body.
30532 // IE7 borks horribly if we use documentElement.
30533 // webkit also does not like documentElement - it creates a body element...
30534 el = Roo.get( document.body || document.documentElement ).createChild();
30535 //config.autoCreate = true;
30539 config.autoTabs = false;
30540 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
30541 this.body.setStyle({overflow:"hidden", position:"relative"});
30542 this.layout = new Roo.BorderLayout(this.body.dom, config);
30543 this.layout.monitorWindowResize = false;
30544 this.el.addClass("x-dlg-auto-layout");
30545 // fix case when center region overwrites center function
30546 this.center = Roo.BasicDialog.prototype.center;
30547 this.on("show", this.layout.layout, this.layout, true);
30548 if (config.items) {
30549 var xitems = config.items;
30550 delete config.items;
30551 Roo.each(xitems, this.addxtype, this);
30556 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
30558 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
30561 endUpdate : function(){
30562 this.layout.endUpdate();
30566 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
30569 beginUpdate : function(){
30570 this.layout.beginUpdate();
30574 * Get the BorderLayout for this dialog
30575 * @return {Roo.BorderLayout}
30577 getLayout : function(){
30578 return this.layout;
30581 showEl : function(){
30582 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
30584 this.layout.layout();
30589 // Use the syncHeightBeforeShow config option to control this automatically
30590 syncBodyHeight : function(){
30591 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
30592 if(this.layout){this.layout.layout();}
30596 * Add an xtype element (actually adds to the layout.)
30597 * @return {Object} xdata xtype object data.
30600 addxtype : function(c) {
30601 return this.layout.addxtype(c);
30605 * Ext JS Library 1.1.1
30606 * Copyright(c) 2006-2007, Ext JS, LLC.
30608 * Originally Released Under LGPL - original licence link has changed is not relivant.
30611 * <script type="text/javascript">
30615 * @class Roo.MessageBox
30616 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
30620 Roo.Msg.alert('Status', 'Changes saved successfully.');
30622 // Prompt for user data:
30623 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
30625 // process text value...
30629 // Show a dialog using config options:
30631 title:'Save Changes?',
30632 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
30633 buttons: Roo.Msg.YESNOCANCEL,
30640 Roo.MessageBox = function(){
30641 var dlg, opt, mask, waitTimer;
30642 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30643 var buttons, activeTextEl, bwidth;
30646 var handleButton = function(button){
30648 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30652 var handleHide = function(){
30653 if(opt && opt.cls){
30654 dlg.el.removeClass(opt.cls);
30657 Roo.TaskMgr.stop(waitTimer);
30663 var updateButtons = function(b){
30666 buttons["ok"].hide();
30667 buttons["cancel"].hide();
30668 buttons["yes"].hide();
30669 buttons["no"].hide();
30670 dlg.footer.dom.style.display = 'none';
30673 dlg.footer.dom.style.display = '';
30674 for(var k in buttons){
30675 if(typeof buttons[k] != "function"){
30678 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30679 width += buttons[k].el.getWidth()+15;
30689 var handleEsc = function(d, k, e){
30690 if(opt && opt.closable !== false){
30700 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30701 * @return {Roo.BasicDialog} The BasicDialog element
30703 getDialog : function(){
30705 dlg = new Roo.BasicDialog("x-msg-box", {
30710 constraintoviewport:false,
30712 collapsible : false,
30715 width:400, height:100,
30716 buttonAlign:"center",
30717 closeClick : function(){
30718 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30719 handleButton("no");
30721 handleButton("cancel");
30725 dlg.on("hide", handleHide);
30727 dlg.addKeyListener(27, handleEsc);
30729 var bt = this.buttonText;
30730 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30731 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30732 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30733 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30734 bodyEl = dlg.body.createChild({
30736 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>'
30738 msgEl = bodyEl.dom.firstChild;
30739 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30740 textboxEl.enableDisplayMode();
30741 textboxEl.addKeyListener([10,13], function(){
30742 if(dlg.isVisible() && opt && opt.buttons){
30743 if(opt.buttons.ok){
30744 handleButton("ok");
30745 }else if(opt.buttons.yes){
30746 handleButton("yes");
30750 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30751 textareaEl.enableDisplayMode();
30752 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30753 progressEl.enableDisplayMode();
30754 var pf = progressEl.dom.firstChild;
30756 pp = Roo.get(pf.firstChild);
30757 pp.setHeight(pf.offsetHeight);
30765 * Updates the message box body text
30766 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30767 * the XHTML-compliant non-breaking space character '&#160;')
30768 * @return {Roo.MessageBox} This message box
30770 updateText : function(text){
30771 if(!dlg.isVisible() && !opt.width){
30772 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30774 msgEl.innerHTML = text || ' ';
30776 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30777 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30779 Math.min(opt.width || cw , this.maxWidth),
30780 Math.max(opt.minWidth || this.minWidth, bwidth)
30783 activeTextEl.setWidth(w);
30785 if(dlg.isVisible()){
30786 dlg.fixedcenter = false;
30788 // to big, make it scroll. = But as usual stupid IE does not support
30791 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30792 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30793 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
30795 bodyEl.dom.style.height = '';
30796 bodyEl.dom.style.overflowY = '';
30799 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
30801 bodyEl.dom.style.overflowX = '';
30804 dlg.setContentSize(w, bodyEl.getHeight());
30805 if(dlg.isVisible()){
30806 dlg.fixedcenter = true;
30812 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30813 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30814 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30815 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30816 * @return {Roo.MessageBox} This message box
30818 updateProgress : function(value, text){
30820 this.updateText(text);
30822 if (pp) { // weird bug on my firefox - for some reason this is not defined
30823 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30829 * Returns true if the message box is currently displayed
30830 * @return {Boolean} True if the message box is visible, else false
30832 isVisible : function(){
30833 return dlg && dlg.isVisible();
30837 * Hides the message box if it is displayed
30840 if(this.isVisible()){
30846 * Displays a new message box, or reinitializes an existing message box, based on the config options
30847 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30848 * The following config object properties are supported:
30850 Property Type Description
30851 ---------- --------------- ------------------------------------------------------------------------------------
30852 animEl String/Element An id or Element from which the message box should animate as it opens and
30853 closes (defaults to undefined)
30854 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30855 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30856 closable Boolean False to hide the top-right close button (defaults to true). Note that
30857 progress and wait dialogs will ignore this property and always hide the
30858 close button as they can only be closed programmatically.
30859 cls String A custom CSS class to apply to the message box element
30860 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30861 displayed (defaults to 75)
30862 fn Function A callback function to execute after closing the dialog. The arguments to the
30863 function will be btn (the name of the button that was clicked, if applicable,
30864 e.g. "ok"), and text (the value of the active text field, if applicable).
30865 Progress and wait dialogs will ignore this option since they do not respond to
30866 user actions and can only be closed programmatically, so any required function
30867 should be called by the same code after it closes the dialog.
30868 icon String A CSS class that provides a background image to be used as an icon for
30869 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30870 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30871 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30872 modal Boolean False to allow user interaction with the page while the message box is
30873 displayed (defaults to true)
30874 msg String A string that will replace the existing message box body text (defaults
30875 to the XHTML-compliant non-breaking space character ' ')
30876 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30877 progress Boolean True to display a progress bar (defaults to false)
30878 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30879 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30880 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30881 title String The title text
30882 value String The string value to set into the active textbox element if displayed
30883 wait Boolean True to display a progress bar (defaults to false)
30884 width Number The width of the dialog in pixels
30891 msg: 'Please enter your address:',
30893 buttons: Roo.MessageBox.OKCANCEL,
30896 animEl: 'addAddressBtn'
30899 * @param {Object} config Configuration options
30900 * @return {Roo.MessageBox} This message box
30902 show : function(options)
30905 // this causes nightmares if you show one dialog after another
30906 // especially on callbacks..
30908 if(this.isVisible()){
30911 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
30912 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
30913 Roo.log("New Dialog Message:" + options.msg )
30914 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30915 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30918 var d = this.getDialog();
30920 d.setTitle(opt.title || " ");
30921 d.close.setDisplayed(opt.closable !== false);
30922 activeTextEl = textboxEl;
30923 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30928 textareaEl.setHeight(typeof opt.multiline == "number" ?
30929 opt.multiline : this.defaultTextHeight);
30930 activeTextEl = textareaEl;
30939 progressEl.setDisplayed(opt.progress === true);
30940 this.updateProgress(0);
30941 activeTextEl.dom.value = opt.value || "";
30943 dlg.setDefaultButton(activeTextEl);
30945 var bs = opt.buttons;
30948 db = buttons["ok"];
30949 }else if(bs && bs.yes){
30950 db = buttons["yes"];
30952 dlg.setDefaultButton(db);
30954 bwidth = updateButtons(opt.buttons);
30955 this.updateText(opt.msg);
30957 d.el.addClass(opt.cls);
30959 d.proxyDrag = opt.proxyDrag === true;
30960 d.modal = opt.modal !== false;
30961 d.mask = opt.modal !== false ? mask : false;
30962 if(!d.isVisible()){
30963 // force it to the end of the z-index stack so it gets a cursor in FF
30964 document.body.appendChild(dlg.el.dom);
30965 d.animateTarget = null;
30966 d.show(options.animEl);
30972 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30973 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30974 * and closing the message box when the process is complete.
30975 * @param {String} title The title bar text
30976 * @param {String} msg The message box body text
30977 * @return {Roo.MessageBox} This message box
30979 progress : function(title, msg){
30986 minWidth: this.minProgressWidth,
30993 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30994 * If a callback function is passed it will be called after the user clicks the button, and the
30995 * id of the button that was clicked will be passed as the only parameter to the callback
30996 * (could also be the top-right close button).
30997 * @param {String} title The title bar text
30998 * @param {String} msg The message box body text
30999 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31000 * @param {Object} scope (optional) The scope of the callback function
31001 * @return {Roo.MessageBox} This message box
31003 alert : function(title, msg, fn, scope){
31016 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31017 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31018 * You are responsible for closing the message box when the process is complete.
31019 * @param {String} msg The message box body text
31020 * @param {String} title (optional) The title bar text
31021 * @return {Roo.MessageBox} This message box
31023 wait : function(msg, title){
31034 waitTimer = Roo.TaskMgr.start({
31036 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31044 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31045 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31046 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31047 * @param {String} title The title bar text
31048 * @param {String} msg The message box body text
31049 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31050 * @param {Object} scope (optional) The scope of the callback function
31051 * @return {Roo.MessageBox} This message box
31053 confirm : function(title, msg, fn, scope){
31057 buttons: this.YESNO,
31066 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31067 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31068 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31069 * (could also be the top-right close button) and the text that was entered will be passed as the two
31070 * parameters to the callback.
31071 * @param {String} title The title bar text
31072 * @param {String} msg The message box body text
31073 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31074 * @param {Object} scope (optional) The scope of the callback function
31075 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31076 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31077 * @return {Roo.MessageBox} This message box
31079 prompt : function(title, msg, fn, scope, multiline){
31083 buttons: this.OKCANCEL,
31088 multiline: multiline,
31095 * Button config that displays a single OK button
31100 * Button config that displays Yes and No buttons
31103 YESNO : {yes:true, no:true},
31105 * Button config that displays OK and Cancel buttons
31108 OKCANCEL : {ok:true, cancel:true},
31110 * Button config that displays Yes, No and Cancel buttons
31113 YESNOCANCEL : {yes:true, no:true, cancel:true},
31116 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31119 defaultTextHeight : 75,
31121 * The maximum width in pixels of the message box (defaults to 600)
31126 * The minimum width in pixels of the message box (defaults to 100)
31131 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31132 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31135 minProgressWidth : 250,
31137 * An object containing the default button text strings that can be overriden for localized language support.
31138 * Supported properties are: ok, cancel, yes and no.
31139 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31152 * Shorthand for {@link Roo.MessageBox}
31154 Roo.Msg = Roo.MessageBox;/*
31156 * Ext JS Library 1.1.1
31157 * Copyright(c) 2006-2007, Ext JS, LLC.
31159 * Originally Released Under LGPL - original licence link has changed is not relivant.
31162 * <script type="text/javascript">
31165 * @class Roo.QuickTips
31166 * Provides attractive and customizable tooltips for any element.
31169 Roo.QuickTips = function(){
31170 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31171 var ce, bd, xy, dd;
31172 var visible = false, disabled = true, inited = false;
31173 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31175 var onOver = function(e){
31179 var t = e.getTarget();
31180 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31183 if(ce && t == ce.el){
31184 clearTimeout(hideProc);
31187 if(t && tagEls[t.id]){
31188 tagEls[t.id].el = t;
31189 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31192 var ttp, et = Roo.fly(t);
31193 var ns = cfg.namespace;
31194 if(tm.interceptTitles && t.title){
31197 t.removeAttribute("title");
31198 e.preventDefault();
31200 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31203 showProc = show.defer(tm.showDelay, tm, [{
31206 width: et.getAttributeNS(ns, cfg.width),
31207 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31208 title: et.getAttributeNS(ns, cfg.title),
31209 cls: et.getAttributeNS(ns, cfg.cls)
31214 var onOut = function(e){
31215 clearTimeout(showProc);
31216 var t = e.getTarget();
31217 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31218 hideProc = setTimeout(hide, tm.hideDelay);
31222 var onMove = function(e){
31228 if(tm.trackMouse && ce){
31233 var onDown = function(e){
31234 clearTimeout(showProc);
31235 clearTimeout(hideProc);
31237 if(tm.hideOnClick){
31240 tm.enable.defer(100, tm);
31245 var getPad = function(){
31246 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31249 var show = function(o){
31253 clearTimeout(dismissProc);
31255 if(removeCls){ // in case manually hidden
31256 el.removeClass(removeCls);
31260 el.addClass(ce.cls);
31261 removeCls = ce.cls;
31264 tipTitle.update(ce.title);
31267 tipTitle.update('');
31270 el.dom.style.width = tm.maxWidth+'px';
31271 //tipBody.dom.style.width = '';
31272 tipBodyText.update(o.text);
31273 var p = getPad(), w = ce.width;
31275 var td = tipBodyText.dom;
31276 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31277 if(aw > tm.maxWidth){
31279 }else if(aw < tm.minWidth){
31285 //tipBody.setWidth(w);
31286 el.setWidth(parseInt(w, 10) + p);
31287 if(ce.autoHide === false){
31288 close.setDisplayed(true);
31293 close.setDisplayed(false);
31299 el.avoidY = xy[1]-18;
31304 el.setStyle("visibility", "visible");
31305 el.fadeIn({callback: afterShow});
31311 var afterShow = function(){
31315 if(tm.autoDismiss && ce.autoHide !== false){
31316 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31321 var hide = function(noanim){
31322 clearTimeout(dismissProc);
31323 clearTimeout(hideProc);
31325 if(el.isVisible()){
31327 if(noanim !== true && tm.animate){
31328 el.fadeOut({callback: afterHide});
31335 var afterHide = function(){
31338 el.removeClass(removeCls);
31345 * @cfg {Number} minWidth
31346 * The minimum width of the quick tip (defaults to 40)
31350 * @cfg {Number} maxWidth
31351 * The maximum width of the quick tip (defaults to 300)
31355 * @cfg {Boolean} interceptTitles
31356 * True to automatically use the element's DOM title value if available (defaults to false)
31358 interceptTitles : false,
31360 * @cfg {Boolean} trackMouse
31361 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31363 trackMouse : false,
31365 * @cfg {Boolean} hideOnClick
31366 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31368 hideOnClick : true,
31370 * @cfg {Number} showDelay
31371 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31375 * @cfg {Number} hideDelay
31376 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31380 * @cfg {Boolean} autoHide
31381 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31382 * Used in conjunction with hideDelay.
31387 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31388 * (defaults to true). Used in conjunction with autoDismissDelay.
31390 autoDismiss : true,
31393 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31395 autoDismissDelay : 5000,
31397 * @cfg {Boolean} animate
31398 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31403 * @cfg {String} title
31404 * Title text to display (defaults to ''). This can be any valid HTML markup.
31408 * @cfg {String} text
31409 * Body text to display (defaults to ''). This can be any valid HTML markup.
31413 * @cfg {String} cls
31414 * A CSS class to apply to the base quick tip element (defaults to '').
31418 * @cfg {Number} width
31419 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
31420 * minWidth or maxWidth.
31425 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
31426 * or display QuickTips in a page.
31429 tm = Roo.QuickTips;
31430 cfg = tm.tagConfig;
31432 if(!Roo.isReady){ // allow calling of init() before onReady
31433 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
31436 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
31437 el.fxDefaults = {stopFx: true};
31438 // maximum custom styling
31439 //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>');
31440 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>');
31441 tipTitle = el.child('h3');
31442 tipTitle.enableDisplayMode("block");
31443 tipBody = el.child('div.x-tip-bd');
31444 tipBodyText = el.child('div.x-tip-bd-inner');
31445 //bdLeft = el.child('div.x-tip-bd-left');
31446 //bdRight = el.child('div.x-tip-bd-right');
31447 close = el.child('div.x-tip-close');
31448 close.enableDisplayMode("block");
31449 close.on("click", hide);
31450 var d = Roo.get(document);
31451 d.on("mousedown", onDown);
31452 d.on("mouseover", onOver);
31453 d.on("mouseout", onOut);
31454 d.on("mousemove", onMove);
31455 esc = d.addKeyListener(27, hide);
31458 dd = el.initDD("default", null, {
31459 onDrag : function(){
31463 dd.setHandleElId(tipTitle.id);
31472 * Configures a new quick tip instance and assigns it to a target element. The following config options
31475 Property Type Description
31476 ---------- --------------------- ------------------------------------------------------------------------
31477 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
31479 * @param {Object} config The config object
31481 register : function(config){
31482 var cs = config instanceof Array ? config : arguments;
31483 for(var i = 0, len = cs.length; i < len; i++) {
31485 var target = c.target;
31487 if(target instanceof Array){
31488 for(var j = 0, jlen = target.length; j < jlen; j++){
31489 tagEls[target[j]] = c;
31492 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
31499 * Removes this quick tip from its element and destroys it.
31500 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
31502 unregister : function(el){
31503 delete tagEls[Roo.id(el)];
31507 * Enable this quick tip.
31509 enable : function(){
31510 if(inited && disabled){
31512 if(locks.length < 1){
31519 * Disable this quick tip.
31521 disable : function(){
31523 clearTimeout(showProc);
31524 clearTimeout(hideProc);
31525 clearTimeout(dismissProc);
31533 * Returns true if the quick tip is enabled, else false.
31535 isEnabled : function(){
31542 attribute : "qtip",
31552 // backwards compat
31553 Roo.QuickTips.tips = Roo.QuickTips.register;/*
31555 * Ext JS Library 1.1.1
31556 * Copyright(c) 2006-2007, Ext JS, LLC.
31558 * Originally Released Under LGPL - original licence link has changed is not relivant.
31561 * <script type="text/javascript">
31566 * @class Roo.tree.TreePanel
31567 * @extends Roo.data.Tree
31569 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
31570 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
31571 * @cfg {Boolean} enableDD true to enable drag and drop
31572 * @cfg {Boolean} enableDrag true to enable just drag
31573 * @cfg {Boolean} enableDrop true to enable just drop
31574 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
31575 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
31576 * @cfg {String} ddGroup The DD group this TreePanel belongs to
31577 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
31578 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
31579 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
31580 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
31581 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
31582 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
31583 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
31584 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
31585 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
31586 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
31587 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
31588 * @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>
31589 * @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>
31592 * @param {String/HTMLElement/Element} el The container element
31593 * @param {Object} config
31595 Roo.tree.TreePanel = function(el, config){
31597 var loader = false;
31599 root = config.root;
31600 delete config.root;
31602 if (config.loader) {
31603 loader = config.loader;
31604 delete config.loader;
31607 Roo.apply(this, config);
31608 Roo.tree.TreePanel.superclass.constructor.call(this);
31609 this.el = Roo.get(el);
31610 this.el.addClass('x-tree');
31611 //console.log(root);
31613 this.setRootNode( Roo.factory(root, Roo.tree));
31616 this.loader = Roo.factory(loader, Roo.tree);
31619 * Read-only. The id of the container element becomes this TreePanel's id.
31621 this.id = this.el.id;
31624 * @event beforeload
31625 * Fires before a node is loaded, return false to cancel
31626 * @param {Node} node The node being loaded
31628 "beforeload" : true,
31631 * Fires when a node is loaded
31632 * @param {Node} node The node that was loaded
31636 * @event textchange
31637 * Fires when the text for a node is changed
31638 * @param {Node} node The node
31639 * @param {String} text The new text
31640 * @param {String} oldText The old text
31642 "textchange" : true,
31644 * @event beforeexpand
31645 * Fires before a node is expanded, return false to cancel.
31646 * @param {Node} node The node
31647 * @param {Boolean} deep
31648 * @param {Boolean} anim
31650 "beforeexpand" : true,
31652 * @event beforecollapse
31653 * Fires before a node is collapsed, return false to cancel.
31654 * @param {Node} node The node
31655 * @param {Boolean} deep
31656 * @param {Boolean} anim
31658 "beforecollapse" : true,
31661 * Fires when a node is expanded
31662 * @param {Node} node The node
31666 * @event disabledchange
31667 * Fires when the disabled status of a node changes
31668 * @param {Node} node The node
31669 * @param {Boolean} disabled
31671 "disabledchange" : true,
31674 * Fires when a node is collapsed
31675 * @param {Node} node The node
31679 * @event beforeclick
31680 * Fires before click processing on a node. Return false to cancel the default action.
31681 * @param {Node} node The node
31682 * @param {Roo.EventObject} e The event object
31684 "beforeclick":true,
31686 * @event checkchange
31687 * Fires when a node with a checkbox's checked property changes
31688 * @param {Node} this This node
31689 * @param {Boolean} checked
31691 "checkchange":true,
31694 * Fires when a node is clicked
31695 * @param {Node} node The node
31696 * @param {Roo.EventObject} e The event object
31701 * Fires when a node is double clicked
31702 * @param {Node} node The node
31703 * @param {Roo.EventObject} e The event object
31707 * @event contextmenu
31708 * Fires when a node is right clicked
31709 * @param {Node} node The node
31710 * @param {Roo.EventObject} e The event object
31712 "contextmenu":true,
31714 * @event beforechildrenrendered
31715 * Fires right before the child nodes for a node are rendered
31716 * @param {Node} node The node
31718 "beforechildrenrendered":true,
31721 * Fires when a node starts being dragged
31722 * @param {Roo.tree.TreePanel} this
31723 * @param {Roo.tree.TreeNode} node
31724 * @param {event} e The raw browser event
31726 "startdrag" : true,
31729 * Fires when a drag operation is complete
31730 * @param {Roo.tree.TreePanel} this
31731 * @param {Roo.tree.TreeNode} node
31732 * @param {event} e The raw browser event
31737 * Fires when a dragged node is dropped on a valid DD target
31738 * @param {Roo.tree.TreePanel} this
31739 * @param {Roo.tree.TreeNode} node
31740 * @param {DD} dd The dd it was dropped on
31741 * @param {event} e The raw browser event
31745 * @event beforenodedrop
31746 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31747 * passed to handlers has the following properties:<br />
31748 * <ul style="padding:5px;padding-left:16px;">
31749 * <li>tree - The TreePanel</li>
31750 * <li>target - The node being targeted for the drop</li>
31751 * <li>data - The drag data from the drag source</li>
31752 * <li>point - The point of the drop - append, above or below</li>
31753 * <li>source - The drag source</li>
31754 * <li>rawEvent - Raw mouse event</li>
31755 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31756 * to be inserted by setting them on this object.</li>
31757 * <li>cancel - Set this to true to cancel the drop.</li>
31759 * @param {Object} dropEvent
31761 "beforenodedrop" : true,
31764 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31765 * passed to handlers has the following properties:<br />
31766 * <ul style="padding:5px;padding-left:16px;">
31767 * <li>tree - The TreePanel</li>
31768 * <li>target - The node being targeted for the drop</li>
31769 * <li>data - The drag data from the drag source</li>
31770 * <li>point - The point of the drop - append, above or below</li>
31771 * <li>source - The drag source</li>
31772 * <li>rawEvent - Raw mouse event</li>
31773 * <li>dropNode - Dropped node(s).</li>
31775 * @param {Object} dropEvent
31779 * @event nodedragover
31780 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31781 * passed to handlers has the following properties:<br />
31782 * <ul style="padding:5px;padding-left:16px;">
31783 * <li>tree - The TreePanel</li>
31784 * <li>target - The node being targeted for the drop</li>
31785 * <li>data - The drag data from the drag source</li>
31786 * <li>point - The point of the drop - append, above or below</li>
31787 * <li>source - The drag source</li>
31788 * <li>rawEvent - Raw mouse event</li>
31789 * <li>dropNode - Drop node(s) provided by the source.</li>
31790 * <li>cancel - Set this to true to signal drop not allowed.</li>
31792 * @param {Object} dragOverEvent
31794 "nodedragover" : true
31797 if(this.singleExpand){
31798 this.on("beforeexpand", this.restrictExpand, this);
31801 this.editor.tree = this;
31802 this.editor = Roo.factory(this.editor, Roo.tree);
31805 if (this.selModel) {
31806 this.selModel = Roo.factory(this.selModel, Roo.tree);
31810 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31811 rootVisible : true,
31812 animate: Roo.enableFx,
31815 hlDrop : Roo.enableFx,
31819 rendererTip: false,
31821 restrictExpand : function(node){
31822 var p = node.parentNode;
31824 if(p.expandedChild && p.expandedChild.parentNode == p){
31825 p.expandedChild.collapse();
31827 p.expandedChild = node;
31831 // private override
31832 setRootNode : function(node){
31833 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31834 if(!this.rootVisible){
31835 node.ui = new Roo.tree.RootTreeNodeUI(node);
31841 * Returns the container element for this TreePanel
31843 getEl : function(){
31848 * Returns the default TreeLoader for this TreePanel
31850 getLoader : function(){
31851 return this.loader;
31857 expandAll : function(){
31858 this.root.expand(true);
31862 * Collapse all nodes
31864 collapseAll : function(){
31865 this.root.collapse(true);
31869 * Returns the selection model used by this TreePanel
31871 getSelectionModel : function(){
31872 if(!this.selModel){
31873 this.selModel = new Roo.tree.DefaultSelectionModel();
31875 return this.selModel;
31879 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31880 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31881 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31884 getChecked : function(a, startNode){
31885 startNode = startNode || this.root;
31887 var f = function(){
31888 if(this.attributes.checked){
31889 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31892 startNode.cascade(f);
31897 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31898 * @param {String} path
31899 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31900 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31901 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31903 expandPath : function(path, attr, callback){
31904 attr = attr || "id";
31905 var keys = path.split(this.pathSeparator);
31906 var curNode = this.root;
31907 if(curNode.attributes[attr] != keys[1]){ // invalid root
31909 callback(false, null);
31914 var f = function(){
31915 if(++index == keys.length){
31917 callback(true, curNode);
31921 var c = curNode.findChild(attr, keys[index]);
31924 callback(false, curNode);
31929 c.expand(false, false, f);
31931 curNode.expand(false, false, f);
31935 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31936 * @param {String} path
31937 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31938 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31939 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31941 selectPath : function(path, attr, callback){
31942 attr = attr || "id";
31943 var keys = path.split(this.pathSeparator);
31944 var v = keys.pop();
31945 if(keys.length > 0){
31946 var f = function(success, node){
31947 if(success && node){
31948 var n = node.findChild(attr, v);
31954 }else if(callback){
31955 callback(false, n);
31959 callback(false, n);
31963 this.expandPath(keys.join(this.pathSeparator), attr, f);
31965 this.root.select();
31967 callback(true, this.root);
31972 getTreeEl : function(){
31977 * Trigger rendering of this TreePanel
31979 render : function(){
31980 if (this.innerCt) {
31981 return this; // stop it rendering more than once!!
31984 this.innerCt = this.el.createChild({tag:"ul",
31985 cls:"x-tree-root-ct " +
31986 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31988 if(this.containerScroll){
31989 Roo.dd.ScrollManager.register(this.el);
31991 if((this.enableDD || this.enableDrop) && !this.dropZone){
31993 * The dropZone used by this tree if drop is enabled
31994 * @type Roo.tree.TreeDropZone
31996 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31997 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32000 if((this.enableDD || this.enableDrag) && !this.dragZone){
32002 * The dragZone used by this tree if drag is enabled
32003 * @type Roo.tree.TreeDragZone
32005 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32006 ddGroup: this.ddGroup || "TreeDD",
32007 scroll: this.ddScroll
32010 this.getSelectionModel().init(this);
32012 Roo.log("ROOT not set in tree");
32015 this.root.render();
32016 if(!this.rootVisible){
32017 this.root.renderChildren();
32023 * Ext JS Library 1.1.1
32024 * Copyright(c) 2006-2007, Ext JS, LLC.
32026 * Originally Released Under LGPL - original licence link has changed is not relivant.
32029 * <script type="text/javascript">
32034 * @class Roo.tree.DefaultSelectionModel
32035 * @extends Roo.util.Observable
32036 * The default single selection for a TreePanel.
32037 * @param {Object} cfg Configuration
32039 Roo.tree.DefaultSelectionModel = function(cfg){
32040 this.selNode = null;
32046 * @event selectionchange
32047 * Fires when the selected node changes
32048 * @param {DefaultSelectionModel} this
32049 * @param {TreeNode} node the new selection
32051 "selectionchange" : true,
32054 * @event beforeselect
32055 * Fires before the selected node changes, return false to cancel the change
32056 * @param {DefaultSelectionModel} this
32057 * @param {TreeNode} node the new selection
32058 * @param {TreeNode} node the old selection
32060 "beforeselect" : true
32063 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32066 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32067 init : function(tree){
32069 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32070 tree.on("click", this.onNodeClick, this);
32073 onNodeClick : function(node, e){
32074 if (e.ctrlKey && this.selNode == node) {
32075 this.unselect(node);
32083 * @param {TreeNode} node The node to select
32084 * @return {TreeNode} The selected node
32086 select : function(node){
32087 var last = this.selNode;
32088 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32090 last.ui.onSelectedChange(false);
32092 this.selNode = node;
32093 node.ui.onSelectedChange(true);
32094 this.fireEvent("selectionchange", this, node, last);
32101 * @param {TreeNode} node The node to unselect
32103 unselect : function(node){
32104 if(this.selNode == node){
32105 this.clearSelections();
32110 * Clear all selections
32112 clearSelections : function(){
32113 var n = this.selNode;
32115 n.ui.onSelectedChange(false);
32116 this.selNode = null;
32117 this.fireEvent("selectionchange", this, null);
32123 * Get the selected node
32124 * @return {TreeNode} The selected node
32126 getSelectedNode : function(){
32127 return this.selNode;
32131 * Returns true if the node is selected
32132 * @param {TreeNode} node The node to check
32133 * @return {Boolean}
32135 isSelected : function(node){
32136 return this.selNode == node;
32140 * Selects the node above the selected node in the tree, intelligently walking the nodes
32141 * @return TreeNode The new selection
32143 selectPrevious : function(){
32144 var s = this.selNode || this.lastSelNode;
32148 var ps = s.previousSibling;
32150 if(!ps.isExpanded() || ps.childNodes.length < 1){
32151 return this.select(ps);
32153 var lc = ps.lastChild;
32154 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32157 return this.select(lc);
32159 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32160 return this.select(s.parentNode);
32166 * Selects the node above the selected node in the tree, intelligently walking the nodes
32167 * @return TreeNode The new selection
32169 selectNext : function(){
32170 var s = this.selNode || this.lastSelNode;
32174 if(s.firstChild && s.isExpanded()){
32175 return this.select(s.firstChild);
32176 }else if(s.nextSibling){
32177 return this.select(s.nextSibling);
32178 }else if(s.parentNode){
32180 s.parentNode.bubble(function(){
32181 if(this.nextSibling){
32182 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32191 onKeyDown : function(e){
32192 var s = this.selNode || this.lastSelNode;
32193 // undesirable, but required
32198 var k = e.getKey();
32206 this.selectPrevious();
32209 e.preventDefault();
32210 if(s.hasChildNodes()){
32211 if(!s.isExpanded()){
32213 }else if(s.firstChild){
32214 this.select(s.firstChild, e);
32219 e.preventDefault();
32220 if(s.hasChildNodes() && s.isExpanded()){
32222 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32223 this.select(s.parentNode, e);
32231 * @class Roo.tree.MultiSelectionModel
32232 * @extends Roo.util.Observable
32233 * Multi selection for a TreePanel.
32234 * @param {Object} cfg Configuration
32236 Roo.tree.MultiSelectionModel = function(){
32237 this.selNodes = [];
32241 * @event selectionchange
32242 * Fires when the selected nodes change
32243 * @param {MultiSelectionModel} this
32244 * @param {Array} nodes Array of the selected nodes
32246 "selectionchange" : true
32248 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32252 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32253 init : function(tree){
32255 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32256 tree.on("click", this.onNodeClick, this);
32259 onNodeClick : function(node, e){
32260 this.select(node, e, e.ctrlKey);
32265 * @param {TreeNode} node The node to select
32266 * @param {EventObject} e (optional) An event associated with the selection
32267 * @param {Boolean} keepExisting True to retain existing selections
32268 * @return {TreeNode} The selected node
32270 select : function(node, e, keepExisting){
32271 if(keepExisting !== true){
32272 this.clearSelections(true);
32274 if(this.isSelected(node)){
32275 this.lastSelNode = node;
32278 this.selNodes.push(node);
32279 this.selMap[node.id] = node;
32280 this.lastSelNode = node;
32281 node.ui.onSelectedChange(true);
32282 this.fireEvent("selectionchange", this, this.selNodes);
32288 * @param {TreeNode} node The node to unselect
32290 unselect : function(node){
32291 if(this.selMap[node.id]){
32292 node.ui.onSelectedChange(false);
32293 var sn = this.selNodes;
32296 index = sn.indexOf(node);
32298 for(var i = 0, len = sn.length; i < len; i++){
32306 this.selNodes.splice(index, 1);
32308 delete this.selMap[node.id];
32309 this.fireEvent("selectionchange", this, this.selNodes);
32314 * Clear all selections
32316 clearSelections : function(suppressEvent){
32317 var sn = this.selNodes;
32319 for(var i = 0, len = sn.length; i < len; i++){
32320 sn[i].ui.onSelectedChange(false);
32322 this.selNodes = [];
32324 if(suppressEvent !== true){
32325 this.fireEvent("selectionchange", this, this.selNodes);
32331 * Returns true if the node is selected
32332 * @param {TreeNode} node The node to check
32333 * @return {Boolean}
32335 isSelected : function(node){
32336 return this.selMap[node.id] ? true : false;
32340 * Returns an array of the selected nodes
32343 getSelectedNodes : function(){
32344 return this.selNodes;
32347 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32349 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32351 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32354 * Ext JS Library 1.1.1
32355 * Copyright(c) 2006-2007, Ext JS, LLC.
32357 * Originally Released Under LGPL - original licence link has changed is not relivant.
32360 * <script type="text/javascript">
32364 * @class Roo.tree.TreeNode
32365 * @extends Roo.data.Node
32366 * @cfg {String} text The text for this node
32367 * @cfg {Boolean} expanded true to start the node expanded
32368 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32369 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32370 * @cfg {Boolean} disabled true to start the node disabled
32371 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32372 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32373 * @cfg {String} cls A css class to be added to the node
32374 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32375 * @cfg {String} href URL of the link used for the node (defaults to #)
32376 * @cfg {String} hrefTarget target frame for the link
32377 * @cfg {String} qtip An Ext QuickTip for the node
32378 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32379 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32380 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32381 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32382 * (defaults to undefined with no checkbox rendered)
32384 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32386 Roo.tree.TreeNode = function(attributes){
32387 attributes = attributes || {};
32388 if(typeof attributes == "string"){
32389 attributes = {text: attributes};
32391 this.childrenRendered = false;
32392 this.rendered = false;
32393 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32394 this.expanded = attributes.expanded === true;
32395 this.isTarget = attributes.isTarget !== false;
32396 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32397 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32400 * Read-only. The text for this node. To change it use setText().
32403 this.text = attributes.text;
32405 * True if this node is disabled.
32408 this.disabled = attributes.disabled === true;
32412 * @event textchange
32413 * Fires when the text for this node is changed
32414 * @param {Node} this This node
32415 * @param {String} text The new text
32416 * @param {String} oldText The old text
32418 "textchange" : true,
32420 * @event beforeexpand
32421 * Fires before this node is expanded, return false to cancel.
32422 * @param {Node} this This node
32423 * @param {Boolean} deep
32424 * @param {Boolean} anim
32426 "beforeexpand" : true,
32428 * @event beforecollapse
32429 * Fires before this node is collapsed, return false to cancel.
32430 * @param {Node} this This node
32431 * @param {Boolean} deep
32432 * @param {Boolean} anim
32434 "beforecollapse" : true,
32437 * Fires when this node is expanded
32438 * @param {Node} this This node
32442 * @event disabledchange
32443 * Fires when the disabled status of this node changes
32444 * @param {Node} this This node
32445 * @param {Boolean} disabled
32447 "disabledchange" : true,
32450 * Fires when this node is collapsed
32451 * @param {Node} this This node
32455 * @event beforeclick
32456 * Fires before click processing. Return false to cancel the default action.
32457 * @param {Node} this This node
32458 * @param {Roo.EventObject} e The event object
32460 "beforeclick":true,
32462 * @event checkchange
32463 * Fires when a node with a checkbox's checked property changes
32464 * @param {Node} this This node
32465 * @param {Boolean} checked
32467 "checkchange":true,
32470 * Fires when this node is clicked
32471 * @param {Node} this This node
32472 * @param {Roo.EventObject} e The event object
32477 * Fires when this node is double clicked
32478 * @param {Node} this This node
32479 * @param {Roo.EventObject} e The event object
32483 * @event contextmenu
32484 * Fires when this node is right clicked
32485 * @param {Node} this This node
32486 * @param {Roo.EventObject} e The event object
32488 "contextmenu":true,
32490 * @event beforechildrenrendered
32491 * Fires right before the child nodes for this node are rendered
32492 * @param {Node} this This node
32494 "beforechildrenrendered":true
32497 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
32500 * Read-only. The UI for this node
32503 this.ui = new uiClass(this);
32505 // finally support items[]
32506 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
32511 Roo.each(this.attributes.items, function(c) {
32512 this.appendChild(Roo.factory(c,Roo.Tree));
32514 delete this.attributes.items;
32519 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
32520 preventHScroll: true,
32522 * Returns true if this node is expanded
32523 * @return {Boolean}
32525 isExpanded : function(){
32526 return this.expanded;
32530 * Returns the UI object for this node
32531 * @return {TreeNodeUI}
32533 getUI : function(){
32537 // private override
32538 setFirstChild : function(node){
32539 var of = this.firstChild;
32540 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
32541 if(this.childrenRendered && of && node != of){
32542 of.renderIndent(true, true);
32545 this.renderIndent(true, true);
32549 // private override
32550 setLastChild : function(node){
32551 var ol = this.lastChild;
32552 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
32553 if(this.childrenRendered && ol && node != ol){
32554 ol.renderIndent(true, true);
32557 this.renderIndent(true, true);
32561 // these methods are overridden to provide lazy rendering support
32562 // private override
32563 appendChild : function()
32565 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
32566 if(node && this.childrenRendered){
32569 this.ui.updateExpandIcon();
32573 // private override
32574 removeChild : function(node){
32575 this.ownerTree.getSelectionModel().unselect(node);
32576 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
32577 // if it's been rendered remove dom node
32578 if(this.childrenRendered){
32581 if(this.childNodes.length < 1){
32582 this.collapse(false, false);
32584 this.ui.updateExpandIcon();
32586 if(!this.firstChild) {
32587 this.childrenRendered = false;
32592 // private override
32593 insertBefore : function(node, refNode){
32594 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
32595 if(newNode && refNode && this.childrenRendered){
32598 this.ui.updateExpandIcon();
32603 * Sets the text for this node
32604 * @param {String} text
32606 setText : function(text){
32607 var oldText = this.text;
32609 this.attributes.text = text;
32610 if(this.rendered){ // event without subscribing
32611 this.ui.onTextChange(this, text, oldText);
32613 this.fireEvent("textchange", this, text, oldText);
32617 * Triggers selection of this node
32619 select : function(){
32620 this.getOwnerTree().getSelectionModel().select(this);
32624 * Triggers deselection of this node
32626 unselect : function(){
32627 this.getOwnerTree().getSelectionModel().unselect(this);
32631 * Returns true if this node is selected
32632 * @return {Boolean}
32634 isSelected : function(){
32635 return this.getOwnerTree().getSelectionModel().isSelected(this);
32639 * Expand this node.
32640 * @param {Boolean} deep (optional) True to expand all children as well
32641 * @param {Boolean} anim (optional) false to cancel the default animation
32642 * @param {Function} callback (optional) A callback to be called when
32643 * expanding this node completes (does not wait for deep expand to complete).
32644 * Called with 1 parameter, this node.
32646 expand : function(deep, anim, callback){
32647 if(!this.expanded){
32648 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
32651 if(!this.childrenRendered){
32652 this.renderChildren();
32654 this.expanded = true;
32655 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
32656 this.ui.animExpand(function(){
32657 this.fireEvent("expand", this);
32658 if(typeof callback == "function"){
32662 this.expandChildNodes(true);
32664 }.createDelegate(this));
32668 this.fireEvent("expand", this);
32669 if(typeof callback == "function"){
32674 if(typeof callback == "function"){
32679 this.expandChildNodes(true);
32683 isHiddenRoot : function(){
32684 return this.isRoot && !this.getOwnerTree().rootVisible;
32688 * Collapse this node.
32689 * @param {Boolean} deep (optional) True to collapse all children as well
32690 * @param {Boolean} anim (optional) false to cancel the default animation
32692 collapse : function(deep, anim){
32693 if(this.expanded && !this.isHiddenRoot()){
32694 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32697 this.expanded = false;
32698 if((this.getOwnerTree().animate && anim !== false) || anim){
32699 this.ui.animCollapse(function(){
32700 this.fireEvent("collapse", this);
32702 this.collapseChildNodes(true);
32704 }.createDelegate(this));
32707 this.ui.collapse();
32708 this.fireEvent("collapse", this);
32712 var cs = this.childNodes;
32713 for(var i = 0, len = cs.length; i < len; i++) {
32714 cs[i].collapse(true, false);
32720 delayedExpand : function(delay){
32721 if(!this.expandProcId){
32722 this.expandProcId = this.expand.defer(delay, this);
32727 cancelExpand : function(){
32728 if(this.expandProcId){
32729 clearTimeout(this.expandProcId);
32731 this.expandProcId = false;
32735 * Toggles expanded/collapsed state of the node
32737 toggle : function(){
32746 * Ensures all parent nodes are expanded
32748 ensureVisible : function(callback){
32749 var tree = this.getOwnerTree();
32750 tree.expandPath(this.parentNode.getPath(), false, function(){
32751 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32752 Roo.callback(callback);
32753 }.createDelegate(this));
32757 * Expand all child nodes
32758 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32760 expandChildNodes : function(deep){
32761 var cs = this.childNodes;
32762 for(var i = 0, len = cs.length; i < len; i++) {
32763 cs[i].expand(deep);
32768 * Collapse all child nodes
32769 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32771 collapseChildNodes : function(deep){
32772 var cs = this.childNodes;
32773 for(var i = 0, len = cs.length; i < len; i++) {
32774 cs[i].collapse(deep);
32779 * Disables this node
32781 disable : function(){
32782 this.disabled = true;
32784 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32785 this.ui.onDisableChange(this, true);
32787 this.fireEvent("disabledchange", this, true);
32791 * Enables this node
32793 enable : function(){
32794 this.disabled = false;
32795 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32796 this.ui.onDisableChange(this, false);
32798 this.fireEvent("disabledchange", this, false);
32802 renderChildren : function(suppressEvent){
32803 if(suppressEvent !== false){
32804 this.fireEvent("beforechildrenrendered", this);
32806 var cs = this.childNodes;
32807 for(var i = 0, len = cs.length; i < len; i++){
32808 cs[i].render(true);
32810 this.childrenRendered = true;
32814 sort : function(fn, scope){
32815 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32816 if(this.childrenRendered){
32817 var cs = this.childNodes;
32818 for(var i = 0, len = cs.length; i < len; i++){
32819 cs[i].render(true);
32825 render : function(bulkRender){
32826 this.ui.render(bulkRender);
32827 if(!this.rendered){
32828 this.rendered = true;
32830 this.expanded = false;
32831 this.expand(false, false);
32837 renderIndent : function(deep, refresh){
32839 this.ui.childIndent = null;
32841 this.ui.renderIndent();
32842 if(deep === true && this.childrenRendered){
32843 var cs = this.childNodes;
32844 for(var i = 0, len = cs.length; i < len; i++){
32845 cs[i].renderIndent(true, refresh);
32851 * Ext JS Library 1.1.1
32852 * Copyright(c) 2006-2007, Ext JS, LLC.
32854 * Originally Released Under LGPL - original licence link has changed is not relivant.
32857 * <script type="text/javascript">
32861 * @class Roo.tree.AsyncTreeNode
32862 * @extends Roo.tree.TreeNode
32863 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32865 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32867 Roo.tree.AsyncTreeNode = function(config){
32868 this.loaded = false;
32869 this.loading = false;
32870 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32872 * @event beforeload
32873 * Fires before this node is loaded, return false to cancel
32874 * @param {Node} this This node
32876 this.addEvents({'beforeload':true, 'load': true});
32879 * Fires when this node is loaded
32880 * @param {Node} this This node
32883 * The loader used by this node (defaults to using the tree's defined loader)
32888 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32889 expand : function(deep, anim, callback){
32890 if(this.loading){ // if an async load is already running, waiting til it's done
32892 var f = function(){
32893 if(!this.loading){ // done loading
32894 clearInterval(timer);
32895 this.expand(deep, anim, callback);
32897 }.createDelegate(this);
32898 timer = setInterval(f, 200);
32902 if(this.fireEvent("beforeload", this) === false){
32905 this.loading = true;
32906 this.ui.beforeLoad(this);
32907 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32909 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32913 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32917 * Returns true if this node is currently loading
32918 * @return {Boolean}
32920 isLoading : function(){
32921 return this.loading;
32924 loadComplete : function(deep, anim, callback){
32925 this.loading = false;
32926 this.loaded = true;
32927 this.ui.afterLoad(this);
32928 this.fireEvent("load", this);
32929 this.expand(deep, anim, callback);
32933 * Returns true if this node has been loaded
32934 * @return {Boolean}
32936 isLoaded : function(){
32937 return this.loaded;
32940 hasChildNodes : function(){
32941 if(!this.isLeaf() && !this.loaded){
32944 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32949 * Trigger a reload for this node
32950 * @param {Function} callback
32952 reload : function(callback){
32953 this.collapse(false, false);
32954 while(this.firstChild){
32955 this.removeChild(this.firstChild);
32957 this.childrenRendered = false;
32958 this.loaded = false;
32959 if(this.isHiddenRoot()){
32960 this.expanded = false;
32962 this.expand(false, false, callback);
32966 * Ext JS Library 1.1.1
32967 * Copyright(c) 2006-2007, Ext JS, LLC.
32969 * Originally Released Under LGPL - original licence link has changed is not relivant.
32972 * <script type="text/javascript">
32976 * @class Roo.tree.TreeNodeUI
32978 * @param {Object} node The node to render
32979 * The TreeNode UI implementation is separate from the
32980 * tree implementation. Unless you are customizing the tree UI,
32981 * you should never have to use this directly.
32983 Roo.tree.TreeNodeUI = function(node){
32985 this.rendered = false;
32986 this.animating = false;
32987 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32990 Roo.tree.TreeNodeUI.prototype = {
32991 removeChild : function(node){
32993 this.ctNode.removeChild(node.ui.getEl());
32997 beforeLoad : function(){
32998 this.addClass("x-tree-node-loading");
33001 afterLoad : function(){
33002 this.removeClass("x-tree-node-loading");
33005 onTextChange : function(node, text, oldText){
33007 this.textNode.innerHTML = text;
33011 onDisableChange : function(node, state){
33012 this.disabled = state;
33014 this.addClass("x-tree-node-disabled");
33016 this.removeClass("x-tree-node-disabled");
33020 onSelectedChange : function(state){
33023 this.addClass("x-tree-selected");
33026 this.removeClass("x-tree-selected");
33030 onMove : function(tree, node, oldParent, newParent, index, refNode){
33031 this.childIndent = null;
33033 var targetNode = newParent.ui.getContainer();
33034 if(!targetNode){//target not rendered
33035 this.holder = document.createElement("div");
33036 this.holder.appendChild(this.wrap);
33039 var insertBefore = refNode ? refNode.ui.getEl() : null;
33041 targetNode.insertBefore(this.wrap, insertBefore);
33043 targetNode.appendChild(this.wrap);
33045 this.node.renderIndent(true);
33049 addClass : function(cls){
33051 Roo.fly(this.elNode).addClass(cls);
33055 removeClass : function(cls){
33057 Roo.fly(this.elNode).removeClass(cls);
33061 remove : function(){
33063 this.holder = document.createElement("div");
33064 this.holder.appendChild(this.wrap);
33068 fireEvent : function(){
33069 return this.node.fireEvent.apply(this.node, arguments);
33072 initEvents : function(){
33073 this.node.on("move", this.onMove, this);
33074 var E = Roo.EventManager;
33075 var a = this.anchor;
33077 var el = Roo.fly(a, '_treeui');
33079 if(Roo.isOpera){ // opera render bug ignores the CSS
33080 el.setStyle("text-decoration", "none");
33083 el.on("click", this.onClick, this);
33084 el.on("dblclick", this.onDblClick, this);
33087 Roo.EventManager.on(this.checkbox,
33088 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33091 el.on("contextmenu", this.onContextMenu, this);
33093 var icon = Roo.fly(this.iconNode);
33094 icon.on("click", this.onClick, this);
33095 icon.on("dblclick", this.onDblClick, this);
33096 icon.on("contextmenu", this.onContextMenu, this);
33097 E.on(this.ecNode, "click", this.ecClick, this, true);
33099 if(this.node.disabled){
33100 this.addClass("x-tree-node-disabled");
33102 if(this.node.hidden){
33103 this.addClass("x-tree-node-disabled");
33105 var ot = this.node.getOwnerTree();
33106 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33107 if(dd && (!this.node.isRoot || ot.rootVisible)){
33108 Roo.dd.Registry.register(this.elNode, {
33110 handles: this.getDDHandles(),
33116 getDDHandles : function(){
33117 return [this.iconNode, this.textNode];
33122 this.wrap.style.display = "none";
33128 this.wrap.style.display = "";
33132 onContextMenu : function(e){
33133 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33134 e.preventDefault();
33136 this.fireEvent("contextmenu", this.node, e);
33140 onClick : function(e){
33145 if(this.fireEvent("beforeclick", this.node, e) !== false){
33146 if(!this.disabled && this.node.attributes.href){
33147 this.fireEvent("click", this.node, e);
33150 e.preventDefault();
33155 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33156 this.node.toggle();
33159 this.fireEvent("click", this.node, e);
33165 onDblClick : function(e){
33166 e.preventDefault();
33171 this.toggleCheck();
33173 if(!this.animating && this.node.hasChildNodes()){
33174 this.node.toggle();
33176 this.fireEvent("dblclick", this.node, e);
33179 onCheckChange : function(){
33180 var checked = this.checkbox.checked;
33181 this.node.attributes.checked = checked;
33182 this.fireEvent('checkchange', this.node, checked);
33185 ecClick : function(e){
33186 if(!this.animating && this.node.hasChildNodes()){
33187 this.node.toggle();
33191 startDrop : function(){
33192 this.dropping = true;
33195 // delayed drop so the click event doesn't get fired on a drop
33196 endDrop : function(){
33197 setTimeout(function(){
33198 this.dropping = false;
33199 }.createDelegate(this), 50);
33202 expand : function(){
33203 this.updateExpandIcon();
33204 this.ctNode.style.display = "";
33207 focus : function(){
33208 if(!this.node.preventHScroll){
33209 try{this.anchor.focus();
33211 }else if(!Roo.isIE){
33213 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33214 var l = noscroll.scrollLeft;
33215 this.anchor.focus();
33216 noscroll.scrollLeft = l;
33221 toggleCheck : function(value){
33222 var cb = this.checkbox;
33224 cb.checked = (value === undefined ? !cb.checked : value);
33230 this.anchor.blur();
33234 animExpand : function(callback){
33235 var ct = Roo.get(this.ctNode);
33237 if(!this.node.hasChildNodes()){
33238 this.updateExpandIcon();
33239 this.ctNode.style.display = "";
33240 Roo.callback(callback);
33243 this.animating = true;
33244 this.updateExpandIcon();
33247 callback : function(){
33248 this.animating = false;
33249 Roo.callback(callback);
33252 duration: this.node.ownerTree.duration || .25
33256 highlight : function(){
33257 var tree = this.node.getOwnerTree();
33258 Roo.fly(this.wrap).highlight(
33259 tree.hlColor || "C3DAF9",
33260 {endColor: tree.hlBaseColor}
33264 collapse : function(){
33265 this.updateExpandIcon();
33266 this.ctNode.style.display = "none";
33269 animCollapse : function(callback){
33270 var ct = Roo.get(this.ctNode);
33271 ct.enableDisplayMode('block');
33274 this.animating = true;
33275 this.updateExpandIcon();
33278 callback : function(){
33279 this.animating = false;
33280 Roo.callback(callback);
33283 duration: this.node.ownerTree.duration || .25
33287 getContainer : function(){
33288 return this.ctNode;
33291 getEl : function(){
33295 appendDDGhost : function(ghostNode){
33296 ghostNode.appendChild(this.elNode.cloneNode(true));
33299 getDDRepairXY : function(){
33300 return Roo.lib.Dom.getXY(this.iconNode);
33303 onRender : function(){
33307 render : function(bulkRender){
33308 var n = this.node, a = n.attributes;
33309 var targetNode = n.parentNode ?
33310 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33312 if(!this.rendered){
33313 this.rendered = true;
33315 this.renderElements(n, a, targetNode, bulkRender);
33318 if(this.textNode.setAttributeNS){
33319 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33321 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33324 this.textNode.setAttribute("ext:qtip", a.qtip);
33326 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33329 }else if(a.qtipCfg){
33330 a.qtipCfg.target = Roo.id(this.textNode);
33331 Roo.QuickTips.register(a.qtipCfg);
33334 if(!this.node.expanded){
33335 this.updateExpandIcon();
33338 if(bulkRender === true) {
33339 targetNode.appendChild(this.wrap);
33344 renderElements : function(n, a, targetNode, bulkRender)
33346 // add some indent caching, this helps performance when rendering a large tree
33347 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33348 var t = n.getOwnerTree();
33349 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33350 if (typeof(n.attributes.html) != 'undefined') {
33351 txt = n.attributes.html;
33353 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33354 var cb = typeof a.checked == 'boolean';
33355 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33356 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33357 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33358 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33359 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33360 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33361 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33362 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33363 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33364 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33367 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33368 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33369 n.nextSibling.ui.getEl(), buf.join(""));
33371 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33374 this.elNode = this.wrap.childNodes[0];
33375 this.ctNode = this.wrap.childNodes[1];
33376 var cs = this.elNode.childNodes;
33377 this.indentNode = cs[0];
33378 this.ecNode = cs[1];
33379 this.iconNode = cs[2];
33382 this.checkbox = cs[3];
33385 this.anchor = cs[index];
33386 this.textNode = cs[index].firstChild;
33389 getAnchor : function(){
33390 return this.anchor;
33393 getTextEl : function(){
33394 return this.textNode;
33397 getIconEl : function(){
33398 return this.iconNode;
33401 isChecked : function(){
33402 return this.checkbox ? this.checkbox.checked : false;
33405 updateExpandIcon : function(){
33407 var n = this.node, c1, c2;
33408 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33409 var hasChild = n.hasChildNodes();
33413 c1 = "x-tree-node-collapsed";
33414 c2 = "x-tree-node-expanded";
33417 c1 = "x-tree-node-expanded";
33418 c2 = "x-tree-node-collapsed";
33421 this.removeClass("x-tree-node-leaf");
33422 this.wasLeaf = false;
33424 if(this.c1 != c1 || this.c2 != c2){
33425 Roo.fly(this.elNode).replaceClass(c1, c2);
33426 this.c1 = c1; this.c2 = c2;
33429 // this changes non-leafs into leafs if they have no children.
33430 // it's not very rational behaviour..
33432 if(!this.wasLeaf && this.node.leaf){
33433 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
33436 this.wasLeaf = true;
33439 var ecc = "x-tree-ec-icon "+cls;
33440 if(this.ecc != ecc){
33441 this.ecNode.className = ecc;
33447 getChildIndent : function(){
33448 if(!this.childIndent){
33452 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
33454 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
33456 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
33461 this.childIndent = buf.join("");
33463 return this.childIndent;
33466 renderIndent : function(){
33469 var p = this.node.parentNode;
33471 indent = p.ui.getChildIndent();
33473 if(this.indentMarkup != indent){ // don't rerender if not required
33474 this.indentNode.innerHTML = indent;
33475 this.indentMarkup = indent;
33477 this.updateExpandIcon();
33482 Roo.tree.RootTreeNodeUI = function(){
33483 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
33485 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
33486 render : function(){
33487 if(!this.rendered){
33488 var targetNode = this.node.ownerTree.innerCt.dom;
33489 this.node.expanded = true;
33490 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
33491 this.wrap = this.ctNode = targetNode.firstChild;
33494 collapse : function(){
33496 expand : function(){
33500 * Ext JS Library 1.1.1
33501 * Copyright(c) 2006-2007, Ext JS, LLC.
33503 * Originally Released Under LGPL - original licence link has changed is not relivant.
33506 * <script type="text/javascript">
33509 * @class Roo.tree.TreeLoader
33510 * @extends Roo.util.Observable
33511 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
33512 * nodes from a specified URL. The response must be a javascript Array definition
33513 * who's elements are node definition objects. eg:
33518 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
33519 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
33526 * The old style respose with just an array is still supported, but not recommended.
33529 * A server request is sent, and child nodes are loaded only when a node is expanded.
33530 * The loading node's id is passed to the server under the parameter name "node" to
33531 * enable the server to produce the correct child nodes.
33533 * To pass extra parameters, an event handler may be attached to the "beforeload"
33534 * event, and the parameters specified in the TreeLoader's baseParams property:
33536 myTreeLoader.on("beforeload", function(treeLoader, node) {
33537 this.baseParams.category = node.attributes.category;
33540 * This would pass an HTTP parameter called "category" to the server containing
33541 * the value of the Node's "category" attribute.
33543 * Creates a new Treeloader.
33544 * @param {Object} config A config object containing config properties.
33546 Roo.tree.TreeLoader = function(config){
33547 this.baseParams = {};
33548 this.requestMethod = "POST";
33549 Roo.apply(this, config);
33554 * @event beforeload
33555 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
33556 * @param {Object} This TreeLoader object.
33557 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33558 * @param {Object} callback The callback function specified in the {@link #load} call.
33563 * Fires when the node has been successfuly loaded.
33564 * @param {Object} This TreeLoader object.
33565 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33566 * @param {Object} response The response object containing the data from the server.
33570 * @event loadexception
33571 * Fires if the network request failed.
33572 * @param {Object} This TreeLoader object.
33573 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33574 * @param {Object} response The response object containing the data from the server.
33576 loadexception : true,
33579 * Fires before a node is created, enabling you to return custom Node types
33580 * @param {Object} This TreeLoader object.
33581 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
33586 Roo.tree.TreeLoader.superclass.constructor.call(this);
33589 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
33591 * @cfg {String} dataUrl The URL from which to request a Json string which
33592 * specifies an array of node definition object representing the child nodes
33596 * @cfg {String} requestMethod either GET or POST
33597 * defaults to POST (due to BC)
33601 * @cfg {Object} baseParams (optional) An object containing properties which
33602 * specify HTTP parameters to be passed to each request for child nodes.
33605 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
33606 * created by this loader. If the attributes sent by the server have an attribute in this object,
33607 * they take priority.
33610 * @cfg {Object} uiProviders (optional) An object containing properties which
33612 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
33613 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
33614 * <i>uiProvider</i> attribute of a returned child node is a string rather
33615 * than a reference to a TreeNodeUI implementation, this that string value
33616 * is used as a property name in the uiProviders object. You can define the provider named
33617 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
33622 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
33623 * child nodes before loading.
33625 clearOnLoad : true,
33628 * @cfg {String} root (optional) Default to false. Use this to read data from an object
33629 * property on loading, rather than expecting an array. (eg. more compatible to a standard
33630 * Grid query { data : [ .....] }
33635 * @cfg {String} queryParam (optional)
33636 * Name of the query as it will be passed on the querystring (defaults to 'node')
33637 * eg. the request will be ?node=[id]
33644 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
33645 * This is called automatically when a node is expanded, but may be used to reload
33646 * a node (or append new children if the {@link #clearOnLoad} option is false.)
33647 * @param {Roo.tree.TreeNode} node
33648 * @param {Function} callback
33650 load : function(node, callback){
33651 if(this.clearOnLoad){
33652 while(node.firstChild){
33653 node.removeChild(node.firstChild);
33656 if(node.attributes.children){ // preloaded json children
33657 var cs = node.attributes.children;
33658 for(var i = 0, len = cs.length; i < len; i++){
33659 node.appendChild(this.createNode(cs[i]));
33661 if(typeof callback == "function"){
33664 }else if(this.dataUrl){
33665 this.requestData(node, callback);
33669 getParams: function(node){
33670 var buf = [], bp = this.baseParams;
33671 for(var key in bp){
33672 if(typeof bp[key] != "function"){
33673 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
33676 var n = this.queryParam === false ? 'node' : this.queryParam;
33677 buf.push(n + "=", encodeURIComponent(node.id));
33678 return buf.join("");
33681 requestData : function(node, callback){
33682 if(this.fireEvent("beforeload", this, node, callback) !== false){
33683 this.transId = Roo.Ajax.request({
33684 method:this.requestMethod,
33685 url: this.dataUrl||this.url,
33686 success: this.handleResponse,
33687 failure: this.handleFailure,
33689 argument: {callback: callback, node: node},
33690 params: this.getParams(node)
33693 // if the load is cancelled, make sure we notify
33694 // the node that we are done
33695 if(typeof callback == "function"){
33701 isLoading : function(){
33702 return this.transId ? true : false;
33705 abort : function(){
33706 if(this.isLoading()){
33707 Roo.Ajax.abort(this.transId);
33712 createNode : function(attr)
33714 // apply baseAttrs, nice idea Corey!
33715 if(this.baseAttrs){
33716 Roo.applyIf(attr, this.baseAttrs);
33718 if(this.applyLoader !== false){
33719 attr.loader = this;
33721 // uiProvider = depreciated..
33723 if(typeof(attr.uiProvider) == 'string'){
33724 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33725 /** eval:var:attr */ eval(attr.uiProvider);
33727 if(typeof(this.uiProviders['default']) != 'undefined') {
33728 attr.uiProvider = this.uiProviders['default'];
33731 this.fireEvent('create', this, attr);
33733 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33735 new Roo.tree.TreeNode(attr) :
33736 new Roo.tree.AsyncTreeNode(attr));
33739 processResponse : function(response, node, callback)
33741 var json = response.responseText;
33744 var o = Roo.decode(json);
33746 if (this.root === false && typeof(o.success) != undefined) {
33747 this.root = 'data'; // the default behaviour for list like data..
33750 if (this.root !== false && !o.success) {
33751 // it's a failure condition.
33752 var a = response.argument;
33753 this.fireEvent("loadexception", this, a.node, response);
33754 Roo.log("Load failed - should have a handler really");
33760 if (this.root !== false) {
33764 for(var i = 0, len = o.length; i < len; i++){
33765 var n = this.createNode(o[i]);
33767 node.appendChild(n);
33770 if(typeof callback == "function"){
33771 callback(this, node);
33774 this.handleFailure(response);
33778 handleResponse : function(response){
33779 this.transId = false;
33780 var a = response.argument;
33781 this.processResponse(response, a.node, a.callback);
33782 this.fireEvent("load", this, a.node, response);
33785 handleFailure : function(response)
33787 // should handle failure better..
33788 this.transId = false;
33789 var a = response.argument;
33790 this.fireEvent("loadexception", this, a.node, response);
33791 if(typeof a.callback == "function"){
33792 a.callback(this, a.node);
33797 * Ext JS Library 1.1.1
33798 * Copyright(c) 2006-2007, Ext JS, LLC.
33800 * Originally Released Under LGPL - original licence link has changed is not relivant.
33803 * <script type="text/javascript">
33807 * @class Roo.tree.TreeFilter
33808 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33809 * @param {TreePanel} tree
33810 * @param {Object} config (optional)
33812 Roo.tree.TreeFilter = function(tree, config){
33814 this.filtered = {};
33815 Roo.apply(this, config);
33818 Roo.tree.TreeFilter.prototype = {
33825 * Filter the data by a specific attribute.
33826 * @param {String/RegExp} value Either string that the attribute value
33827 * should start with or a RegExp to test against the attribute
33828 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33829 * @param {TreeNode} startNode (optional) The node to start the filter at.
33831 filter : function(value, attr, startNode){
33832 attr = attr || "text";
33834 if(typeof value == "string"){
33835 var vlen = value.length;
33836 // auto clear empty filter
33837 if(vlen == 0 && this.clearBlank){
33841 value = value.toLowerCase();
33843 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33845 }else if(value.exec){ // regex?
33847 return value.test(n.attributes[attr]);
33850 throw 'Illegal filter type, must be string or regex';
33852 this.filterBy(f, null, startNode);
33856 * Filter by a function. The passed function will be called with each
33857 * node in the tree (or from the startNode). If the function returns true, the node is kept
33858 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33859 * @param {Function} fn The filter function
33860 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33862 filterBy : function(fn, scope, startNode){
33863 startNode = startNode || this.tree.root;
33864 if(this.autoClear){
33867 var af = this.filtered, rv = this.reverse;
33868 var f = function(n){
33869 if(n == startNode){
33875 var m = fn.call(scope || n, n);
33883 startNode.cascade(f);
33886 if(typeof id != "function"){
33888 if(n && n.parentNode){
33889 n.parentNode.removeChild(n);
33897 * Clears the current filter. Note: with the "remove" option
33898 * set a filter cannot be cleared.
33900 clear : function(){
33902 var af = this.filtered;
33904 if(typeof id != "function"){
33911 this.filtered = {};
33916 * Ext JS Library 1.1.1
33917 * Copyright(c) 2006-2007, Ext JS, LLC.
33919 * Originally Released Under LGPL - original licence link has changed is not relivant.
33922 * <script type="text/javascript">
33927 * @class Roo.tree.TreeSorter
33928 * Provides sorting of nodes in a TreePanel
33930 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33931 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33932 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33933 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33934 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33935 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33937 * @param {TreePanel} tree
33938 * @param {Object} config
33940 Roo.tree.TreeSorter = function(tree, config){
33941 Roo.apply(this, config);
33942 tree.on("beforechildrenrendered", this.doSort, this);
33943 tree.on("append", this.updateSort, this);
33944 tree.on("insert", this.updateSort, this);
33946 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33947 var p = this.property || "text";
33948 var sortType = this.sortType;
33949 var fs = this.folderSort;
33950 var cs = this.caseSensitive === true;
33951 var leafAttr = this.leafAttr || 'leaf';
33953 this.sortFn = function(n1, n2){
33955 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33958 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33962 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33963 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33965 return dsc ? +1 : -1;
33967 return dsc ? -1 : +1;
33974 Roo.tree.TreeSorter.prototype = {
33975 doSort : function(node){
33976 node.sort(this.sortFn);
33979 compareNodes : function(n1, n2){
33980 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33983 updateSort : function(tree, node){
33984 if(node.childrenRendered){
33985 this.doSort.defer(1, this, [node]);
33990 * Ext JS Library 1.1.1
33991 * Copyright(c) 2006-2007, Ext JS, LLC.
33993 * Originally Released Under LGPL - original licence link has changed is not relivant.
33996 * <script type="text/javascript">
33999 if(Roo.dd.DropZone){
34001 Roo.tree.TreeDropZone = function(tree, config){
34002 this.allowParentInsert = false;
34003 this.allowContainerDrop = false;
34004 this.appendOnly = false;
34005 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34007 this.lastInsertClass = "x-tree-no-status";
34008 this.dragOverData = {};
34011 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34012 ddGroup : "TreeDD",
34015 expandDelay : 1000,
34017 expandNode : function(node){
34018 if(node.hasChildNodes() && !node.isExpanded()){
34019 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34023 queueExpand : function(node){
34024 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34027 cancelExpand : function(){
34028 if(this.expandProcId){
34029 clearTimeout(this.expandProcId);
34030 this.expandProcId = false;
34034 isValidDropPoint : function(n, pt, dd, e, data){
34035 if(!n || !data){ return false; }
34036 var targetNode = n.node;
34037 var dropNode = data.node;
34038 // default drop rules
34039 if(!(targetNode && targetNode.isTarget && pt)){
34042 if(pt == "append" && targetNode.allowChildren === false){
34045 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34048 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34051 // reuse the object
34052 var overEvent = this.dragOverData;
34053 overEvent.tree = this.tree;
34054 overEvent.target = targetNode;
34055 overEvent.data = data;
34056 overEvent.point = pt;
34057 overEvent.source = dd;
34058 overEvent.rawEvent = e;
34059 overEvent.dropNode = dropNode;
34060 overEvent.cancel = false;
34061 var result = this.tree.fireEvent("nodedragover", overEvent);
34062 return overEvent.cancel === false && result !== false;
34065 getDropPoint : function(e, n, dd)
34069 return tn.allowChildren !== false ? "append" : false; // always append for root
34071 var dragEl = n.ddel;
34072 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34073 var y = Roo.lib.Event.getPageY(e);
34074 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34076 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34077 var noAppend = tn.allowChildren === false;
34078 if(this.appendOnly || tn.parentNode.allowChildren === false){
34079 return noAppend ? false : "append";
34081 var noBelow = false;
34082 if(!this.allowParentInsert){
34083 noBelow = tn.hasChildNodes() && tn.isExpanded();
34085 var q = (b - t) / (noAppend ? 2 : 3);
34086 if(y >= t && y < (t + q)){
34088 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34095 onNodeEnter : function(n, dd, e, data)
34097 this.cancelExpand();
34100 onNodeOver : function(n, dd, e, data)
34103 var pt = this.getDropPoint(e, n, dd);
34106 // auto node expand check
34107 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34108 this.queueExpand(node);
34109 }else if(pt != "append"){
34110 this.cancelExpand();
34113 // set the insert point style on the target node
34114 var returnCls = this.dropNotAllowed;
34115 if(this.isValidDropPoint(n, pt, dd, e, data)){
34120 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34121 cls = "x-tree-drag-insert-above";
34122 }else if(pt == "below"){
34123 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34124 cls = "x-tree-drag-insert-below";
34126 returnCls = "x-tree-drop-ok-append";
34127 cls = "x-tree-drag-append";
34129 if(this.lastInsertClass != cls){
34130 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34131 this.lastInsertClass = cls;
34138 onNodeOut : function(n, dd, e, data){
34140 this.cancelExpand();
34141 this.removeDropIndicators(n);
34144 onNodeDrop : function(n, dd, e, data){
34145 var point = this.getDropPoint(e, n, dd);
34146 var targetNode = n.node;
34147 targetNode.ui.startDrop();
34148 if(!this.isValidDropPoint(n, point, dd, e, data)){
34149 targetNode.ui.endDrop();
34152 // first try to find the drop node
34153 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34156 target: targetNode,
34161 dropNode: dropNode,
34164 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34165 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34166 targetNode.ui.endDrop();
34169 // allow target changing
34170 targetNode = dropEvent.target;
34171 if(point == "append" && !targetNode.isExpanded()){
34172 targetNode.expand(false, null, function(){
34173 this.completeDrop(dropEvent);
34174 }.createDelegate(this));
34176 this.completeDrop(dropEvent);
34181 completeDrop : function(de){
34182 var ns = de.dropNode, p = de.point, t = de.target;
34183 if(!(ns instanceof Array)){
34187 for(var i = 0, len = ns.length; i < len; i++){
34190 t.parentNode.insertBefore(n, t);
34191 }else if(p == "below"){
34192 t.parentNode.insertBefore(n, t.nextSibling);
34198 if(this.tree.hlDrop){
34202 this.tree.fireEvent("nodedrop", de);
34205 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34206 if(this.tree.hlDrop){
34207 dropNode.ui.focus();
34208 dropNode.ui.highlight();
34210 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34213 getTree : function(){
34217 removeDropIndicators : function(n){
34220 Roo.fly(el).removeClass([
34221 "x-tree-drag-insert-above",
34222 "x-tree-drag-insert-below",
34223 "x-tree-drag-append"]);
34224 this.lastInsertClass = "_noclass";
34228 beforeDragDrop : function(target, e, id){
34229 this.cancelExpand();
34233 afterRepair : function(data){
34234 if(data && Roo.enableFx){
34235 data.node.ui.highlight();
34245 * Ext JS Library 1.1.1
34246 * Copyright(c) 2006-2007, Ext JS, LLC.
34248 * Originally Released Under LGPL - original licence link has changed is not relivant.
34251 * <script type="text/javascript">
34255 if(Roo.dd.DragZone){
34256 Roo.tree.TreeDragZone = function(tree, config){
34257 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34261 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34262 ddGroup : "TreeDD",
34264 onBeforeDrag : function(data, e){
34266 return n && n.draggable && !n.disabled;
34270 onInitDrag : function(e){
34271 var data = this.dragData;
34272 this.tree.getSelectionModel().select(data.node);
34273 this.proxy.update("");
34274 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34275 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34278 getRepairXY : function(e, data){
34279 return data.node.ui.getDDRepairXY();
34282 onEndDrag : function(data, e){
34283 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34288 onValidDrop : function(dd, e, id){
34289 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34293 beforeInvalidDrop : function(e, id){
34294 // this scrolls the original position back into view
34295 var sm = this.tree.getSelectionModel();
34296 sm.clearSelections();
34297 sm.select(this.dragData.node);
34302 * Ext JS Library 1.1.1
34303 * Copyright(c) 2006-2007, Ext JS, LLC.
34305 * Originally Released Under LGPL - original licence link has changed is not relivant.
34308 * <script type="text/javascript">
34311 * @class Roo.tree.TreeEditor
34312 * @extends Roo.Editor
34313 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34314 * as the editor field.
34316 * @param {Object} config (used to be the tree panel.)
34317 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34319 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34320 * @cfg {Roo.form.TextField|Object} field The field configuration
34324 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34327 if (oldconfig) { // old style..
34328 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34331 tree = config.tree;
34332 config.field = config.field || {};
34333 config.field.xtype = 'TextField';
34334 field = Roo.factory(config.field, Roo.form);
34336 config = config || {};
34341 * @event beforenodeedit
34342 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34343 * false from the handler of this event.
34344 * @param {Editor} this
34345 * @param {Roo.tree.Node} node
34347 "beforenodeedit" : true
34351 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34355 tree.on('beforeclick', this.beforeNodeClick, this);
34356 tree.getTreeEl().on('mousedown', this.hide, this);
34357 this.on('complete', this.updateNode, this);
34358 this.on('beforestartedit', this.fitToTree, this);
34359 this.on('startedit', this.bindScroll, this, {delay:10});
34360 this.on('specialkey', this.onSpecialKey, this);
34363 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34365 * @cfg {String} alignment
34366 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34372 * @cfg {Boolean} hideEl
34373 * True to hide the bound element while the editor is displayed (defaults to false)
34377 * @cfg {String} cls
34378 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34380 cls: "x-small-editor x-tree-editor",
34382 * @cfg {Boolean} shim
34383 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34389 * @cfg {Number} maxWidth
34390 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34391 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34392 * scroll and client offsets into account prior to each edit.
34399 fitToTree : function(ed, el){
34400 var td = this.tree.getTreeEl().dom, nd = el.dom;
34401 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34402 td.scrollLeft = nd.offsetLeft;
34406 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34407 this.setSize(w, '');
34409 return this.fireEvent('beforenodeedit', this, this.editNode);
34414 triggerEdit : function(node){
34415 this.completeEdit();
34416 this.editNode = node;
34417 this.startEdit(node.ui.textNode, node.text);
34421 bindScroll : function(){
34422 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
34426 beforeNodeClick : function(node, e){
34427 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
34428 this.lastClick = new Date();
34429 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
34431 this.triggerEdit(node);
34438 updateNode : function(ed, value){
34439 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
34440 this.editNode.setText(value);
34444 onHide : function(){
34445 Roo.tree.TreeEditor.superclass.onHide.call(this);
34447 this.editNode.ui.focus();
34452 onSpecialKey : function(field, e){
34453 var k = e.getKey();
34457 }else if(k == e.ENTER && !e.hasModifier()){
34459 this.completeEdit();
34462 });//<Script type="text/javascript">
34465 * Ext JS Library 1.1.1
34466 * Copyright(c) 2006-2007, Ext JS, LLC.
34468 * Originally Released Under LGPL - original licence link has changed is not relivant.
34471 * <script type="text/javascript">
34475 * Not documented??? - probably should be...
34478 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
34479 //focus: Roo.emptyFn, // prevent odd scrolling behavior
34481 renderElements : function(n, a, targetNode, bulkRender){
34482 //consel.log("renderElements?");
34483 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34485 var t = n.getOwnerTree();
34486 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
34488 var cols = t.columns;
34489 var bw = t.borderWidth;
34491 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34492 var cb = typeof a.checked == "boolean";
34493 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34494 var colcls = 'x-t-' + tid + '-c0';
34496 '<li class="x-tree-node">',
34499 '<div class="x-tree-node-el ', a.cls,'">',
34501 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
34504 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
34505 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
34506 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
34507 (a.icon ? ' x-tree-node-inline-icon' : ''),
34508 (a.iconCls ? ' '+a.iconCls : ''),
34509 '" unselectable="on" />',
34510 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
34511 (a.checked ? 'checked="checked" />' : ' />')) : ''),
34513 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34514 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
34515 '<span unselectable="on" qtip="' + tx + '">',
34519 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34520 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
34522 for(var i = 1, len = cols.length; i < len; i++){
34524 colcls = 'x-t-' + tid + '-c' +i;
34525 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34526 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
34527 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
34533 '<div class="x-clear"></div></div>',
34534 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34537 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34538 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34539 n.nextSibling.ui.getEl(), buf.join(""));
34541 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34543 var el = this.wrap.firstChild;
34545 this.elNode = el.firstChild;
34546 this.ranchor = el.childNodes[1];
34547 this.ctNode = this.wrap.childNodes[1];
34548 var cs = el.firstChild.childNodes;
34549 this.indentNode = cs[0];
34550 this.ecNode = cs[1];
34551 this.iconNode = cs[2];
34554 this.checkbox = cs[3];
34557 this.anchor = cs[index];
34559 this.textNode = cs[index].firstChild;
34561 //el.on("click", this.onClick, this);
34562 //el.on("dblclick", this.onDblClick, this);
34565 // console.log(this);
34567 initEvents : function(){
34568 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
34571 var a = this.ranchor;
34573 var el = Roo.get(a);
34575 if(Roo.isOpera){ // opera render bug ignores the CSS
34576 el.setStyle("text-decoration", "none");
34579 el.on("click", this.onClick, this);
34580 el.on("dblclick", this.onDblClick, this);
34581 el.on("contextmenu", this.onContextMenu, this);
34585 /*onSelectedChange : function(state){
34588 this.addClass("x-tree-selected");
34591 this.removeClass("x-tree-selected");
34594 addClass : function(cls){
34596 Roo.fly(this.elRow).addClass(cls);
34602 removeClass : function(cls){
34604 Roo.fly(this.elRow).removeClass(cls);
34610 });//<Script type="text/javascript">
34614 * Ext JS Library 1.1.1
34615 * Copyright(c) 2006-2007, Ext JS, LLC.
34617 * Originally Released Under LGPL - original licence link has changed is not relivant.
34620 * <script type="text/javascript">
34625 * @class Roo.tree.ColumnTree
34626 * @extends Roo.data.TreePanel
34627 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
34628 * @cfg {int} borderWidth compined right/left border allowance
34630 * @param {String/HTMLElement/Element} el The container element
34631 * @param {Object} config
34633 Roo.tree.ColumnTree = function(el, config)
34635 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
34639 * Fire this event on a container when it resizes
34640 * @param {int} w Width
34641 * @param {int} h Height
34645 this.on('resize', this.onResize, this);
34648 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
34652 borderWidth: Roo.isBorderBox ? 0 : 2,
34655 render : function(){
34656 // add the header.....
34658 Roo.tree.ColumnTree.superclass.render.apply(this);
34660 this.el.addClass('x-column-tree');
34662 this.headers = this.el.createChild(
34663 {cls:'x-tree-headers'},this.innerCt.dom);
34665 var cols = this.columns, c;
34666 var totalWidth = 0;
34668 var len = cols.length;
34669 for(var i = 0; i < len; i++){
34671 totalWidth += c.width;
34672 this.headEls.push(this.headers.createChild({
34673 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
34675 cls:'x-tree-hd-text',
34678 style:'width:'+(c.width-this.borderWidth)+'px;'
34681 this.headers.createChild({cls:'x-clear'});
34682 // prevent floats from wrapping when clipped
34683 this.headers.setWidth(totalWidth);
34684 //this.innerCt.setWidth(totalWidth);
34685 this.innerCt.setStyle({ overflow: 'auto' });
34686 this.onResize(this.width, this.height);
34690 onResize : function(w,h)
34695 this.innerCt.setWidth(this.width);
34696 this.innerCt.setHeight(this.height-20);
34699 var cols = this.columns, c;
34700 var totalWidth = 0;
34702 var len = cols.length;
34703 for(var i = 0; i < len; i++){
34705 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34706 // it's the expander..
34707 expEl = this.headEls[i];
34710 totalWidth += c.width;
34714 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34716 this.headers.setWidth(w-20);
34725 * Ext JS Library 1.1.1
34726 * Copyright(c) 2006-2007, Ext JS, LLC.
34728 * Originally Released Under LGPL - original licence link has changed is not relivant.
34731 * <script type="text/javascript">
34735 * @class Roo.menu.Menu
34736 * @extends Roo.util.Observable
34737 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34738 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34740 * Creates a new Menu
34741 * @param {Object} config Configuration options
34743 Roo.menu.Menu = function(config){
34744 Roo.apply(this, config);
34745 this.id = this.id || Roo.id();
34748 * @event beforeshow
34749 * Fires before this menu is displayed
34750 * @param {Roo.menu.Menu} this
34754 * @event beforehide
34755 * Fires before this menu is hidden
34756 * @param {Roo.menu.Menu} this
34761 * Fires after this menu is displayed
34762 * @param {Roo.menu.Menu} this
34767 * Fires after this menu is hidden
34768 * @param {Roo.menu.Menu} this
34773 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34774 * @param {Roo.menu.Menu} this
34775 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34776 * @param {Roo.EventObject} e
34781 * Fires when the mouse is hovering over this menu
34782 * @param {Roo.menu.Menu} this
34783 * @param {Roo.EventObject} e
34784 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34789 * Fires when the mouse exits this menu
34790 * @param {Roo.menu.Menu} this
34791 * @param {Roo.EventObject} e
34792 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34797 * Fires when a menu item contained in this menu is clicked
34798 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34799 * @param {Roo.EventObject} e
34803 if (this.registerMenu) {
34804 Roo.menu.MenuMgr.register(this);
34807 var mis = this.items;
34808 this.items = new Roo.util.MixedCollection();
34810 this.add.apply(this, mis);
34814 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34816 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34820 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34821 * for bottom-right shadow (defaults to "sides")
34825 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34826 * this menu (defaults to "tl-tr?")
34828 subMenuAlign : "tl-tr?",
34830 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34831 * relative to its element of origin (defaults to "tl-bl?")
34833 defaultAlign : "tl-bl?",
34835 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34837 allowOtherMenus : false,
34839 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34841 registerMenu : true,
34846 render : function(){
34850 var el = this.el = new Roo.Layer({
34852 shadow:this.shadow,
34854 parentEl: this.parentEl || document.body,
34858 this.keyNav = new Roo.menu.MenuNav(this);
34861 el.addClass("x-menu-plain");
34864 el.addClass(this.cls);
34866 // generic focus element
34867 this.focusEl = el.createChild({
34868 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34870 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34871 ul.on("click", this.onClick, this);
34872 ul.on("mouseover", this.onMouseOver, this);
34873 ul.on("mouseout", this.onMouseOut, this);
34874 this.items.each(function(item){
34879 var li = document.createElement("li");
34880 li.className = "x-menu-list-item";
34881 ul.dom.appendChild(li);
34882 item.render(li, this);
34889 autoWidth : function(){
34890 var el = this.el, ul = this.ul;
34894 var w = this.width;
34897 }else if(Roo.isIE){
34898 el.setWidth(this.minWidth);
34899 var t = el.dom.offsetWidth; // force recalc
34900 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34905 delayAutoWidth : function(){
34908 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34910 this.awTask.delay(20);
34915 findTargetItem : function(e){
34916 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34917 if(t && t.menuItemId){
34918 return this.items.get(t.menuItemId);
34923 onClick : function(e){
34925 if(t = this.findTargetItem(e)){
34927 this.fireEvent("click", this, t, e);
34932 setActiveItem : function(item, autoExpand){
34933 if(item != this.activeItem){
34934 if(this.activeItem){
34935 this.activeItem.deactivate();
34937 this.activeItem = item;
34938 item.activate(autoExpand);
34939 }else if(autoExpand){
34945 tryActivate : function(start, step){
34946 var items = this.items;
34947 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34948 var item = items.get(i);
34949 if(!item.disabled && item.canActivate){
34950 this.setActiveItem(item, false);
34958 onMouseOver : function(e){
34960 if(t = this.findTargetItem(e)){
34961 if(t.canActivate && !t.disabled){
34962 this.setActiveItem(t, true);
34965 this.fireEvent("mouseover", this, e, t);
34969 onMouseOut : function(e){
34971 if(t = this.findTargetItem(e)){
34972 if(t == this.activeItem && t.shouldDeactivate(e)){
34973 this.activeItem.deactivate();
34974 delete this.activeItem;
34977 this.fireEvent("mouseout", this, e, t);
34981 * Read-only. Returns true if the menu is currently displayed, else false.
34984 isVisible : function(){
34985 return this.el && !this.hidden;
34989 * Displays this menu relative to another element
34990 * @param {String/HTMLElement/Roo.Element} element The element to align to
34991 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34992 * the element (defaults to this.defaultAlign)
34993 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34995 show : function(el, pos, parentMenu){
34996 this.parentMenu = parentMenu;
35000 this.fireEvent("beforeshow", this);
35001 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35005 * Displays this menu at a specific xy position
35006 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35007 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35009 showAt : function(xy, parentMenu, /* private: */_e){
35010 this.parentMenu = parentMenu;
35015 this.fireEvent("beforeshow", this);
35016 xy = this.el.adjustForConstraints(xy);
35020 this.hidden = false;
35022 this.fireEvent("show", this);
35025 focus : function(){
35027 this.doFocus.defer(50, this);
35031 doFocus : function(){
35033 this.focusEl.focus();
35038 * Hides this menu and optionally all parent menus
35039 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35041 hide : function(deep){
35042 if(this.el && this.isVisible()){
35043 this.fireEvent("beforehide", this);
35044 if(this.activeItem){
35045 this.activeItem.deactivate();
35046 this.activeItem = null;
35049 this.hidden = true;
35050 this.fireEvent("hide", this);
35052 if(deep === true && this.parentMenu){
35053 this.parentMenu.hide(true);
35058 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35059 * Any of the following are valid:
35061 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35062 * <li>An HTMLElement object which will be converted to a menu item</li>
35063 * <li>A menu item config object that will be created as a new menu item</li>
35064 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35065 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35070 var menu = new Roo.menu.Menu();
35072 // Create a menu item to add by reference
35073 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35075 // Add a bunch of items at once using different methods.
35076 // Only the last item added will be returned.
35077 var item = menu.add(
35078 menuItem, // add existing item by ref
35079 'Dynamic Item', // new TextItem
35080 '-', // new separator
35081 { text: 'Config Item' } // new item by config
35084 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35085 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35088 var a = arguments, l = a.length, item;
35089 for(var i = 0; i < l; i++){
35091 if ((typeof(el) == "object") && el.xtype && el.xns) {
35092 el = Roo.factory(el, Roo.menu);
35095 if(el.render){ // some kind of Item
35096 item = this.addItem(el);
35097 }else if(typeof el == "string"){ // string
35098 if(el == "separator" || el == "-"){
35099 item = this.addSeparator();
35101 item = this.addText(el);
35103 }else if(el.tagName || el.el){ // element
35104 item = this.addElement(el);
35105 }else if(typeof el == "object"){ // must be menu item config?
35106 item = this.addMenuItem(el);
35113 * Returns this menu's underlying {@link Roo.Element} object
35114 * @return {Roo.Element} The element
35116 getEl : function(){
35124 * Adds a separator bar to the menu
35125 * @return {Roo.menu.Item} The menu item that was added
35127 addSeparator : function(){
35128 return this.addItem(new Roo.menu.Separator());
35132 * Adds an {@link Roo.Element} object to the menu
35133 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35134 * @return {Roo.menu.Item} The menu item that was added
35136 addElement : function(el){
35137 return this.addItem(new Roo.menu.BaseItem(el));
35141 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35142 * @param {Roo.menu.Item} item The menu item to add
35143 * @return {Roo.menu.Item} The menu item that was added
35145 addItem : function(item){
35146 this.items.add(item);
35148 var li = document.createElement("li");
35149 li.className = "x-menu-list-item";
35150 this.ul.dom.appendChild(li);
35151 item.render(li, this);
35152 this.delayAutoWidth();
35158 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35159 * @param {Object} config A MenuItem config object
35160 * @return {Roo.menu.Item} The menu item that was added
35162 addMenuItem : function(config){
35163 if(!(config instanceof Roo.menu.Item)){
35164 if(typeof config.checked == "boolean"){ // must be check menu item config?
35165 config = new Roo.menu.CheckItem(config);
35167 config = new Roo.menu.Item(config);
35170 return this.addItem(config);
35174 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35175 * @param {String} text The text to display in the menu item
35176 * @return {Roo.menu.Item} The menu item that was added
35178 addText : function(text){
35179 return this.addItem(new Roo.menu.TextItem({ text : text }));
35183 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35184 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35185 * @param {Roo.menu.Item} item The menu item to add
35186 * @return {Roo.menu.Item} The menu item that was added
35188 insert : function(index, item){
35189 this.items.insert(index, item);
35191 var li = document.createElement("li");
35192 li.className = "x-menu-list-item";
35193 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35194 item.render(li, this);
35195 this.delayAutoWidth();
35201 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35202 * @param {Roo.menu.Item} item The menu item to remove
35204 remove : function(item){
35205 this.items.removeKey(item.id);
35210 * Removes and destroys all items in the menu
35212 removeAll : function(){
35214 while(f = this.items.first()){
35220 // MenuNav is a private utility class used internally by the Menu
35221 Roo.menu.MenuNav = function(menu){
35222 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35223 this.scope = this.menu = menu;
35226 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35227 doRelay : function(e, h){
35228 var k = e.getKey();
35229 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35230 this.menu.tryActivate(0, 1);
35233 return h.call(this.scope || this, e, this.menu);
35236 up : function(e, m){
35237 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35238 m.tryActivate(m.items.length-1, -1);
35242 down : function(e, m){
35243 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35244 m.tryActivate(0, 1);
35248 right : function(e, m){
35250 m.activeItem.expandMenu(true);
35254 left : function(e, m){
35256 if(m.parentMenu && m.parentMenu.activeItem){
35257 m.parentMenu.activeItem.activate();
35261 enter : function(e, m){
35263 e.stopPropagation();
35264 m.activeItem.onClick(e);
35265 m.fireEvent("click", this, m.activeItem);
35271 * Ext JS Library 1.1.1
35272 * Copyright(c) 2006-2007, Ext JS, LLC.
35274 * Originally Released Under LGPL - original licence link has changed is not relivant.
35277 * <script type="text/javascript">
35281 * @class Roo.menu.MenuMgr
35282 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35285 Roo.menu.MenuMgr = function(){
35286 var menus, active, groups = {}, attached = false, lastShow = new Date();
35288 // private - called when first menu is created
35291 active = new Roo.util.MixedCollection();
35292 Roo.get(document).addKeyListener(27, function(){
35293 if(active.length > 0){
35300 function hideAll(){
35301 if(active && active.length > 0){
35302 var c = active.clone();
35303 c.each(function(m){
35310 function onHide(m){
35312 if(active.length < 1){
35313 Roo.get(document).un("mousedown", onMouseDown);
35319 function onShow(m){
35320 var last = active.last();
35321 lastShow = new Date();
35324 Roo.get(document).on("mousedown", onMouseDown);
35328 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35329 m.parentMenu.activeChild = m;
35330 }else if(last && last.isVisible()){
35331 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35336 function onBeforeHide(m){
35338 m.activeChild.hide();
35340 if(m.autoHideTimer){
35341 clearTimeout(m.autoHideTimer);
35342 delete m.autoHideTimer;
35347 function onBeforeShow(m){
35348 var pm = m.parentMenu;
35349 if(!pm && !m.allowOtherMenus){
35351 }else if(pm && pm.activeChild && active != m){
35352 pm.activeChild.hide();
35357 function onMouseDown(e){
35358 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35364 function onBeforeCheck(mi, state){
35366 var g = groups[mi.group];
35367 for(var i = 0, l = g.length; i < l; i++){
35369 g[i].setChecked(false);
35378 * Hides all menus that are currently visible
35380 hideAll : function(){
35385 register : function(menu){
35389 menus[menu.id] = menu;
35390 menu.on("beforehide", onBeforeHide);
35391 menu.on("hide", onHide);
35392 menu.on("beforeshow", onBeforeShow);
35393 menu.on("show", onShow);
35394 var g = menu.group;
35395 if(g && menu.events["checkchange"]){
35399 groups[g].push(menu);
35400 menu.on("checkchange", onCheck);
35405 * Returns a {@link Roo.menu.Menu} object
35406 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35407 * be used to generate and return a new Menu instance.
35409 get : function(menu){
35410 if(typeof menu == "string"){ // menu id
35411 return menus[menu];
35412 }else if(menu.events){ // menu instance
35414 }else if(typeof menu.length == 'number'){ // array of menu items?
35415 return new Roo.menu.Menu({items:menu});
35416 }else{ // otherwise, must be a config
35417 return new Roo.menu.Menu(menu);
35422 unregister : function(menu){
35423 delete menus[menu.id];
35424 menu.un("beforehide", onBeforeHide);
35425 menu.un("hide", onHide);
35426 menu.un("beforeshow", onBeforeShow);
35427 menu.un("show", onShow);
35428 var g = menu.group;
35429 if(g && menu.events["checkchange"]){
35430 groups[g].remove(menu);
35431 menu.un("checkchange", onCheck);
35436 registerCheckable : function(menuItem){
35437 var g = menuItem.group;
35442 groups[g].push(menuItem);
35443 menuItem.on("beforecheckchange", onBeforeCheck);
35448 unregisterCheckable : function(menuItem){
35449 var g = menuItem.group;
35451 groups[g].remove(menuItem);
35452 menuItem.un("beforecheckchange", onBeforeCheck);
35458 * Ext JS Library 1.1.1
35459 * Copyright(c) 2006-2007, Ext JS, LLC.
35461 * Originally Released Under LGPL - original licence link has changed is not relivant.
35464 * <script type="text/javascript">
35469 * @class Roo.menu.BaseItem
35470 * @extends Roo.Component
35471 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
35472 * management and base configuration options shared by all menu components.
35474 * Creates a new BaseItem
35475 * @param {Object} config Configuration options
35477 Roo.menu.BaseItem = function(config){
35478 Roo.menu.BaseItem.superclass.constructor.call(this, config);
35483 * Fires when this item is clicked
35484 * @param {Roo.menu.BaseItem} this
35485 * @param {Roo.EventObject} e
35490 * Fires when this item is activated
35491 * @param {Roo.menu.BaseItem} this
35495 * @event deactivate
35496 * Fires when this item is deactivated
35497 * @param {Roo.menu.BaseItem} this
35503 this.on("click", this.handler, this.scope, true);
35507 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
35509 * @cfg {Function} handler
35510 * A function that will handle the click event of this menu item (defaults to undefined)
35513 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
35515 canActivate : false,
35518 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
35523 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
35525 activeClass : "x-menu-item-active",
35527 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
35529 hideOnClick : true,
35531 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
35536 ctype: "Roo.menu.BaseItem",
35539 actionMode : "container",
35542 render : function(container, parentMenu){
35543 this.parentMenu = parentMenu;
35544 Roo.menu.BaseItem.superclass.render.call(this, container);
35545 this.container.menuItemId = this.id;
35549 onRender : function(container, position){
35550 this.el = Roo.get(this.el);
35551 container.dom.appendChild(this.el.dom);
35555 onClick : function(e){
35556 if(!this.disabled && this.fireEvent("click", this, e) !== false
35557 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
35558 this.handleClick(e);
35565 activate : function(){
35569 var li = this.container;
35570 li.addClass(this.activeClass);
35571 this.region = li.getRegion().adjust(2, 2, -2, -2);
35572 this.fireEvent("activate", this);
35577 deactivate : function(){
35578 this.container.removeClass(this.activeClass);
35579 this.fireEvent("deactivate", this);
35583 shouldDeactivate : function(e){
35584 return !this.region || !this.region.contains(e.getPoint());
35588 handleClick : function(e){
35589 if(this.hideOnClick){
35590 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
35595 expandMenu : function(autoActivate){
35600 hideMenu : function(){
35605 * Ext JS Library 1.1.1
35606 * Copyright(c) 2006-2007, Ext JS, LLC.
35608 * Originally Released Under LGPL - original licence link has changed is not relivant.
35611 * <script type="text/javascript">
35615 * @class Roo.menu.Adapter
35616 * @extends Roo.menu.BaseItem
35617 * 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.
35618 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
35620 * Creates a new Adapter
35621 * @param {Object} config Configuration options
35623 Roo.menu.Adapter = function(component, config){
35624 Roo.menu.Adapter.superclass.constructor.call(this, config);
35625 this.component = component;
35627 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
35629 canActivate : true,
35632 onRender : function(container, position){
35633 this.component.render(container);
35634 this.el = this.component.getEl();
35638 activate : function(){
35642 this.component.focus();
35643 this.fireEvent("activate", this);
35648 deactivate : function(){
35649 this.fireEvent("deactivate", this);
35653 disable : function(){
35654 this.component.disable();
35655 Roo.menu.Adapter.superclass.disable.call(this);
35659 enable : function(){
35660 this.component.enable();
35661 Roo.menu.Adapter.superclass.enable.call(this);
35665 * Ext JS Library 1.1.1
35666 * Copyright(c) 2006-2007, Ext JS, LLC.
35668 * Originally Released Under LGPL - original licence link has changed is not relivant.
35671 * <script type="text/javascript">
35675 * @class Roo.menu.TextItem
35676 * @extends Roo.menu.BaseItem
35677 * Adds a static text string to a menu, usually used as either a heading or group separator.
35678 * Note: old style constructor with text is still supported.
35681 * Creates a new TextItem
35682 * @param {Object} cfg Configuration
35684 Roo.menu.TextItem = function(cfg){
35685 if (typeof(cfg) == 'string') {
35688 Roo.apply(this,cfg);
35691 Roo.menu.TextItem.superclass.constructor.call(this);
35694 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
35696 * @cfg {Boolean} text Text to show on item.
35701 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35703 hideOnClick : false,
35705 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35707 itemCls : "x-menu-text",
35710 onRender : function(){
35711 var s = document.createElement("span");
35712 s.className = this.itemCls;
35713 s.innerHTML = this.text;
35715 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35719 * Ext JS Library 1.1.1
35720 * Copyright(c) 2006-2007, Ext JS, LLC.
35722 * Originally Released Under LGPL - original licence link has changed is not relivant.
35725 * <script type="text/javascript">
35729 * @class Roo.menu.Separator
35730 * @extends Roo.menu.BaseItem
35731 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35732 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35734 * @param {Object} config Configuration options
35736 Roo.menu.Separator = function(config){
35737 Roo.menu.Separator.superclass.constructor.call(this, config);
35740 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35742 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35744 itemCls : "x-menu-sep",
35746 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35748 hideOnClick : false,
35751 onRender : function(li){
35752 var s = document.createElement("span");
35753 s.className = this.itemCls;
35754 s.innerHTML = " ";
35756 li.addClass("x-menu-sep-li");
35757 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35761 * Ext JS Library 1.1.1
35762 * Copyright(c) 2006-2007, Ext JS, LLC.
35764 * Originally Released Under LGPL - original licence link has changed is not relivant.
35767 * <script type="text/javascript">
35770 * @class Roo.menu.Item
35771 * @extends Roo.menu.BaseItem
35772 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35773 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35774 * activation and click handling.
35776 * Creates a new Item
35777 * @param {Object} config Configuration options
35779 Roo.menu.Item = function(config){
35780 Roo.menu.Item.superclass.constructor.call(this, config);
35782 this.menu = Roo.menu.MenuMgr.get(this.menu);
35785 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35788 * @cfg {String} text
35789 * The text to show on the menu item.
35793 * @cfg {String} HTML to render in menu
35794 * The text to show on the menu item (HTML version).
35798 * @cfg {String} icon
35799 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35803 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35805 itemCls : "x-menu-item",
35807 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35809 canActivate : true,
35811 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35814 // doc'd in BaseItem
35818 ctype: "Roo.menu.Item",
35821 onRender : function(container, position){
35822 var el = document.createElement("a");
35823 el.hideFocus = true;
35824 el.unselectable = "on";
35825 el.href = this.href || "#";
35826 if(this.hrefTarget){
35827 el.target = this.hrefTarget;
35829 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35831 var html = this.html.length ? this.html : String.format('{0}',this.text);
35833 el.innerHTML = String.format(
35834 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35835 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35837 Roo.menu.Item.superclass.onRender.call(this, container, position);
35841 * Sets the text to display in this menu item
35842 * @param {String} text The text to display
35843 * @param {Boolean} isHTML true to indicate text is pure html.
35845 setText : function(text, isHTML){
35853 var html = this.html.length ? this.html : String.format('{0}',this.text);
35855 this.el.update(String.format(
35856 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35857 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35858 this.parentMenu.autoWidth();
35863 handleClick : function(e){
35864 if(!this.href){ // if no link defined, stop the event automatically
35867 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35871 activate : function(autoExpand){
35872 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35882 shouldDeactivate : function(e){
35883 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35884 if(this.menu && this.menu.isVisible()){
35885 return !this.menu.getEl().getRegion().contains(e.getPoint());
35893 deactivate : function(){
35894 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35899 expandMenu : function(autoActivate){
35900 if(!this.disabled && this.menu){
35901 clearTimeout(this.hideTimer);
35902 delete this.hideTimer;
35903 if(!this.menu.isVisible() && !this.showTimer){
35904 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35905 }else if (this.menu.isVisible() && autoActivate){
35906 this.menu.tryActivate(0, 1);
35912 deferExpand : function(autoActivate){
35913 delete this.showTimer;
35914 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35916 this.menu.tryActivate(0, 1);
35921 hideMenu : function(){
35922 clearTimeout(this.showTimer);
35923 delete this.showTimer;
35924 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35925 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35930 deferHide : function(){
35931 delete this.hideTimer;
35936 * Ext JS Library 1.1.1
35937 * Copyright(c) 2006-2007, Ext JS, LLC.
35939 * Originally Released Under LGPL - original licence link has changed is not relivant.
35942 * <script type="text/javascript">
35946 * @class Roo.menu.CheckItem
35947 * @extends Roo.menu.Item
35948 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35950 * Creates a new CheckItem
35951 * @param {Object} config Configuration options
35953 Roo.menu.CheckItem = function(config){
35954 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35957 * @event beforecheckchange
35958 * Fires before the checked value is set, providing an opportunity to cancel if needed
35959 * @param {Roo.menu.CheckItem} this
35960 * @param {Boolean} checked The new checked value that will be set
35962 "beforecheckchange" : true,
35964 * @event checkchange
35965 * Fires after the checked value has been set
35966 * @param {Roo.menu.CheckItem} this
35967 * @param {Boolean} checked The checked value that was set
35969 "checkchange" : true
35971 if(this.checkHandler){
35972 this.on('checkchange', this.checkHandler, this.scope);
35975 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35977 * @cfg {String} group
35978 * All check items with the same group name will automatically be grouped into a single-select
35979 * radio button group (defaults to '')
35982 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35984 itemCls : "x-menu-item x-menu-check-item",
35986 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35988 groupClass : "x-menu-group-item",
35991 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35992 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35993 * initialized with checked = true will be rendered as checked.
35998 ctype: "Roo.menu.CheckItem",
36001 onRender : function(c){
36002 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36004 this.el.addClass(this.groupClass);
36006 Roo.menu.MenuMgr.registerCheckable(this);
36008 this.checked = false;
36009 this.setChecked(true, true);
36014 destroy : function(){
36016 Roo.menu.MenuMgr.unregisterCheckable(this);
36018 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36022 * Set the checked state of this item
36023 * @param {Boolean} checked The new checked value
36024 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36026 setChecked : function(state, suppressEvent){
36027 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36028 if(this.container){
36029 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36031 this.checked = state;
36032 if(suppressEvent !== true){
36033 this.fireEvent("checkchange", this, state);
36039 handleClick : function(e){
36040 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36041 this.setChecked(!this.checked);
36043 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36047 * Ext JS Library 1.1.1
36048 * Copyright(c) 2006-2007, Ext JS, LLC.
36050 * Originally Released Under LGPL - original licence link has changed is not relivant.
36053 * <script type="text/javascript">
36057 * @class Roo.menu.DateItem
36058 * @extends Roo.menu.Adapter
36059 * A menu item that wraps the {@link Roo.DatPicker} component.
36061 * Creates a new DateItem
36062 * @param {Object} config Configuration options
36064 Roo.menu.DateItem = function(config){
36065 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36066 /** The Roo.DatePicker object @type Roo.DatePicker */
36067 this.picker = this.component;
36068 this.addEvents({select: true});
36070 this.picker.on("render", function(picker){
36071 picker.getEl().swallowEvent("click");
36072 picker.container.addClass("x-menu-date-item");
36075 this.picker.on("select", this.onSelect, this);
36078 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36080 onSelect : function(picker, date){
36081 this.fireEvent("select", this, date, picker);
36082 Roo.menu.DateItem.superclass.handleClick.call(this);
36086 * Ext JS Library 1.1.1
36087 * Copyright(c) 2006-2007, Ext JS, LLC.
36089 * Originally Released Under LGPL - original licence link has changed is not relivant.
36092 * <script type="text/javascript">
36096 * @class Roo.menu.ColorItem
36097 * @extends Roo.menu.Adapter
36098 * A menu item that wraps the {@link Roo.ColorPalette} component.
36100 * Creates a new ColorItem
36101 * @param {Object} config Configuration options
36103 Roo.menu.ColorItem = function(config){
36104 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36105 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36106 this.palette = this.component;
36107 this.relayEvents(this.palette, ["select"]);
36108 if(this.selectHandler){
36109 this.on('select', this.selectHandler, this.scope);
36112 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36114 * Ext JS Library 1.1.1
36115 * Copyright(c) 2006-2007, Ext JS, LLC.
36117 * Originally Released Under LGPL - original licence link has changed is not relivant.
36120 * <script type="text/javascript">
36125 * @class Roo.menu.DateMenu
36126 * @extends Roo.menu.Menu
36127 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36129 * Creates a new DateMenu
36130 * @param {Object} config Configuration options
36132 Roo.menu.DateMenu = function(config){
36133 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36135 var di = new Roo.menu.DateItem(config);
36138 * The {@link Roo.DatePicker} instance for this DateMenu
36141 this.picker = di.picker;
36144 * @param {DatePicker} picker
36145 * @param {Date} date
36147 this.relayEvents(di, ["select"]);
36148 this.on('beforeshow', function(){
36150 this.picker.hideMonthPicker(false);
36154 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36158 * Ext JS Library 1.1.1
36159 * Copyright(c) 2006-2007, Ext JS, LLC.
36161 * Originally Released Under LGPL - original licence link has changed is not relivant.
36164 * <script type="text/javascript">
36169 * @class Roo.menu.ColorMenu
36170 * @extends Roo.menu.Menu
36171 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36173 * Creates a new ColorMenu
36174 * @param {Object} config Configuration options
36176 Roo.menu.ColorMenu = function(config){
36177 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36179 var ci = new Roo.menu.ColorItem(config);
36182 * The {@link Roo.ColorPalette} instance for this ColorMenu
36183 * @type ColorPalette
36185 this.palette = ci.palette;
36188 * @param {ColorPalette} palette
36189 * @param {String} color
36191 this.relayEvents(ci, ["select"]);
36193 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36195 * Ext JS Library 1.1.1
36196 * Copyright(c) 2006-2007, Ext JS, LLC.
36198 * Originally Released Under LGPL - original licence link has changed is not relivant.
36201 * <script type="text/javascript">
36205 * @class Roo.form.Field
36206 * @extends Roo.BoxComponent
36207 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36209 * Creates a new Field
36210 * @param {Object} config Configuration options
36212 Roo.form.Field = function(config){
36213 Roo.form.Field.superclass.constructor.call(this, config);
36216 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36218 * @cfg {String} fieldLabel Label to use when rendering a form.
36221 * @cfg {String} qtip Mouse over tip
36225 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36227 invalidClass : "x-form-invalid",
36229 * @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")
36231 invalidText : "The value in this field is invalid",
36233 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36235 focusClass : "x-form-focus",
36237 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36238 automatic validation (defaults to "keyup").
36240 validationEvent : "keyup",
36242 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36244 validateOnBlur : true,
36246 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36248 validationDelay : 250,
36250 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36251 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36253 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36255 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36257 fieldClass : "x-form-field",
36259 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36262 ----------- ----------------------------------------------------------------------
36263 qtip Display a quick tip when the user hovers over the field
36264 title Display a default browser title attribute popup
36265 under Add a block div beneath the field containing the error text
36266 side Add an error icon to the right of the field with a popup on hover
36267 [element id] Add the error text directly to the innerHTML of the specified element
36270 msgTarget : 'qtip',
36272 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36277 * @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.
36282 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36287 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36289 inputType : undefined,
36292 * @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).
36294 tabIndex : undefined,
36297 isFormField : true,
36302 * @property {Roo.Element} fieldEl
36303 * Element Containing the rendered Field (with label etc.)
36306 * @cfg {Mixed} value A value to initialize this field with.
36311 * @cfg {String} name The field's HTML name attribute.
36314 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36318 initComponent : function(){
36319 Roo.form.Field.superclass.initComponent.call(this);
36323 * Fires when this field receives input focus.
36324 * @param {Roo.form.Field} this
36329 * Fires when this field loses input focus.
36330 * @param {Roo.form.Field} this
36334 * @event specialkey
36335 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36336 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36337 * @param {Roo.form.Field} this
36338 * @param {Roo.EventObject} e The event object
36343 * Fires just before the field blurs if the field value has changed.
36344 * @param {Roo.form.Field} this
36345 * @param {Mixed} newValue The new value
36346 * @param {Mixed} oldValue The original value
36351 * Fires after the field has been marked as invalid.
36352 * @param {Roo.form.Field} this
36353 * @param {String} msg The validation message
36358 * Fires after the field has been validated with no errors.
36359 * @param {Roo.form.Field} this
36364 * Fires after the key up
36365 * @param {Roo.form.Field} this
36366 * @param {Roo.EventObject} e The event Object
36373 * Returns the name attribute of the field if available
36374 * @return {String} name The field name
36376 getName: function(){
36377 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36381 onRender : function(ct, position){
36382 Roo.form.Field.superclass.onRender.call(this, ct, position);
36384 var cfg = this.getAutoCreate();
36386 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
36388 if (!cfg.name.length) {
36391 if(this.inputType){
36392 cfg.type = this.inputType;
36394 this.el = ct.createChild(cfg, position);
36396 var type = this.el.dom.type;
36398 if(type == 'password'){
36401 this.el.addClass('x-form-'+type);
36404 this.el.dom.readOnly = true;
36406 if(this.tabIndex !== undefined){
36407 this.el.dom.setAttribute('tabIndex', this.tabIndex);
36410 this.el.addClass([this.fieldClass, this.cls]);
36415 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
36416 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
36417 * @return {Roo.form.Field} this
36419 applyTo : function(target){
36420 this.allowDomMove = false;
36421 this.el = Roo.get(target);
36422 this.render(this.el.dom.parentNode);
36427 initValue : function(){
36428 if(this.value !== undefined){
36429 this.setValue(this.value);
36430 }else if(this.el.dom.value.length > 0){
36431 this.setValue(this.el.dom.value);
36436 * Returns true if this field has been changed since it was originally loaded and is not disabled.
36438 isDirty : function() {
36439 if(this.disabled) {
36442 return String(this.getValue()) !== String(this.originalValue);
36446 afterRender : function(){
36447 Roo.form.Field.superclass.afterRender.call(this);
36452 fireKey : function(e){
36453 //Roo.log('field ' + e.getKey());
36454 if(e.isNavKeyPress()){
36455 this.fireEvent("specialkey", this, e);
36460 * Resets the current field value to the originally loaded value and clears any validation messages
36462 reset : function(){
36463 this.setValue(this.originalValue);
36464 this.clearInvalid();
36468 initEvents : function(){
36469 // safari killled keypress - so keydown is now used..
36470 this.el.on("keydown" , this.fireKey, this);
36471 this.el.on("focus", this.onFocus, this);
36472 this.el.on("blur", this.onBlur, this);
36473 this.el.relayEvent('keyup', this);
36475 // reference to original value for reset
36476 this.originalValue = this.getValue();
36480 onFocus : function(){
36481 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36482 this.el.addClass(this.focusClass);
36484 if(!this.hasFocus){
36485 this.hasFocus = true;
36486 this.startValue = this.getValue();
36487 this.fireEvent("focus", this);
36491 beforeBlur : Roo.emptyFn,
36494 onBlur : function(){
36496 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36497 this.el.removeClass(this.focusClass);
36499 this.hasFocus = false;
36500 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
36503 var v = this.getValue();
36504 if(String(v) !== String(this.startValue)){
36505 this.fireEvent('change', this, v, this.startValue);
36507 this.fireEvent("blur", this);
36511 * Returns whether or not the field value is currently valid
36512 * @param {Boolean} preventMark True to disable marking the field invalid
36513 * @return {Boolean} True if the value is valid, else false
36515 isValid : function(preventMark){
36519 var restore = this.preventMark;
36520 this.preventMark = preventMark === true;
36521 var v = this.validateValue(this.processValue(this.getRawValue()));
36522 this.preventMark = restore;
36527 * Validates the field value
36528 * @return {Boolean} True if the value is valid, else false
36530 validate : function(){
36531 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
36532 this.clearInvalid();
36538 processValue : function(value){
36543 // Subclasses should provide the validation implementation by overriding this
36544 validateValue : function(value){
36549 * Mark this field as invalid
36550 * @param {String} msg The validation message
36552 markInvalid : function(msg){
36553 if(!this.rendered || this.preventMark){ // not rendered
36556 this.el.addClass(this.invalidClass);
36557 msg = msg || this.invalidText;
36558 switch(this.msgTarget){
36560 this.el.dom.qtip = msg;
36561 this.el.dom.qclass = 'x-form-invalid-tip';
36562 if(Roo.QuickTips){ // fix for floating editors interacting with DND
36563 Roo.QuickTips.enable();
36567 this.el.dom.title = msg;
36571 var elp = this.el.findParent('.x-form-element', 5, true);
36572 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
36573 this.errorEl.setWidth(elp.getWidth(true)-20);
36575 this.errorEl.update(msg);
36576 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
36579 if(!this.errorIcon){
36580 var elp = this.el.findParent('.x-form-element', 5, true);
36581 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
36583 this.alignErrorIcon();
36584 this.errorIcon.dom.qtip = msg;
36585 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
36586 this.errorIcon.show();
36587 this.on('resize', this.alignErrorIcon, this);
36590 var t = Roo.getDom(this.msgTarget);
36592 t.style.display = this.msgDisplay;
36595 this.fireEvent('invalid', this, msg);
36599 alignErrorIcon : function(){
36600 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
36604 * Clear any invalid styles/messages for this field
36606 clearInvalid : function(){
36607 if(!this.rendered || this.preventMark){ // not rendered
36610 this.el.removeClass(this.invalidClass);
36611 switch(this.msgTarget){
36613 this.el.dom.qtip = '';
36616 this.el.dom.title = '';
36620 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
36624 if(this.errorIcon){
36625 this.errorIcon.dom.qtip = '';
36626 this.errorIcon.hide();
36627 this.un('resize', this.alignErrorIcon, this);
36631 var t = Roo.getDom(this.msgTarget);
36633 t.style.display = 'none';
36636 this.fireEvent('valid', this);
36640 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
36641 * @return {Mixed} value The field value
36643 getRawValue : function(){
36644 var v = this.el.getValue();
36650 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
36651 * @return {Mixed} value The field value
36653 getValue : function(){
36654 var v = this.el.getValue();
36660 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
36661 * @param {Mixed} value The value to set
36663 setRawValue : function(v){
36664 return this.el.dom.value = (v === null || v === undefined ? '' : v);
36668 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
36669 * @param {Mixed} value The value to set
36671 setValue : function(v){
36674 this.el.dom.value = (v === null || v === undefined ? '' : v);
36679 adjustSize : function(w, h){
36680 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
36681 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
36685 adjustWidth : function(tag, w){
36686 tag = tag.toLowerCase();
36687 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
36688 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
36689 if(tag == 'input'){
36692 if(tag == 'textarea'){
36695 }else if(Roo.isOpera){
36696 if(tag == 'input'){
36699 if(tag == 'textarea'){
36709 // anything other than normal should be considered experimental
36710 Roo.form.Field.msgFx = {
36712 show: function(msgEl, f){
36713 msgEl.setDisplayed('block');
36716 hide : function(msgEl, f){
36717 msgEl.setDisplayed(false).update('');
36722 show: function(msgEl, f){
36723 msgEl.slideIn('t', {stopFx:true});
36726 hide : function(msgEl, f){
36727 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36732 show: function(msgEl, f){
36733 msgEl.fixDisplay();
36734 msgEl.alignTo(f.el, 'tl-tr');
36735 msgEl.slideIn('l', {stopFx:true});
36738 hide : function(msgEl, f){
36739 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36744 * Ext JS Library 1.1.1
36745 * Copyright(c) 2006-2007, Ext JS, LLC.
36747 * Originally Released Under LGPL - original licence link has changed is not relivant.
36750 * <script type="text/javascript">
36755 * @class Roo.form.TextField
36756 * @extends Roo.form.Field
36757 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36758 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36760 * Creates a new TextField
36761 * @param {Object} config Configuration options
36763 Roo.form.TextField = function(config){
36764 Roo.form.TextField.superclass.constructor.call(this, config);
36768 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36769 * according to the default logic, but this event provides a hook for the developer to apply additional
36770 * logic at runtime to resize the field if needed.
36771 * @param {Roo.form.Field} this This text field
36772 * @param {Number} width The new field width
36778 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36780 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36784 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36788 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36792 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36796 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36800 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36802 disableKeyFilter : false,
36804 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36808 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36812 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36814 maxLength : Number.MAX_VALUE,
36816 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36818 minLengthText : "The minimum length for this field is {0}",
36820 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36822 maxLengthText : "The maximum length for this field is {0}",
36824 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36826 selectOnFocus : false,
36828 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36830 blankText : "This field is required",
36832 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36833 * If available, this function will be called only after the basic validators all return true, and will be passed the
36834 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36838 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36839 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36840 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36844 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36848 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
36854 initEvents : function()
36856 if (this.emptyText) {
36857 this.el.attr('placeholder', this.emptyText);
36860 Roo.form.TextField.superclass.initEvents.call(this);
36861 if(this.validationEvent == 'keyup'){
36862 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36863 this.el.on('keyup', this.filterValidation, this);
36865 else if(this.validationEvent !== false){
36866 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36869 if(this.selectOnFocus){
36870 this.on("focus", this.preFocus, this);
36873 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36874 this.el.on("keypress", this.filterKeys, this);
36877 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36878 this.el.on("click", this.autoSize, this);
36880 if(this.el.is('input[type=password]') && Roo.isSafari){
36881 this.el.on('keydown', this.SafariOnKeyDown, this);
36885 processValue : function(value){
36886 if(this.stripCharsRe){
36887 var newValue = value.replace(this.stripCharsRe, '');
36888 if(newValue !== value){
36889 this.setRawValue(newValue);
36896 filterValidation : function(e){
36897 if(!e.isNavKeyPress()){
36898 this.validationTask.delay(this.validationDelay);
36903 onKeyUp : function(e){
36904 if(!e.isNavKeyPress()){
36910 * Resets the current field value to the originally-loaded value and clears any validation messages.
36913 reset : function(){
36914 Roo.form.TextField.superclass.reset.call(this);
36920 preFocus : function(){
36922 if(this.selectOnFocus){
36923 this.el.dom.select();
36929 filterKeys : function(e){
36930 var k = e.getKey();
36931 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36934 var c = e.getCharCode(), cc = String.fromCharCode(c);
36935 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36938 if(!this.maskRe.test(cc)){
36943 setValue : function(v){
36945 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36951 * Validates a value according to the field's validation rules and marks the field as invalid
36952 * if the validation fails
36953 * @param {Mixed} value The value to validate
36954 * @return {Boolean} True if the value is valid, else false
36956 validateValue : function(value){
36957 if(value.length < 1) { // if it's blank
36958 if(this.allowBlank){
36959 this.clearInvalid();
36962 this.markInvalid(this.blankText);
36966 if(value.length < this.minLength){
36967 this.markInvalid(String.format(this.minLengthText, this.minLength));
36970 if(value.length > this.maxLength){
36971 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36975 var vt = Roo.form.VTypes;
36976 if(!vt[this.vtype](value, this)){
36977 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36981 if(typeof this.validator == "function"){
36982 var msg = this.validator(value);
36984 this.markInvalid(msg);
36988 if(this.regex && !this.regex.test(value)){
36989 this.markInvalid(this.regexText);
36996 * Selects text in this field
36997 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36998 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37000 selectText : function(start, end){
37001 var v = this.getRawValue();
37003 start = start === undefined ? 0 : start;
37004 end = end === undefined ? v.length : end;
37005 var d = this.el.dom;
37006 if(d.setSelectionRange){
37007 d.setSelectionRange(start, end);
37008 }else if(d.createTextRange){
37009 var range = d.createTextRange();
37010 range.moveStart("character", start);
37011 range.moveEnd("character", v.length-end);
37018 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37019 * This only takes effect if grow = true, and fires the autosize event.
37021 autoSize : function(){
37022 if(!this.grow || !this.rendered){
37026 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37029 var v = el.dom.value;
37030 var d = document.createElement('div');
37031 d.appendChild(document.createTextNode(v));
37035 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37036 this.el.setWidth(w);
37037 this.fireEvent("autosize", this, w);
37041 SafariOnKeyDown : function(event)
37043 // this is a workaround for a password hang bug on chrome/ webkit.
37045 var isSelectAll = false;
37047 if(this.el.dom.selectionEnd > 0){
37048 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37050 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37051 event.preventDefault();
37056 if(isSelectAll){ // backspace and delete key
37058 event.preventDefault();
37059 // this is very hacky as keydown always get's upper case.
37061 var cc = String.fromCharCode(event.getCharCode());
37062 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37070 * Ext JS Library 1.1.1
37071 * Copyright(c) 2006-2007, Ext JS, LLC.
37073 * Originally Released Under LGPL - original licence link has changed is not relivant.
37076 * <script type="text/javascript">
37080 * @class Roo.form.Hidden
37081 * @extends Roo.form.TextField
37082 * Simple Hidden element used on forms
37084 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37087 * Creates a new Hidden form element.
37088 * @param {Object} config Configuration options
37093 // easy hidden field...
37094 Roo.form.Hidden = function(config){
37095 Roo.form.Hidden.superclass.constructor.call(this, config);
37098 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37100 inputType: 'hidden',
37103 labelSeparator: '',
37105 itemCls : 'x-form-item-display-none'
37113 * Ext JS Library 1.1.1
37114 * Copyright(c) 2006-2007, Ext JS, LLC.
37116 * Originally Released Under LGPL - original licence link has changed is not relivant.
37119 * <script type="text/javascript">
37123 * @class Roo.form.TriggerField
37124 * @extends Roo.form.TextField
37125 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37126 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37127 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37128 * for which you can provide a custom implementation. For example:
37130 var trigger = new Roo.form.TriggerField();
37131 trigger.onTriggerClick = myTriggerFn;
37132 trigger.applyTo('my-field');
37135 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37136 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37137 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37138 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37140 * Create a new TriggerField.
37141 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37142 * to the base TextField)
37144 Roo.form.TriggerField = function(config){
37145 this.mimicing = false;
37146 Roo.form.TriggerField.superclass.constructor.call(this, config);
37149 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37151 * @cfg {String} triggerClass A CSS class to apply to the trigger
37154 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37155 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37157 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37159 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37163 /** @cfg {Boolean} grow @hide */
37164 /** @cfg {Number} growMin @hide */
37165 /** @cfg {Number} growMax @hide */
37171 autoSize: Roo.emptyFn,
37175 deferHeight : true,
37178 actionMode : 'wrap',
37180 onResize : function(w, h){
37181 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37182 if(typeof w == 'number'){
37183 var x = w - this.trigger.getWidth();
37184 this.el.setWidth(this.adjustWidth('input', x));
37185 this.trigger.setStyle('left', x+'px');
37190 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37193 getResizeEl : function(){
37198 getPositionEl : function(){
37203 alignErrorIcon : function(){
37204 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37208 onRender : function(ct, position){
37209 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37210 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37211 this.trigger = this.wrap.createChild(this.triggerConfig ||
37212 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37213 if(this.hideTrigger){
37214 this.trigger.setDisplayed(false);
37216 this.initTrigger();
37218 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37223 initTrigger : function(){
37224 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37225 this.trigger.addClassOnOver('x-form-trigger-over');
37226 this.trigger.addClassOnClick('x-form-trigger-click');
37230 onDestroy : function(){
37232 this.trigger.removeAllListeners();
37233 this.trigger.remove();
37236 this.wrap.remove();
37238 Roo.form.TriggerField.superclass.onDestroy.call(this);
37242 onFocus : function(){
37243 Roo.form.TriggerField.superclass.onFocus.call(this);
37244 if(!this.mimicing){
37245 this.wrap.addClass('x-trigger-wrap-focus');
37246 this.mimicing = true;
37247 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37248 if(this.monitorTab){
37249 this.el.on("keydown", this.checkTab, this);
37255 checkTab : function(e){
37256 if(e.getKey() == e.TAB){
37257 this.triggerBlur();
37262 onBlur : function(){
37267 mimicBlur : function(e, t){
37268 if(!this.wrap.contains(t) && this.validateBlur()){
37269 this.triggerBlur();
37274 triggerBlur : function(){
37275 this.mimicing = false;
37276 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37277 if(this.monitorTab){
37278 this.el.un("keydown", this.checkTab, this);
37280 this.wrap.removeClass('x-trigger-wrap-focus');
37281 Roo.form.TriggerField.superclass.onBlur.call(this);
37285 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37286 validateBlur : function(e, t){
37291 onDisable : function(){
37292 Roo.form.TriggerField.superclass.onDisable.call(this);
37294 this.wrap.addClass('x-item-disabled');
37299 onEnable : function(){
37300 Roo.form.TriggerField.superclass.onEnable.call(this);
37302 this.wrap.removeClass('x-item-disabled');
37307 onShow : function(){
37308 var ae = this.getActionEl();
37311 ae.dom.style.display = '';
37312 ae.dom.style.visibility = 'visible';
37318 onHide : function(){
37319 var ae = this.getActionEl();
37320 ae.dom.style.display = 'none';
37324 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37325 * by an implementing function.
37327 * @param {EventObject} e
37329 onTriggerClick : Roo.emptyFn
37332 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37333 // to be extended by an implementing class. For an example of implementing this class, see the custom
37334 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37335 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37336 initComponent : function(){
37337 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37339 this.triggerConfig = {
37340 tag:'span', cls:'x-form-twin-triggers', cn:[
37341 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37342 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37346 getTrigger : function(index){
37347 return this.triggers[index];
37350 initTrigger : function(){
37351 var ts = this.trigger.select('.x-form-trigger', true);
37352 this.wrap.setStyle('overflow', 'hidden');
37353 var triggerField = this;
37354 ts.each(function(t, all, index){
37355 t.hide = function(){
37356 var w = triggerField.wrap.getWidth();
37357 this.dom.style.display = 'none';
37358 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37360 t.show = function(){
37361 var w = triggerField.wrap.getWidth();
37362 this.dom.style.display = '';
37363 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37365 var triggerIndex = 'Trigger'+(index+1);
37367 if(this['hide'+triggerIndex]){
37368 t.dom.style.display = 'none';
37370 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37371 t.addClassOnOver('x-form-trigger-over');
37372 t.addClassOnClick('x-form-trigger-click');
37374 this.triggers = ts.elements;
37377 onTrigger1Click : Roo.emptyFn,
37378 onTrigger2Click : Roo.emptyFn
37381 * Ext JS Library 1.1.1
37382 * Copyright(c) 2006-2007, Ext JS, LLC.
37384 * Originally Released Under LGPL - original licence link has changed is not relivant.
37387 * <script type="text/javascript">
37391 * @class Roo.form.TextArea
37392 * @extends Roo.form.TextField
37393 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37394 * support for auto-sizing.
37396 * Creates a new TextArea
37397 * @param {Object} config Configuration options
37399 Roo.form.TextArea = function(config){
37400 Roo.form.TextArea.superclass.constructor.call(this, config);
37401 // these are provided exchanges for backwards compat
37402 // minHeight/maxHeight were replaced by growMin/growMax to be
37403 // compatible with TextField growing config values
37404 if(this.minHeight !== undefined){
37405 this.growMin = this.minHeight;
37407 if(this.maxHeight !== undefined){
37408 this.growMax = this.maxHeight;
37412 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
37414 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
37418 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
37422 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
37423 * in the field (equivalent to setting overflow: hidden, defaults to false)
37425 preventScrollbars: false,
37427 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37428 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
37432 onRender : function(ct, position){
37434 this.defaultAutoCreate = {
37436 style:"width:300px;height:60px;",
37437 autocomplete: "off"
37440 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
37442 this.textSizeEl = Roo.DomHelper.append(document.body, {
37443 tag: "pre", cls: "x-form-grow-sizer"
37445 if(this.preventScrollbars){
37446 this.el.setStyle("overflow", "hidden");
37448 this.el.setHeight(this.growMin);
37452 onDestroy : function(){
37453 if(this.textSizeEl){
37454 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
37456 Roo.form.TextArea.superclass.onDestroy.call(this);
37460 onKeyUp : function(e){
37461 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
37467 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
37468 * This only takes effect if grow = true, and fires the autosize event if the height changes.
37470 autoSize : function(){
37471 if(!this.grow || !this.textSizeEl){
37475 var v = el.dom.value;
37476 var ts = this.textSizeEl;
37479 ts.appendChild(document.createTextNode(v));
37482 Roo.fly(ts).setWidth(this.el.getWidth());
37484 v = "  ";
37487 v = v.replace(/\n/g, '<p> </p>');
37489 v += " \n ";
37492 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
37493 if(h != this.lastHeight){
37494 this.lastHeight = h;
37495 this.el.setHeight(h);
37496 this.fireEvent("autosize", this, h);
37501 * Ext JS Library 1.1.1
37502 * Copyright(c) 2006-2007, Ext JS, LLC.
37504 * Originally Released Under LGPL - original licence link has changed is not relivant.
37507 * <script type="text/javascript">
37512 * @class Roo.form.NumberField
37513 * @extends Roo.form.TextField
37514 * Numeric text field that provides automatic keystroke filtering and numeric validation.
37516 * Creates a new NumberField
37517 * @param {Object} config Configuration options
37519 Roo.form.NumberField = function(config){
37520 Roo.form.NumberField.superclass.constructor.call(this, config);
37523 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
37525 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
37527 fieldClass: "x-form-field x-form-num-field",
37529 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
37531 allowDecimals : true,
37533 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
37535 decimalSeparator : ".",
37537 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
37539 decimalPrecision : 2,
37541 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
37543 allowNegative : true,
37545 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
37547 minValue : Number.NEGATIVE_INFINITY,
37549 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
37551 maxValue : Number.MAX_VALUE,
37553 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
37555 minText : "The minimum value for this field is {0}",
37557 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
37559 maxText : "The maximum value for this field is {0}",
37561 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
37562 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
37564 nanText : "{0} is not a valid number",
37567 initEvents : function(){
37568 Roo.form.NumberField.superclass.initEvents.call(this);
37569 var allowed = "0123456789";
37570 if(this.allowDecimals){
37571 allowed += this.decimalSeparator;
37573 if(this.allowNegative){
37576 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
37577 var keyPress = function(e){
37578 var k = e.getKey();
37579 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
37582 var c = e.getCharCode();
37583 if(allowed.indexOf(String.fromCharCode(c)) === -1){
37587 this.el.on("keypress", keyPress, this);
37591 validateValue : function(value){
37592 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
37595 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37598 var num = this.parseValue(value);
37600 this.markInvalid(String.format(this.nanText, value));
37603 if(num < this.minValue){
37604 this.markInvalid(String.format(this.minText, this.minValue));
37607 if(num > this.maxValue){
37608 this.markInvalid(String.format(this.maxText, this.maxValue));
37614 getValue : function(){
37615 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
37619 parseValue : function(value){
37620 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
37621 return isNaN(value) ? '' : value;
37625 fixPrecision : function(value){
37626 var nan = isNaN(value);
37627 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
37628 return nan ? '' : value;
37630 return parseFloat(value).toFixed(this.decimalPrecision);
37633 setValue : function(v){
37634 v = this.fixPrecision(v);
37635 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
37639 decimalPrecisionFcn : function(v){
37640 return Math.floor(v);
37643 beforeBlur : function(){
37644 var v = this.parseValue(this.getRawValue());
37651 * Ext JS Library 1.1.1
37652 * Copyright(c) 2006-2007, Ext JS, LLC.
37654 * Originally Released Under LGPL - original licence link has changed is not relivant.
37657 * <script type="text/javascript">
37661 * @class Roo.form.DateField
37662 * @extends Roo.form.TriggerField
37663 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37665 * Create a new DateField
37666 * @param {Object} config
37668 Roo.form.DateField = function(config){
37669 Roo.form.DateField.superclass.constructor.call(this, config);
37675 * Fires when a date is selected
37676 * @param {Roo.form.DateField} combo This combo box
37677 * @param {Date} date The date selected
37684 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37685 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37686 this.ddMatch = null;
37687 if(this.disabledDates){
37688 var dd = this.disabledDates;
37690 for(var i = 0; i < dd.length; i++){
37692 if(i != dd.length-1) re += "|";
37694 this.ddMatch = new RegExp(re + ")");
37698 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
37700 * @cfg {String} format
37701 * The default date format string which can be overriden for localization support. The format must be
37702 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37706 * @cfg {String} altFormats
37707 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37708 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37710 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
37712 * @cfg {Array} disabledDays
37713 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37715 disabledDays : null,
37717 * @cfg {String} disabledDaysText
37718 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37720 disabledDaysText : "Disabled",
37722 * @cfg {Array} disabledDates
37723 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37724 * expression so they are very powerful. Some examples:
37726 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37727 * <li>["03/08", "09/16"] would disable those days for every year</li>
37728 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37729 * <li>["03/../2006"] would disable every day in March 2006</li>
37730 * <li>["^03"] would disable every day in every March</li>
37732 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37733 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37735 disabledDates : null,
37737 * @cfg {String} disabledDatesText
37738 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37740 disabledDatesText : "Disabled",
37742 * @cfg {Date/String} minValue
37743 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37744 * valid format (defaults to null).
37748 * @cfg {Date/String} maxValue
37749 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37750 * valid format (defaults to null).
37754 * @cfg {String} minText
37755 * The error text to display when the date in the cell is before minValue (defaults to
37756 * 'The date in this field must be after {minValue}').
37758 minText : "The date in this field must be equal to or after {0}",
37760 * @cfg {String} maxText
37761 * The error text to display when the date in the cell is after maxValue (defaults to
37762 * 'The date in this field must be before {maxValue}').
37764 maxText : "The date in this field must be equal to or before {0}",
37766 * @cfg {String} invalidText
37767 * The error text to display when the date in the field is invalid (defaults to
37768 * '{value} is not a valid date - it must be in the format {format}').
37770 invalidText : "{0} is not a valid date - it must be in the format {1}",
37772 * @cfg {String} triggerClass
37773 * An additional CSS class used to style the trigger button. The trigger will always get the
37774 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37775 * which displays a calendar icon).
37777 triggerClass : 'x-form-date-trigger',
37781 * @cfg {Boolean} useIso
37782 * if enabled, then the date field will use a hidden field to store the
37783 * real value as iso formated date. default (false)
37787 * @cfg {String/Object} autoCreate
37788 * A DomHelper element spec, or true for a default element spec (defaults to
37789 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37792 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37795 hiddenField: false,
37797 onRender : function(ct, position)
37799 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37801 //this.el.dom.removeAttribute('name');
37802 Roo.log("Changing name?");
37803 this.el.dom.setAttribute('name', this.name + '____hidden___' );
37804 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37806 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
37807 // prevent input submission
37808 this.hiddenName = this.name;
37815 validateValue : function(value)
37817 value = this.formatDate(value);
37818 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37819 Roo.log('super failed');
37822 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37825 var svalue = value;
37826 value = this.parseDate(value);
37828 Roo.log('parse date failed' + svalue);
37829 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37832 var time = value.getTime();
37833 if(this.minValue && time < this.minValue.getTime()){
37834 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37837 if(this.maxValue && time > this.maxValue.getTime()){
37838 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37841 if(this.disabledDays){
37842 var day = value.getDay();
37843 for(var i = 0; i < this.disabledDays.length; i++) {
37844 if(day === this.disabledDays[i]){
37845 this.markInvalid(this.disabledDaysText);
37850 var fvalue = this.formatDate(value);
37851 if(this.ddMatch && this.ddMatch.test(fvalue)){
37852 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37859 // Provides logic to override the default TriggerField.validateBlur which just returns true
37860 validateBlur : function(){
37861 return !this.menu || !this.menu.isVisible();
37864 getName: function()
37866 // returns hidden if it's set..
37867 if (!this.rendered) {return ''};
37868 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37873 * Returns the current date value of the date field.
37874 * @return {Date} The date value
37876 getValue : function(){
37878 return this.hiddenField ?
37879 this.hiddenField.value :
37880 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37884 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37885 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37886 * (the default format used is "m/d/y").
37889 //All of these calls set the same date value (May 4, 2006)
37891 //Pass a date object:
37892 var dt = new Date('5/4/06');
37893 dateField.setValue(dt);
37895 //Pass a date string (default format):
37896 dateField.setValue('5/4/06');
37898 //Pass a date string (custom format):
37899 dateField.format = 'Y-m-d';
37900 dateField.setValue('2006-5-4');
37902 * @param {String/Date} date The date or valid date string
37904 setValue : function(date){
37905 if (this.hiddenField) {
37906 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37908 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37909 // make sure the value field is always stored as a date..
37910 this.value = this.parseDate(date);
37916 parseDate : function(value){
37917 if(!value || value instanceof Date){
37920 var v = Date.parseDate(value, this.format);
37921 if (!v && this.useIso) {
37922 v = Date.parseDate(value, 'Y-m-d');
37924 if(!v && this.altFormats){
37925 if(!this.altFormatsArray){
37926 this.altFormatsArray = this.altFormats.split("|");
37928 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37929 v = Date.parseDate(value, this.altFormatsArray[i]);
37936 formatDate : function(date, fmt){
37937 return (!date || !(date instanceof Date)) ?
37938 date : date.dateFormat(fmt || this.format);
37943 select: function(m, d){
37946 this.fireEvent('select', this, d);
37948 show : function(){ // retain focus styling
37952 this.focus.defer(10, this);
37953 var ml = this.menuListeners;
37954 this.menu.un("select", ml.select, this);
37955 this.menu.un("show", ml.show, this);
37956 this.menu.un("hide", ml.hide, this);
37961 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37962 onTriggerClick : function(){
37966 if(this.menu == null){
37967 this.menu = new Roo.menu.DateMenu();
37969 Roo.apply(this.menu.picker, {
37970 showClear: this.allowBlank,
37971 minDate : this.minValue,
37972 maxDate : this.maxValue,
37973 disabledDatesRE : this.ddMatch,
37974 disabledDatesText : this.disabledDatesText,
37975 disabledDays : this.disabledDays,
37976 disabledDaysText : this.disabledDaysText,
37977 format : this.useIso ? 'Y-m-d' : this.format,
37978 minText : String.format(this.minText, this.formatDate(this.minValue)),
37979 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37981 this.menu.on(Roo.apply({}, this.menuListeners, {
37984 this.menu.picker.setValue(this.getValue() || new Date());
37985 this.menu.show(this.el, "tl-bl?");
37988 beforeBlur : function(){
37989 var v = this.parseDate(this.getRawValue());
37995 /** @cfg {Boolean} grow @hide */
37996 /** @cfg {Number} growMin @hide */
37997 /** @cfg {Number} growMax @hide */
38004 * Ext JS Library 1.1.1
38005 * Copyright(c) 2006-2007, Ext JS, LLC.
38007 * Originally Released Under LGPL - original licence link has changed is not relivant.
38010 * <script type="text/javascript">
38014 * @class Roo.form.MonthField
38015 * @extends Roo.form.TriggerField
38016 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38018 * Create a new MonthField
38019 * @param {Object} config
38021 Roo.form.MonthField = function(config){
38023 Roo.form.MonthField.superclass.constructor.call(this, config);
38029 * Fires when a date is selected
38030 * @param {Roo.form.MonthFieeld} combo This combo box
38031 * @param {Date} date The date selected
38038 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38039 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38040 this.ddMatch = null;
38041 if(this.disabledDates){
38042 var dd = this.disabledDates;
38044 for(var i = 0; i < dd.length; i++){
38046 if(i != dd.length-1) re += "|";
38048 this.ddMatch = new RegExp(re + ")");
38052 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38054 * @cfg {String} format
38055 * The default date format string which can be overriden for localization support. The format must be
38056 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38060 * @cfg {String} altFormats
38061 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38062 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38064 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38066 * @cfg {Array} disabledDays
38067 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38069 disabledDays : [0,1,2,3,4,5,6],
38071 * @cfg {String} disabledDaysText
38072 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38074 disabledDaysText : "Disabled",
38076 * @cfg {Array} disabledDates
38077 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38078 * expression so they are very powerful. Some examples:
38080 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38081 * <li>["03/08", "09/16"] would disable those days for every year</li>
38082 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38083 * <li>["03/../2006"] would disable every day in March 2006</li>
38084 * <li>["^03"] would disable every day in every March</li>
38086 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38087 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38089 disabledDates : null,
38091 * @cfg {String} disabledDatesText
38092 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38094 disabledDatesText : "Disabled",
38096 * @cfg {Date/String} minValue
38097 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38098 * valid format (defaults to null).
38102 * @cfg {Date/String} maxValue
38103 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38104 * valid format (defaults to null).
38108 * @cfg {String} minText
38109 * The error text to display when the date in the cell is before minValue (defaults to
38110 * 'The date in this field must be after {minValue}').
38112 minText : "The date in this field must be equal to or after {0}",
38114 * @cfg {String} maxTextf
38115 * The error text to display when the date in the cell is after maxValue (defaults to
38116 * 'The date in this field must be before {maxValue}').
38118 maxText : "The date in this field must be equal to or before {0}",
38120 * @cfg {String} invalidText
38121 * The error text to display when the date in the field is invalid (defaults to
38122 * '{value} is not a valid date - it must be in the format {format}').
38124 invalidText : "{0} is not a valid date - it must be in the format {1}",
38126 * @cfg {String} triggerClass
38127 * An additional CSS class used to style the trigger button. The trigger will always get the
38128 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38129 * which displays a calendar icon).
38131 triggerClass : 'x-form-date-trigger',
38135 * @cfg {Boolean} useIso
38136 * if enabled, then the date field will use a hidden field to store the
38137 * real value as iso formated date. default (true)
38141 * @cfg {String/Object} autoCreate
38142 * A DomHelper element spec, or true for a default element spec (defaults to
38143 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38146 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38149 hiddenField: false,
38151 hideMonthPicker : false,
38153 onRender : function(ct, position)
38155 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38157 this.el.dom.removeAttribute('name');
38158 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38160 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38161 // prevent input submission
38162 this.hiddenName = this.name;
38169 validateValue : function(value)
38171 value = this.formatDate(value);
38172 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38175 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38178 var svalue = value;
38179 value = this.parseDate(value);
38181 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38184 var time = value.getTime();
38185 if(this.minValue && time < this.minValue.getTime()){
38186 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38189 if(this.maxValue && time > this.maxValue.getTime()){
38190 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38193 /*if(this.disabledDays){
38194 var day = value.getDay();
38195 for(var i = 0; i < this.disabledDays.length; i++) {
38196 if(day === this.disabledDays[i]){
38197 this.markInvalid(this.disabledDaysText);
38203 var fvalue = this.formatDate(value);
38204 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38205 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38213 // Provides logic to override the default TriggerField.validateBlur which just returns true
38214 validateBlur : function(){
38215 return !this.menu || !this.menu.isVisible();
38219 * Returns the current date value of the date field.
38220 * @return {Date} The date value
38222 getValue : function(){
38226 return this.hiddenField ?
38227 this.hiddenField.value :
38228 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38232 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38233 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38234 * (the default format used is "m/d/y").
38237 //All of these calls set the same date value (May 4, 2006)
38239 //Pass a date object:
38240 var dt = new Date('5/4/06');
38241 monthField.setValue(dt);
38243 //Pass a date string (default format):
38244 monthField.setValue('5/4/06');
38246 //Pass a date string (custom format):
38247 monthField.format = 'Y-m-d';
38248 monthField.setValue('2006-5-4');
38250 * @param {String/Date} date The date or valid date string
38252 setValue : function(date){
38253 Roo.log('month setValue' + date);
38254 // can only be first of month..
38256 var val = this.parseDate(date);
38258 if (this.hiddenField) {
38259 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38261 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38262 this.value = this.parseDate(date);
38266 parseDate : function(value){
38267 if(!value || value instanceof Date){
38268 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38271 var v = Date.parseDate(value, this.format);
38272 if (!v && this.useIso) {
38273 v = Date.parseDate(value, 'Y-m-d');
38277 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38281 if(!v && this.altFormats){
38282 if(!this.altFormatsArray){
38283 this.altFormatsArray = this.altFormats.split("|");
38285 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38286 v = Date.parseDate(value, this.altFormatsArray[i]);
38293 formatDate : function(date, fmt){
38294 return (!date || !(date instanceof Date)) ?
38295 date : date.dateFormat(fmt || this.format);
38300 select: function(m, d){
38302 this.fireEvent('select', this, d);
38304 show : function(){ // retain focus styling
38308 this.focus.defer(10, this);
38309 var ml = this.menuListeners;
38310 this.menu.un("select", ml.select, this);
38311 this.menu.un("show", ml.show, this);
38312 this.menu.un("hide", ml.hide, this);
38316 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38317 onTriggerClick : function(){
38321 if(this.menu == null){
38322 this.menu = new Roo.menu.DateMenu();
38326 Roo.apply(this.menu.picker, {
38328 showClear: this.allowBlank,
38329 minDate : this.minValue,
38330 maxDate : this.maxValue,
38331 disabledDatesRE : this.ddMatch,
38332 disabledDatesText : this.disabledDatesText,
38334 format : this.useIso ? 'Y-m-d' : this.format,
38335 minText : String.format(this.minText, this.formatDate(this.minValue)),
38336 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38339 this.menu.on(Roo.apply({}, this.menuListeners, {
38347 // hide month picker get's called when we called by 'before hide';
38349 var ignorehide = true;
38350 p.hideMonthPicker = function(disableAnim){
38354 if(this.monthPicker){
38355 Roo.log("hideMonthPicker called");
38356 if(disableAnim === true){
38357 this.monthPicker.hide();
38359 this.monthPicker.slideOut('t', {duration:.2});
38360 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38361 p.fireEvent("select", this, this.value);
38367 Roo.log('picker set value');
38368 Roo.log(this.getValue());
38369 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
38370 m.show(this.el, 'tl-bl?');
38371 ignorehide = false;
38372 // this will trigger hideMonthPicker..
38375 // hidden the day picker
38376 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
38382 p.showMonthPicker.defer(100, p);
38388 beforeBlur : function(){
38389 var v = this.parseDate(this.getRawValue());
38395 /** @cfg {Boolean} grow @hide */
38396 /** @cfg {Number} growMin @hide */
38397 /** @cfg {Number} growMax @hide */
38404 * Ext JS Library 1.1.1
38405 * Copyright(c) 2006-2007, Ext JS, LLC.
38407 * Originally Released Under LGPL - original licence link has changed is not relivant.
38410 * <script type="text/javascript">
38415 * @class Roo.form.ComboBox
38416 * @extends Roo.form.TriggerField
38417 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
38419 * Create a new ComboBox.
38420 * @param {Object} config Configuration options
38422 Roo.form.ComboBox = function(config){
38423 Roo.form.ComboBox.superclass.constructor.call(this, config);
38427 * Fires when the dropdown list is expanded
38428 * @param {Roo.form.ComboBox} combo This combo box
38433 * Fires when the dropdown list is collapsed
38434 * @param {Roo.form.ComboBox} combo This combo box
38438 * @event beforeselect
38439 * Fires before a list item is selected. Return false to cancel the selection.
38440 * @param {Roo.form.ComboBox} combo This combo box
38441 * @param {Roo.data.Record} record The data record returned from the underlying store
38442 * @param {Number} index The index of the selected item in the dropdown list
38444 'beforeselect' : true,
38447 * Fires when a list item is selected
38448 * @param {Roo.form.ComboBox} combo This combo box
38449 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
38450 * @param {Number} index The index of the selected item in the dropdown list
38454 * @event beforequery
38455 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
38456 * The event object passed has these properties:
38457 * @param {Roo.form.ComboBox} combo This combo box
38458 * @param {String} query The query
38459 * @param {Boolean} forceAll true to force "all" query
38460 * @param {Boolean} cancel true to cancel the query
38461 * @param {Object} e The query event object
38463 'beforequery': true,
38466 * Fires when the 'add' icon is pressed (add a listener to enable add button)
38467 * @param {Roo.form.ComboBox} combo This combo box
38472 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
38473 * @param {Roo.form.ComboBox} combo This combo box
38474 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
38480 if(this.transform){
38481 this.allowDomMove = false;
38482 var s = Roo.getDom(this.transform);
38483 if(!this.hiddenName){
38484 this.hiddenName = s.name;
38487 this.mode = 'local';
38488 var d = [], opts = s.options;
38489 for(var i = 0, len = opts.length;i < len; i++){
38491 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
38493 this.value = value;
38495 d.push([value, o.text]);
38497 this.store = new Roo.data.SimpleStore({
38499 fields: ['value', 'text'],
38502 this.valueField = 'value';
38503 this.displayField = 'text';
38505 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
38506 if(!this.lazyRender){
38507 this.target = true;
38508 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
38509 s.parentNode.removeChild(s); // remove it
38510 this.render(this.el.parentNode);
38512 s.parentNode.removeChild(s); // remove it
38517 this.store = Roo.factory(this.store, Roo.data);
38520 this.selectedIndex = -1;
38521 if(this.mode == 'local'){
38522 if(config.queryDelay === undefined){
38523 this.queryDelay = 10;
38525 if(config.minChars === undefined){
38531 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
38533 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
38536 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
38537 * rendering into an Roo.Editor, defaults to false)
38540 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
38541 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
38544 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
38547 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
38548 * the dropdown list (defaults to undefined, with no header element)
38552 * @cfg {String/Roo.Template} tpl The template to use to render the output
38556 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
38558 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
38560 listWidth: undefined,
38562 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
38563 * mode = 'remote' or 'text' if mode = 'local')
38565 displayField: undefined,
38567 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
38568 * mode = 'remote' or 'value' if mode = 'local').
38569 * Note: use of a valueField requires the user make a selection
38570 * in order for a value to be mapped.
38572 valueField: undefined,
38576 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
38577 * field's data value (defaults to the underlying DOM element's name)
38579 hiddenName: undefined,
38581 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
38585 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
38587 selectedClass: 'x-combo-selected',
38589 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38590 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
38591 * which displays a downward arrow icon).
38593 triggerClass : 'x-form-arrow-trigger',
38595 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
38599 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
38600 * anchor positions (defaults to 'tl-bl')
38602 listAlign: 'tl-bl?',
38604 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
38608 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
38609 * query specified by the allQuery config option (defaults to 'query')
38611 triggerAction: 'query',
38613 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
38614 * (defaults to 4, does not apply if editable = false)
38618 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
38619 * delay (typeAheadDelay) if it matches a known value (defaults to false)
38623 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
38624 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
38628 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
38629 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
38633 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
38634 * when editable = true (defaults to false)
38636 selectOnFocus:false,
38638 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
38640 queryParam: 'query',
38642 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
38643 * when mode = 'remote' (defaults to 'Loading...')
38645 loadingText: 'Loading...',
38647 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
38651 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
38655 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
38656 * traditional select (defaults to true)
38660 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
38664 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
38668 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
38669 * listWidth has a higher value)
38673 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
38674 * allow the user to set arbitrary text into the field (defaults to false)
38676 forceSelection:false,
38678 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
38679 * if typeAhead = true (defaults to 250)
38681 typeAheadDelay : 250,
38683 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
38684 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
38686 valueNotFoundText : undefined,
38688 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
38690 blockFocus : false,
38693 * @cfg {Boolean} disableClear Disable showing of clear button.
38695 disableClear : false,
38697 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
38699 alwaysQuery : false,
38705 // element that contains real text value.. (when hidden is used..)
38708 onRender : function(ct, position){
38709 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
38710 if(this.hiddenName){
38711 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
38713 this.hiddenField.value =
38714 this.hiddenValue !== undefined ? this.hiddenValue :
38715 this.value !== undefined ? this.value : '';
38717 // prevent input submission
38718 this.el.dom.removeAttribute('name');
38723 this.el.dom.setAttribute('autocomplete', 'off');
38726 var cls = 'x-combo-list';
38728 this.list = new Roo.Layer({
38729 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
38732 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
38733 this.list.setWidth(lw);
38734 this.list.swallowEvent('mousewheel');
38735 this.assetHeight = 0;
38738 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
38739 this.assetHeight += this.header.getHeight();
38742 this.innerList = this.list.createChild({cls:cls+'-inner'});
38743 this.innerList.on('mouseover', this.onViewOver, this);
38744 this.innerList.on('mousemove', this.onViewMove, this);
38745 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38747 if(this.allowBlank && !this.pageSize && !this.disableClear){
38748 this.footer = this.list.createChild({cls:cls+'-ft'});
38749 this.pageTb = new Roo.Toolbar(this.footer);
38753 this.footer = this.list.createChild({cls:cls+'-ft'});
38754 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
38755 {pageSize: this.pageSize});
38759 if (this.pageTb && this.allowBlank && !this.disableClear) {
38761 this.pageTb.add(new Roo.Toolbar.Fill(), {
38762 cls: 'x-btn-icon x-btn-clear',
38764 handler: function()
38767 _this.clearValue();
38768 _this.onSelect(false, -1);
38773 this.assetHeight += this.footer.getHeight();
38778 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
38781 this.view = new Roo.View(this.innerList, this.tpl, {
38782 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38785 this.view.on('click', this.onViewClick, this);
38787 this.store.on('beforeload', this.onBeforeLoad, this);
38788 this.store.on('load', this.onLoad, this);
38789 this.store.on('loadexception', this.onLoadException, this);
38791 if(this.resizable){
38792 this.resizer = new Roo.Resizable(this.list, {
38793 pinned:true, handles:'se'
38795 this.resizer.on('resize', function(r, w, h){
38796 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
38797 this.listWidth = w;
38798 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
38799 this.restrictHeight();
38801 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
38803 if(!this.editable){
38804 this.editable = true;
38805 this.setEditable(false);
38809 if (typeof(this.events.add.listeners) != 'undefined') {
38811 this.addicon = this.wrap.createChild(
38812 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
38814 this.addicon.on('click', function(e) {
38815 this.fireEvent('add', this);
38818 if (typeof(this.events.edit.listeners) != 'undefined') {
38820 this.editicon = this.wrap.createChild(
38821 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
38822 if (this.addicon) {
38823 this.editicon.setStyle('margin-left', '40px');
38825 this.editicon.on('click', function(e) {
38827 // we fire even if inothing is selected..
38828 this.fireEvent('edit', this, this.lastData );
38838 initEvents : function(){
38839 Roo.form.ComboBox.superclass.initEvents.call(this);
38841 this.keyNav = new Roo.KeyNav(this.el, {
38842 "up" : function(e){
38843 this.inKeyMode = true;
38847 "down" : function(e){
38848 if(!this.isExpanded()){
38849 this.onTriggerClick();
38851 this.inKeyMode = true;
38856 "enter" : function(e){
38857 this.onViewClick();
38861 "esc" : function(e){
38865 "tab" : function(e){
38866 this.onViewClick(false);
38867 this.fireEvent("specialkey", this, e);
38873 doRelay : function(foo, bar, hname){
38874 if(hname == 'down' || this.scope.isExpanded()){
38875 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38882 this.queryDelay = Math.max(this.queryDelay || 10,
38883 this.mode == 'local' ? 10 : 250);
38884 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38885 if(this.typeAhead){
38886 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38888 if(this.editable !== false){
38889 this.el.on("keyup", this.onKeyUp, this);
38891 if(this.forceSelection){
38892 this.on('blur', this.doForce, this);
38896 onDestroy : function(){
38898 this.view.setStore(null);
38899 this.view.el.removeAllListeners();
38900 this.view.el.remove();
38901 this.view.purgeListeners();
38904 this.list.destroy();
38907 this.store.un('beforeload', this.onBeforeLoad, this);
38908 this.store.un('load', this.onLoad, this);
38909 this.store.un('loadexception', this.onLoadException, this);
38911 Roo.form.ComboBox.superclass.onDestroy.call(this);
38915 fireKey : function(e){
38916 if(e.isNavKeyPress() && !this.list.isVisible()){
38917 this.fireEvent("specialkey", this, e);
38922 onResize: function(w, h){
38923 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
38925 if(typeof w != 'number'){
38926 // we do not handle it!?!?
38929 var tw = this.trigger.getWidth();
38930 tw += this.addicon ? this.addicon.getWidth() : 0;
38931 tw += this.editicon ? this.editicon.getWidth() : 0;
38933 this.el.setWidth( this.adjustWidth('input', x));
38935 this.trigger.setStyle('left', x+'px');
38937 if(this.list && this.listWidth === undefined){
38938 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
38939 this.list.setWidth(lw);
38940 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38948 * Allow or prevent the user from directly editing the field text. If false is passed,
38949 * the user will only be able to select from the items defined in the dropdown list. This method
38950 * is the runtime equivalent of setting the 'editable' config option at config time.
38951 * @param {Boolean} value True to allow the user to directly edit the field text
38953 setEditable : function(value){
38954 if(value == this.editable){
38957 this.editable = value;
38959 this.el.dom.setAttribute('readOnly', true);
38960 this.el.on('mousedown', this.onTriggerClick, this);
38961 this.el.addClass('x-combo-noedit');
38963 this.el.dom.setAttribute('readOnly', false);
38964 this.el.un('mousedown', this.onTriggerClick, this);
38965 this.el.removeClass('x-combo-noedit');
38970 onBeforeLoad : function(){
38971 if(!this.hasFocus){
38974 this.innerList.update(this.loadingText ?
38975 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
38976 this.restrictHeight();
38977 this.selectedIndex = -1;
38981 onLoad : function(){
38982 if(!this.hasFocus){
38985 if(this.store.getCount() > 0){
38987 this.restrictHeight();
38988 if(this.lastQuery == this.allQuery){
38990 this.el.dom.select();
38992 if(!this.selectByValue(this.value, true)){
38993 this.select(0, true);
38997 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
38998 this.taTask.delay(this.typeAheadDelay);
39002 this.onEmptyResults();
39007 onLoadException : function()
39010 Roo.log(this.store.reader.jsonData);
39011 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39012 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39018 onTypeAhead : function(){
39019 if(this.store.getCount() > 0){
39020 var r = this.store.getAt(0);
39021 var newValue = r.data[this.displayField];
39022 var len = newValue.length;
39023 var selStart = this.getRawValue().length;
39024 if(selStart != len){
39025 this.setRawValue(newValue);
39026 this.selectText(selStart, newValue.length);
39032 onSelect : function(record, index){
39033 if(this.fireEvent('beforeselect', this, record, index) !== false){
39034 this.setFromData(index > -1 ? record.data : false);
39036 this.fireEvent('select', this, record, index);
39041 * Returns the currently selected field value or empty string if no value is set.
39042 * @return {String} value The selected value
39044 getValue : function(){
39045 if(this.valueField){
39046 return typeof this.value != 'undefined' ? this.value : '';
39048 return Roo.form.ComboBox.superclass.getValue.call(this);
39053 * Clears any text/value currently set in the field
39055 clearValue : function(){
39056 if(this.hiddenField){
39057 this.hiddenField.value = '';
39060 this.setRawValue('');
39061 this.lastSelectionText = '';
39066 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39067 * will be displayed in the field. If the value does not match the data value of an existing item,
39068 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39069 * Otherwise the field will be blank (although the value will still be set).
39070 * @param {String} value The value to match
39072 setValue : function(v){
39074 if(this.valueField){
39075 var r = this.findRecord(this.valueField, v);
39077 text = r.data[this.displayField];
39078 }else if(this.valueNotFoundText !== undefined){
39079 text = this.valueNotFoundText;
39082 this.lastSelectionText = text;
39083 if(this.hiddenField){
39084 this.hiddenField.value = v;
39086 Roo.form.ComboBox.superclass.setValue.call(this, text);
39090 * @property {Object} the last set data for the element
39095 * Sets the value of the field based on a object which is related to the record format for the store.
39096 * @param {Object} value the value to set as. or false on reset?
39098 setFromData : function(o){
39099 var dv = ''; // display value
39100 var vv = ''; // value value..
39102 if (this.displayField) {
39103 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39105 // this is an error condition!!!
39106 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39109 if(this.valueField){
39110 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39112 if(this.hiddenField){
39113 this.hiddenField.value = vv;
39115 this.lastSelectionText = dv;
39116 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39120 // no hidden field.. - we store the value in 'value', but still display
39121 // display field!!!!
39122 this.lastSelectionText = dv;
39123 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39129 reset : function(){
39130 // overridden so that last data is reset..
39131 this.setValue(this.originalValue);
39132 this.clearInvalid();
39133 this.lastData = false;
39135 this.view.clearSelections();
39139 findRecord : function(prop, value){
39141 if(this.store.getCount() > 0){
39142 this.store.each(function(r){
39143 if(r.data[prop] == value){
39153 getName: function()
39155 // returns hidden if it's set..
39156 if (!this.rendered) {return ''};
39157 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39161 onViewMove : function(e, t){
39162 this.inKeyMode = false;
39166 onViewOver : function(e, t){
39167 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39170 var item = this.view.findItemFromChild(t);
39172 var index = this.view.indexOf(item);
39173 this.select(index, false);
39178 onViewClick : function(doFocus)
39180 var index = this.view.getSelectedIndexes()[0];
39181 var r = this.store.getAt(index);
39183 this.onSelect(r, index);
39185 if(doFocus !== false && !this.blockFocus){
39191 restrictHeight : function(){
39192 this.innerList.dom.style.height = '';
39193 var inner = this.innerList.dom;
39194 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39195 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39196 this.list.beginUpdate();
39197 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39198 this.list.alignTo(this.el, this.listAlign);
39199 this.list.endUpdate();
39203 onEmptyResults : function(){
39208 * Returns true if the dropdown list is expanded, else false.
39210 isExpanded : function(){
39211 return this.list.isVisible();
39215 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39216 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39217 * @param {String} value The data value of the item to select
39218 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39219 * selected item if it is not currently in view (defaults to true)
39220 * @return {Boolean} True if the value matched an item in the list, else false
39222 selectByValue : function(v, scrollIntoView){
39223 if(v !== undefined && v !== null){
39224 var r = this.findRecord(this.valueField || this.displayField, v);
39226 this.select(this.store.indexOf(r), scrollIntoView);
39234 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39235 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39236 * @param {Number} index The zero-based index of the list item to select
39237 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39238 * selected item if it is not currently in view (defaults to true)
39240 select : function(index, scrollIntoView){
39241 this.selectedIndex = index;
39242 this.view.select(index);
39243 if(scrollIntoView !== false){
39244 var el = this.view.getNode(index);
39246 this.innerList.scrollChildIntoView(el, false);
39252 selectNext : function(){
39253 var ct = this.store.getCount();
39255 if(this.selectedIndex == -1){
39257 }else if(this.selectedIndex < ct-1){
39258 this.select(this.selectedIndex+1);
39264 selectPrev : function(){
39265 var ct = this.store.getCount();
39267 if(this.selectedIndex == -1){
39269 }else if(this.selectedIndex != 0){
39270 this.select(this.selectedIndex-1);
39276 onKeyUp : function(e){
39277 if(this.editable !== false && !e.isSpecialKey()){
39278 this.lastKey = e.getKey();
39279 this.dqTask.delay(this.queryDelay);
39284 validateBlur : function(){
39285 return !this.list || !this.list.isVisible();
39289 initQuery : function(){
39290 this.doQuery(this.getRawValue());
39294 doForce : function(){
39295 if(this.el.dom.value.length > 0){
39296 this.el.dom.value =
39297 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39303 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39304 * query allowing the query action to be canceled if needed.
39305 * @param {String} query The SQL query to execute
39306 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39307 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39308 * saved in the current store (defaults to false)
39310 doQuery : function(q, forceAll){
39311 if(q === undefined || q === null){
39316 forceAll: forceAll,
39320 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39324 forceAll = qe.forceAll;
39325 if(forceAll === true || (q.length >= this.minChars)){
39326 if(this.lastQuery != q || this.alwaysQuery){
39327 this.lastQuery = q;
39328 if(this.mode == 'local'){
39329 this.selectedIndex = -1;
39331 this.store.clearFilter();
39333 this.store.filter(this.displayField, q);
39337 this.store.baseParams[this.queryParam] = q;
39339 params: this.getParams(q)
39344 this.selectedIndex = -1;
39351 getParams : function(q){
39353 //p[this.queryParam] = q;
39356 p.limit = this.pageSize;
39362 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39364 collapse : function(){
39365 if(!this.isExpanded()){
39369 Roo.get(document).un('mousedown', this.collapseIf, this);
39370 Roo.get(document).un('mousewheel', this.collapseIf, this);
39371 if (!this.editable) {
39372 Roo.get(document).un('keydown', this.listKeyPress, this);
39374 this.fireEvent('collapse', this);
39378 collapseIf : function(e){
39379 if(!e.within(this.wrap) && !e.within(this.list)){
39385 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39387 expand : function(){
39388 if(this.isExpanded() || !this.hasFocus){
39391 this.list.alignTo(this.el, this.listAlign);
39393 Roo.get(document).on('mousedown', this.collapseIf, this);
39394 Roo.get(document).on('mousewheel', this.collapseIf, this);
39395 if (!this.editable) {
39396 Roo.get(document).on('keydown', this.listKeyPress, this);
39399 this.fireEvent('expand', this);
39403 // Implements the default empty TriggerField.onTriggerClick function
39404 onTriggerClick : function(){
39408 if(this.isExpanded()){
39410 if (!this.blockFocus) {
39415 this.hasFocus = true;
39416 if(this.triggerAction == 'all') {
39417 this.doQuery(this.allQuery, true);
39419 this.doQuery(this.getRawValue());
39421 if (!this.blockFocus) {
39426 listKeyPress : function(e)
39428 //Roo.log('listkeypress');
39429 // scroll to first matching element based on key pres..
39430 if (e.isSpecialKey()) {
39433 var k = String.fromCharCode(e.getKey()).toUpperCase();
39436 var csel = this.view.getSelectedNodes();
39437 var cselitem = false;
39439 var ix = this.view.indexOf(csel[0]);
39440 cselitem = this.store.getAt(ix);
39441 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
39447 this.store.each(function(v) {
39449 // start at existing selection.
39450 if (cselitem.id == v.id) {
39456 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
39457 match = this.store.indexOf(v);
39462 if (match === false) {
39463 return true; // no more action?
39466 this.view.select(match);
39467 var sn = Roo.get(this.view.getSelectedNodes()[0])
39468 sn.scrollIntoView(sn.dom.parentNode, false);
39472 * @cfg {Boolean} grow
39476 * @cfg {Number} growMin
39480 * @cfg {Number} growMax
39488 * Copyright(c) 2010-2012, Roo J Solutions Limited
39495 * @class Roo.form.ComboBoxArray
39496 * @extends Roo.form.TextField
39497 * A facebook style adder... for lists of email / people / countries etc...
39498 * pick multiple items from a combo box, and shows each one.
39500 * Fred [x] Brian [x] [Pick another |v]
39503 * For this to work: it needs various extra information
39504 * - normal combo problay has
39506 * + displayField, valueField
39508 * For our purpose...
39511 * If we change from 'extends' to wrapping...
39518 * Create a new ComboBoxArray.
39519 * @param {Object} config Configuration options
39523 Roo.form.ComboBoxArray = function(config)
39526 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
39528 this.items = new Roo.util.MixedCollection(false);
39530 // construct the child combo...
39540 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
39543 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
39548 // behavies liek a hiddne field
39549 inputType: 'hidden',
39551 * @cfg {Number} width The width of the box that displays the selected element
39558 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
39562 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
39564 hiddenName : false,
39567 // private the array of items that are displayed..
39569 // private - the hidden field el.
39571 // private - the filed el..
39574 //validateValue : function() { return true; }, // all values are ok!
39575 //onAddClick: function() { },
39577 onRender : function(ct, position)
39580 // create the standard hidden element
39581 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
39584 // give fake names to child combo;
39585 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
39586 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
39588 this.combo = Roo.factory(this.combo, Roo.form);
39589 this.combo.onRender(ct, position);
39590 if (typeof(this.combo.width) != 'undefined') {
39591 this.combo.onResize(this.combo.width,0);
39594 this.combo.initEvents();
39596 // assigned so form know we need to do this..
39597 this.store = this.combo.store;
39598 this.valueField = this.combo.valueField;
39599 this.displayField = this.combo.displayField ;
39602 this.combo.wrap.addClass('x-cbarray-grp');
39604 var cbwrap = this.combo.wrap.createChild(
39605 {tag: 'div', cls: 'x-cbarray-cb'},
39610 this.hiddenEl = this.combo.wrap.createChild({
39611 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
39613 this.el = this.combo.wrap.createChild({
39614 tag: 'input', type:'hidden' , name: this.name, value : ''
39616 // this.el.dom.removeAttribute("name");
39619 this.outerWrap = this.combo.wrap;
39620 this.wrap = cbwrap;
39622 this.outerWrap.setWidth(this.width);
39623 this.outerWrap.dom.removeChild(this.el.dom);
39625 this.wrap.dom.appendChild(this.el.dom);
39626 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
39627 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
39629 this.combo.trigger.setStyle('position','relative');
39630 this.combo.trigger.setStyle('left', '0px');
39631 this.combo.trigger.setStyle('top', '2px');
39633 this.combo.el.setStyle('vertical-align', 'text-bottom');
39635 //this.trigger.setStyle('vertical-align', 'top');
39637 // this should use the code from combo really... on('add' ....)
39641 this.adder = this.outerWrap.createChild(
39642 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
39644 this.adder.on('click', function(e) {
39645 _t.fireEvent('adderclick', this, e);
39649 //this.adder.on('click', this.onAddClick, _t);
39652 this.combo.on('select', function(cb, rec, ix) {
39653 this.addItem(rec.data);
39656 cb.el.dom.value = '';
39657 //cb.lastData = rec.data;
39666 getName: function()
39668 // returns hidden if it's set..
39669 if (!this.rendered) {return ''};
39670 return this.hiddenName ? this.hiddenName : this.name;
39675 onResize: function(w, h){
39678 // not sure if this is needed..
39679 //this.combo.onResize(w,h);
39681 if(typeof w != 'number'){
39682 // we do not handle it!?!?
39685 var tw = this.combo.trigger.getWidth();
39686 tw += this.addicon ? this.addicon.getWidth() : 0;
39687 tw += this.editicon ? this.editicon.getWidth() : 0;
39689 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
39691 this.combo.trigger.setStyle('left', '0px');
39693 if(this.list && this.listWidth === undefined){
39694 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
39695 this.list.setWidth(lw);
39696 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39703 addItem: function(rec)
39705 var valueField = this.combo.valueField;
39706 var displayField = this.combo.displayField;
39707 if (this.items.indexOfKey(rec[valueField]) > -1) {
39708 //console.log("GOT " + rec.data.id);
39712 var x = new Roo.form.ComboBoxArray.Item({
39713 //id : rec[this.idField],
39715 displayField : displayField ,
39716 tipField : displayField ,
39720 this.items.add(rec[valueField],x);
39721 // add it before the element..
39722 this.updateHiddenEl();
39723 x.render(this.outerWrap, this.wrap.dom);
39724 // add the image handler..
39727 updateHiddenEl : function()
39730 if (!this.hiddenEl) {
39734 var idField = this.combo.valueField;
39736 this.items.each(function(f) {
39737 ar.push(f.data[idField]);
39740 this.hiddenEl.dom.value = ar.join(',');
39746 //Roo.form.ComboBoxArray.superclass.reset.call(this);
39747 this.items.each(function(f) {
39750 this.el.dom.value = '';
39751 if (this.hiddenEl) {
39752 this.hiddenEl.dom.value = '';
39756 getValue: function()
39758 return this.hiddenEl ? this.hiddenEl.dom.value : '';
39760 setValue: function(v) // not a valid action - must use addItems..
39767 if (this.store.isLocal && (typeof(v) == 'string')) {
39768 // then we can use the store to find the values..
39769 // comma seperated at present.. this needs to allow JSON based encoding..
39770 this.hiddenEl.value = v;
39772 Roo.each(v.split(','), function(k) {
39773 Roo.log("CHECK " + this.valueField + ',' + k);
39774 var li = this.store.query(this.valueField, k);
39779 add[this.valueField] = k;
39780 add[this.displayField] = li.item(0).data[this.displayField];
39786 if (typeof(v) == 'object') {
39787 // then let's assume it's an array of objects..
39788 Roo.each(v, function(l) {
39796 setFromData: function(v)
39798 // this recieves an object, if setValues is called.
39800 this.el.dom.value = v[this.displayField];
39801 this.hiddenEl.dom.value = v[this.valueField];
39802 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
39805 var kv = v[this.valueField];
39806 var dv = v[this.displayField];
39807 kv = typeof(kv) != 'string' ? '' : kv;
39808 dv = typeof(dv) != 'string' ? '' : dv;
39811 var keys = kv.split(',');
39812 var display = dv.split(',');
39813 for (var i = 0 ; i < keys.length; i++) {
39816 add[this.valueField] = keys[i];
39817 add[this.displayField] = display[i];
39825 validateValue : function(value){
39826 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
39835 * @class Roo.form.ComboBoxArray.Item
39836 * @extends Roo.BoxComponent
39837 * A selected item in the list
39838 * Fred [x] Brian [x] [Pick another |v]
39841 * Create a new item.
39842 * @param {Object} config Configuration options
39845 Roo.form.ComboBoxArray.Item = function(config) {
39846 config.id = Roo.id();
39847 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
39850 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
39853 displayField : false,
39857 defaultAutoCreate : {
39859 cls: 'x-cbarray-item',
39866 src : Roo.BLANK_IMAGE_URL ,
39874 onRender : function(ct, position)
39876 Roo.form.Field.superclass.onRender.call(this, ct, position);
39879 var cfg = this.getAutoCreate();
39880 this.el = ct.createChild(cfg, position);
39883 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
39885 this.el.child('div').dom.innerHTML = this.cb.renderer ?
39886 this.cb.renderer(this.data) :
39887 String.format('{0}',this.data[this.displayField]);
39890 this.el.child('div').dom.setAttribute('qtip',
39891 String.format('{0}',this.data[this.tipField])
39894 this.el.child('img').on('click', this.remove, this);
39898 remove : function()
39901 this.cb.items.remove(this);
39902 this.el.child('img').un('click', this.remove, this);
39904 this.cb.updateHiddenEl();
39910 * Ext JS Library 1.1.1
39911 * Copyright(c) 2006-2007, Ext JS, LLC.
39913 * Originally Released Under LGPL - original licence link has changed is not relivant.
39916 * <script type="text/javascript">
39919 * @class Roo.form.Checkbox
39920 * @extends Roo.form.Field
39921 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
39923 * Creates a new Checkbox
39924 * @param {Object} config Configuration options
39926 Roo.form.Checkbox = function(config){
39927 Roo.form.Checkbox.superclass.constructor.call(this, config);
39931 * Fires when the checkbox is checked or unchecked.
39932 * @param {Roo.form.Checkbox} this This checkbox
39933 * @param {Boolean} checked The new checked value
39939 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
39941 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
39943 focusClass : undefined,
39945 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
39947 fieldClass: "x-form-field",
39949 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
39953 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39954 * {tag: "input", type: "checkbox", autocomplete: "off"})
39956 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
39958 * @cfg {String} boxLabel The text that appears beside the checkbox
39962 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
39966 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
39968 valueOff: '0', // value when not checked..
39970 actionMode : 'viewEl',
39973 itemCls : 'x-menu-check-item x-form-item',
39974 groupClass : 'x-menu-group-item',
39975 inputType : 'hidden',
39978 inSetChecked: false, // check that we are not calling self...
39980 inputElement: false, // real input element?
39981 basedOn: false, // ????
39983 isFormField: true, // not sure where this is needed!!!!
39985 onResize : function(){
39986 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
39987 if(!this.boxLabel){
39988 this.el.alignTo(this.wrap, 'c-c');
39992 initEvents : function(){
39993 Roo.form.Checkbox.superclass.initEvents.call(this);
39994 this.el.on("click", this.onClick, this);
39995 this.el.on("change", this.onClick, this);
39999 getResizeEl : function(){
40003 getPositionEl : function(){
40008 onRender : function(ct, position){
40009 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40011 if(this.inputValue !== undefined){
40012 this.el.dom.value = this.inputValue;
40015 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40016 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40017 var viewEl = this.wrap.createChild({
40018 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40019 this.viewEl = viewEl;
40020 this.wrap.on('click', this.onClick, this);
40022 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40023 this.el.on('propertychange', this.setFromHidden, this); //ie
40028 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40029 // viewEl.on('click', this.onClick, this);
40031 //if(this.checked){
40032 this.setChecked(this.checked);
40034 //this.checked = this.el.dom;
40040 initValue : Roo.emptyFn,
40043 * Returns the checked state of the checkbox.
40044 * @return {Boolean} True if checked, else false
40046 getValue : function(){
40048 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40050 return this.valueOff;
40055 onClick : function(){
40056 this.setChecked(!this.checked);
40058 //if(this.el.dom.checked != this.checked){
40059 // this.setValue(this.el.dom.checked);
40064 * Sets the checked state of the checkbox.
40065 * On is always based on a string comparison between inputValue and the param.
40066 * @param {Boolean/String} value - the value to set
40067 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40069 setValue : function(v,suppressEvent){
40072 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40073 //if(this.el && this.el.dom){
40074 // this.el.dom.checked = this.checked;
40075 // this.el.dom.defaultChecked = this.checked;
40077 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40078 //this.fireEvent("check", this, this.checked);
40081 setChecked : function(state,suppressEvent)
40083 if (this.inSetChecked) {
40084 this.checked = state;
40090 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40092 this.checked = state;
40093 if(suppressEvent !== true){
40094 this.fireEvent('check', this, state);
40096 this.inSetChecked = true;
40097 this.el.dom.value = state ? this.inputValue : this.valueOff;
40098 this.inSetChecked = false;
40101 // handle setting of hidden value by some other method!!?!?
40102 setFromHidden: function()
40107 //console.log("SET FROM HIDDEN");
40108 //alert('setFrom hidden');
40109 this.setValue(this.el.dom.value);
40112 onDestroy : function()
40115 Roo.get(this.viewEl).remove();
40118 Roo.form.Checkbox.superclass.onDestroy.call(this);
40123 * Ext JS Library 1.1.1
40124 * Copyright(c) 2006-2007, Ext JS, LLC.
40126 * Originally Released Under LGPL - original licence link has changed is not relivant.
40129 * <script type="text/javascript">
40133 * @class Roo.form.Radio
40134 * @extends Roo.form.Checkbox
40135 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40136 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40138 * Creates a new Radio
40139 * @param {Object} config Configuration options
40141 Roo.form.Radio = function(){
40142 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40144 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40145 inputType: 'radio',
40148 * If this radio is part of a group, it will return the selected value
40151 getGroupValue : function(){
40152 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40156 onRender : function(ct, position){
40157 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40159 if(this.inputValue !== undefined){
40160 this.el.dom.value = this.inputValue;
40163 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40164 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40165 //var viewEl = this.wrap.createChild({
40166 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40167 //this.viewEl = viewEl;
40168 //this.wrap.on('click', this.onClick, this);
40170 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40171 //this.el.on('propertychange', this.setFromHidden, this); //ie
40176 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40177 // viewEl.on('click', this.onClick, this);
40180 this.el.dom.checked = 'checked' ;
40186 });//<script type="text/javascript">
40189 * Ext JS Library 1.1.1
40190 * Copyright(c) 2006-2007, Ext JS, LLC.
40191 * licensing@extjs.com
40193 * http://www.extjs.com/license
40199 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
40200 * - IE ? - no idea how much works there.
40208 * @class Ext.form.HtmlEditor
40209 * @extends Ext.form.Field
40210 * Provides a lightweight HTML Editor component.
40212 * This has been tested on Fireforx / Chrome.. IE may not be so great..
40214 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
40215 * supported by this editor.</b><br/><br/>
40216 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
40217 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40219 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
40221 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
40225 * @cfg {String} createLinkText The default text for the create link prompt
40227 createLinkText : 'Please enter the URL for the link:',
40229 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
40231 defaultLinkValue : 'http:/'+'/',
40234 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40239 * @cfg {Number} height (in pixels)
40243 * @cfg {Number} width (in pixels)
40248 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40251 stylesheets: false,
40256 // private properties
40257 validationEvent : false,
40259 initialized : false,
40261 sourceEditMode : false,
40262 onFocus : Roo.emptyFn,
40264 hideMode:'offsets',
40266 defaultAutoCreate : { // modified by initCompnoent..
40268 style:"width:500px;height:300px;",
40269 autocomplete: "off"
40273 initComponent : function(){
40276 * @event initialize
40277 * Fires when the editor is fully initialized (including the iframe)
40278 * @param {HtmlEditor} this
40283 * Fires when the editor is first receives the focus. Any insertion must wait
40284 * until after this event.
40285 * @param {HtmlEditor} this
40289 * @event beforesync
40290 * Fires before the textarea is updated with content from the editor iframe. Return false
40291 * to cancel the sync.
40292 * @param {HtmlEditor} this
40293 * @param {String} html
40297 * @event beforepush
40298 * Fires before the iframe editor is updated with content from the textarea. Return false
40299 * to cancel the push.
40300 * @param {HtmlEditor} this
40301 * @param {String} html
40306 * Fires when the textarea is updated with content from the editor iframe.
40307 * @param {HtmlEditor} this
40308 * @param {String} html
40313 * Fires when the iframe editor is updated with content from the textarea.
40314 * @param {HtmlEditor} this
40315 * @param {String} html
40319 * @event editmodechange
40320 * Fires when the editor switches edit modes
40321 * @param {HtmlEditor} this
40322 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
40324 editmodechange: true,
40326 * @event editorevent
40327 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40328 * @param {HtmlEditor} this
40332 this.defaultAutoCreate = {
40334 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
40335 autocomplete: "off"
40340 * Protected method that will not generally be called directly. It
40341 * is called when the editor creates its toolbar. Override this method if you need to
40342 * add custom toolbar buttons.
40343 * @param {HtmlEditor} editor
40345 createToolbar : function(editor){
40346 if (!editor.toolbars || !editor.toolbars.length) {
40347 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
40350 for (var i =0 ; i < editor.toolbars.length;i++) {
40351 editor.toolbars[i] = Roo.factory(
40352 typeof(editor.toolbars[i]) == 'string' ?
40353 { xtype: editor.toolbars[i]} : editor.toolbars[i],
40354 Roo.form.HtmlEditor);
40355 editor.toolbars[i].init(editor);
40362 * Protected method that will not generally be called directly. It
40363 * is called when the editor initializes the iframe with HTML contents. Override this method if you
40364 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
40366 getDocMarkup : function(){
40369 if (this.stylesheets === false) {
40371 Roo.get(document.head).select('style').each(function(node) {
40372 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40375 Roo.get(document.head).select('link').each(function(node) {
40376 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40379 } else if (!this.stylesheets.length) {
40381 st = '<style type="text/css">' +
40382 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40385 Roo.each(this.stylesheets, function(s) {
40386 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
40391 st += '<style type="text/css">' +
40392 'IMG { cursor: pointer } ' +
40396 return '<html><head>' + st +
40397 //<style type="text/css">' +
40398 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40400 ' </head><body class="roo-htmleditor-body"></body></html>';
40404 onRender : function(ct, position)
40407 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
40408 this.el.dom.style.border = '0 none';
40409 this.el.dom.setAttribute('tabIndex', -1);
40410 this.el.addClass('x-hidden');
40411 if(Roo.isIE){ // fix IE 1px bogus margin
40412 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
40414 this.wrap = this.el.wrap({
40415 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
40418 if (this.resizable) {
40419 this.resizeEl = new Roo.Resizable(this.wrap, {
40423 minHeight : this.height,
40424 height: this.height,
40425 handles : this.resizable,
40428 resize : function(r, w, h) {
40429 _t.onResize(w,h); // -something
40436 this.frameId = Roo.id();
40438 this.createToolbar(this);
40442 var iframe = this.wrap.createChild({
40445 name: this.frameId,
40446 frameBorder : 'no',
40447 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
40451 // console.log(iframe);
40452 //this.wrap.dom.appendChild(iframe);
40454 this.iframe = iframe.dom;
40456 this.assignDocWin();
40458 this.doc.designMode = 'on';
40461 this.doc.write(this.getDocMarkup());
40465 var task = { // must defer to wait for browser to be ready
40467 //console.log("run task?" + this.doc.readyState);
40468 this.assignDocWin();
40469 if(this.doc.body || this.doc.readyState == 'complete'){
40471 this.doc.designMode="on";
40475 Roo.TaskMgr.stop(task);
40476 this.initEditor.defer(10, this);
40483 Roo.TaskMgr.start(task);
40486 this.setSize(this.wrap.getSize());
40488 if (this.resizeEl) {
40489 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
40490 // should trigger onReize..
40495 onResize : function(w, h)
40497 //Roo.log('resize: ' +w + ',' + h );
40498 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
40499 if(this.el && this.iframe){
40500 if(typeof w == 'number'){
40501 var aw = w - this.wrap.getFrameWidth('lr');
40502 this.el.setWidth(this.adjustWidth('textarea', aw));
40503 this.iframe.style.width = aw + 'px';
40505 if(typeof h == 'number'){
40507 for (var i =0; i < this.toolbars.length;i++) {
40508 // fixme - ask toolbars for heights?
40509 tbh += this.toolbars[i].tb.el.getHeight();
40510 if (this.toolbars[i].footer) {
40511 tbh += this.toolbars[i].footer.el.getHeight();
40518 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
40519 ah -= 5; // knock a few pixes off for look..
40520 this.el.setHeight(this.adjustWidth('textarea', ah));
40521 this.iframe.style.height = ah + 'px';
40523 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
40530 * Toggles the editor between standard and source edit mode.
40531 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
40533 toggleSourceEdit : function(sourceEditMode){
40535 this.sourceEditMode = sourceEditMode === true;
40537 if(this.sourceEditMode){
40539 // Roo.log(this.syncValue());
40541 this.iframe.className = 'x-hidden';
40542 this.el.removeClass('x-hidden');
40543 this.el.dom.removeAttribute('tabIndex');
40547 // Roo.log(this.pushValue());
40549 this.iframe.className = '';
40550 this.el.addClass('x-hidden');
40551 this.el.dom.setAttribute('tabIndex', -1);
40554 this.setSize(this.wrap.getSize());
40555 this.fireEvent('editmodechange', this, this.sourceEditMode);
40558 // private used internally
40559 createLink : function(){
40560 var url = prompt(this.createLinkText, this.defaultLinkValue);
40561 if(url && url != 'http:/'+'/'){
40562 this.relayCmd('createlink', url);
40566 // private (for BoxComponent)
40567 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40569 // private (for BoxComponent)
40570 getResizeEl : function(){
40574 // private (for BoxComponent)
40575 getPositionEl : function(){
40580 initEvents : function(){
40581 this.originalValue = this.getValue();
40585 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40588 markInvalid : Roo.emptyFn,
40590 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40593 clearInvalid : Roo.emptyFn,
40595 setValue : function(v){
40596 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
40601 * Protected method that will not generally be called directly. If you need/want
40602 * custom HTML cleanup, this is the method you should override.
40603 * @param {String} html The HTML to be cleaned
40604 * return {String} The cleaned HTML
40606 cleanHtml : function(html){
40607 html = String(html);
40608 if(html.length > 5){
40609 if(Roo.isSafari){ // strip safari nonsense
40610 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
40613 if(html == ' '){
40620 * Protected method that will not generally be called directly. Syncs the contents
40621 * of the editor iframe with the textarea.
40623 syncValue : function(){
40624 if(this.initialized){
40625 var bd = (this.doc.body || this.doc.documentElement);
40626 //this.cleanUpPaste(); -- this is done else where and causes havoc..
40627 var html = bd.innerHTML;
40629 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
40630 var m = bs.match(/text-align:(.*?);/i);
40632 html = '<div style="'+m[0]+'">' + html + '</div>';
40635 html = this.cleanHtml(html);
40636 // fix up the special chars.. normaly like back quotes in word...
40637 // however we do not want to do this with chinese..
40638 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
40639 var cc = b.charCodeAt();
40641 (cc >= 0x4E00 && cc < 0xA000 ) ||
40642 (cc >= 0x3400 && cc < 0x4E00 ) ||
40643 (cc >= 0xf900 && cc < 0xfb00 )
40649 if(this.fireEvent('beforesync', this, html) !== false){
40650 this.el.dom.value = html;
40651 this.fireEvent('sync', this, html);
40657 * Protected method that will not generally be called directly. Pushes the value of the textarea
40658 * into the iframe editor.
40660 pushValue : function(){
40661 if(this.initialized){
40662 var v = this.el.dom.value;
40668 if(this.fireEvent('beforepush', this, v) !== false){
40669 var d = (this.doc.body || this.doc.documentElement);
40671 this.cleanUpPaste();
40672 this.el.dom.value = d.innerHTML;
40673 this.fireEvent('push', this, v);
40679 deferFocus : function(){
40680 this.focus.defer(10, this);
40684 focus : function(){
40685 if(this.win && !this.sourceEditMode){
40692 assignDocWin: function()
40694 var iframe = this.iframe;
40697 this.doc = iframe.contentWindow.document;
40698 this.win = iframe.contentWindow;
40700 if (!Roo.get(this.frameId)) {
40703 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
40704 this.win = Roo.get(this.frameId).dom.contentWindow;
40709 initEditor : function(){
40710 //console.log("INIT EDITOR");
40711 this.assignDocWin();
40715 this.doc.designMode="on";
40717 this.doc.write(this.getDocMarkup());
40720 var dbody = (this.doc.body || this.doc.documentElement);
40721 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
40722 // this copies styles from the containing element into thsi one..
40723 // not sure why we need all of this..
40724 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
40725 ss['background-attachment'] = 'fixed'; // w3c
40726 dbody.bgProperties = 'fixed'; // ie
40727 Roo.DomHelper.applyStyles(dbody, ss);
40728 Roo.EventManager.on(this.doc, {
40729 //'mousedown': this.onEditorEvent,
40730 'mouseup': this.onEditorEvent,
40731 'dblclick': this.onEditorEvent,
40732 'click': this.onEditorEvent,
40733 'keyup': this.onEditorEvent,
40738 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
40740 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
40741 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
40743 this.initialized = true;
40745 this.fireEvent('initialize', this);
40750 onDestroy : function(){
40756 for (var i =0; i < this.toolbars.length;i++) {
40757 // fixme - ask toolbars for heights?
40758 this.toolbars[i].onDestroy();
40761 this.wrap.dom.innerHTML = '';
40762 this.wrap.remove();
40767 onFirstFocus : function(){
40769 this.assignDocWin();
40772 this.activated = true;
40773 for (var i =0; i < this.toolbars.length;i++) {
40774 this.toolbars[i].onFirstFocus();
40777 if(Roo.isGecko){ // prevent silly gecko errors
40779 var s = this.win.getSelection();
40780 if(!s.focusNode || s.focusNode.nodeType != 3){
40781 var r = s.getRangeAt(0);
40782 r.selectNodeContents((this.doc.body || this.doc.documentElement));
40787 this.execCmd('useCSS', true);
40788 this.execCmd('styleWithCSS', false);
40791 this.fireEvent('activate', this);
40795 adjustFont: function(btn){
40796 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
40797 //if(Roo.isSafari){ // safari
40800 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
40801 if(Roo.isSafari){ // safari
40802 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
40803 v = (v < 10) ? 10 : v;
40804 v = (v > 48) ? 48 : v;
40805 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
40810 v = Math.max(1, v+adjust);
40812 this.execCmd('FontSize', v );
40815 onEditorEvent : function(e){
40816 this.fireEvent('editorevent', this, e);
40817 // this.updateToolbar();
40818 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
40821 insertTag : function(tg)
40823 // could be a bit smarter... -> wrap the current selected tRoo..
40824 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
40826 range = this.createRange(this.getSelection());
40827 var wrappingNode = this.doc.createElement(tg.toLowerCase());
40828 wrappingNode.appendChild(range.extractContents());
40829 range.insertNode(wrappingNode);
40836 this.execCmd("formatblock", tg);
40840 insertText : function(txt)
40844 var range = this.createRange();
40845 range.deleteContents();
40846 //alert(Sender.getAttribute('label'));
40848 range.insertNode(this.doc.createTextNode(txt));
40852 relayBtnCmd : function(btn){
40853 this.relayCmd(btn.cmd);
40857 * Executes a Midas editor command on the editor document and performs necessary focus and
40858 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
40859 * @param {String} cmd The Midas command
40860 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40862 relayCmd : function(cmd, value){
40864 this.execCmd(cmd, value);
40865 this.fireEvent('editorevent', this);
40866 //this.updateToolbar();
40871 * Executes a Midas editor command directly on the editor document.
40872 * For visual commands, you should use {@link #relayCmd} instead.
40873 * <b>This should only be called after the editor is initialized.</b>
40874 * @param {String} cmd The Midas command
40875 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40877 execCmd : function(cmd, value){
40878 this.doc.execCommand(cmd, false, value === undefined ? null : value);
40885 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
40887 * @param {String} text | dom node..
40889 insertAtCursor : function(text)
40894 if(!this.activated){
40900 var r = this.doc.selection.createRange();
40911 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
40915 // from jquery ui (MIT licenced)
40917 var win = this.win;
40919 if (win.getSelection && win.getSelection().getRangeAt) {
40920 range = win.getSelection().getRangeAt(0);
40921 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
40922 range.insertNode(node);
40923 } else if (win.document.selection && win.document.selection.createRange) {
40924 // no firefox support
40925 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40926 win.document.selection.createRange().pasteHTML(txt);
40928 // no firefox support
40929 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40930 this.execCmd('InsertHTML', txt);
40939 mozKeyPress : function(e){
40941 var c = e.getCharCode(), cmd;
40944 c = String.fromCharCode(c).toLowerCase();
40958 this.cleanUpPaste.defer(100, this);
40966 e.preventDefault();
40974 fixKeys : function(){ // load time branching for fastest keydown performance
40976 return function(e){
40977 var k = e.getKey(), r;
40980 r = this.doc.selection.createRange();
40983 r.pasteHTML('    ');
40990 r = this.doc.selection.createRange();
40992 var target = r.parentElement();
40993 if(!target || target.tagName.toLowerCase() != 'li'){
40995 r.pasteHTML('<br />');
41001 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41002 this.cleanUpPaste.defer(100, this);
41008 }else if(Roo.isOpera){
41009 return function(e){
41010 var k = e.getKey();
41014 this.execCmd('InsertHTML','    ');
41017 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41018 this.cleanUpPaste.defer(100, this);
41023 }else if(Roo.isSafari){
41024 return function(e){
41025 var k = e.getKey();
41029 this.execCmd('InsertText','\t');
41033 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41034 this.cleanUpPaste.defer(100, this);
41042 getAllAncestors: function()
41044 var p = this.getSelectedNode();
41047 a.push(p); // push blank onto stack..
41048 p = this.getParentElement();
41052 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41056 a.push(this.doc.body);
41060 lastSelNode : false,
41063 getSelection : function()
41065 this.assignDocWin();
41066 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41069 getSelectedNode: function()
41071 // this may only work on Gecko!!!
41073 // should we cache this!!!!
41078 var range = this.createRange(this.getSelection()).cloneRange();
41081 var parent = range.parentElement();
41083 var testRange = range.duplicate();
41084 testRange.moveToElementText(parent);
41085 if (testRange.inRange(range)) {
41088 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41091 parent = parent.parentElement;
41096 // is ancestor a text element.
41097 var ac = range.commonAncestorContainer;
41098 if (ac.nodeType == 3) {
41099 ac = ac.parentNode;
41102 var ar = ac.childNodes;
41105 var other_nodes = [];
41106 var has_other_nodes = false;
41107 for (var i=0;i<ar.length;i++) {
41108 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41111 // fullly contained node.
41113 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41118 // probably selected..
41119 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41120 other_nodes.push(ar[i]);
41124 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41129 has_other_nodes = true;
41131 if (!nodes.length && other_nodes.length) {
41132 nodes= other_nodes;
41134 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41140 createRange: function(sel)
41142 // this has strange effects when using with
41143 // top toolbar - not sure if it's a great idea.
41144 //this.editor.contentWindow.focus();
41145 if (typeof sel != "undefined") {
41147 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41149 return this.doc.createRange();
41152 return this.doc.createRange();
41155 getParentElement: function()
41158 this.assignDocWin();
41159 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41161 var range = this.createRange(sel);
41164 var p = range.commonAncestorContainer;
41165 while (p.nodeType == 3) { // text node
41176 * Range intersection.. the hard stuff...
41180 * [ -- selected range --- ]
41184 * if end is before start or hits it. fail.
41185 * if start is after end or hits it fail.
41187 * if either hits (but other is outside. - then it's not
41193 // @see http://www.thismuchiknow.co.uk/?p=64.
41194 rangeIntersectsNode : function(range, node)
41196 var nodeRange = node.ownerDocument.createRange();
41198 nodeRange.selectNode(node);
41200 nodeRange.selectNodeContents(node);
41203 var rangeStartRange = range.cloneRange();
41204 rangeStartRange.collapse(true);
41206 var rangeEndRange = range.cloneRange();
41207 rangeEndRange.collapse(false);
41209 var nodeStartRange = nodeRange.cloneRange();
41210 nodeStartRange.collapse(true);
41212 var nodeEndRange = nodeRange.cloneRange();
41213 nodeEndRange.collapse(false);
41215 return rangeStartRange.compareBoundaryPoints(
41216 Range.START_TO_START, nodeEndRange) == -1 &&
41217 rangeEndRange.compareBoundaryPoints(
41218 Range.START_TO_START, nodeStartRange) == 1;
41222 rangeCompareNode : function(range, node)
41224 var nodeRange = node.ownerDocument.createRange();
41226 nodeRange.selectNode(node);
41228 nodeRange.selectNodeContents(node);
41232 range.collapse(true);
41234 nodeRange.collapse(true);
41236 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41237 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41239 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41241 var nodeIsBefore = ss == 1;
41242 var nodeIsAfter = ee == -1;
41244 if (nodeIsBefore && nodeIsAfter)
41246 if (!nodeIsBefore && nodeIsAfter)
41247 return 1; //right trailed.
41249 if (nodeIsBefore && !nodeIsAfter)
41250 return 2; // left trailed.
41255 // private? - in a new class?
41256 cleanUpPaste : function()
41258 // cleans up the whole document..
41259 Roo.log('cleanuppaste');
41260 this.cleanUpChildren(this.doc.body);
41261 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41262 if (clean != this.doc.body.innerHTML) {
41263 this.doc.body.innerHTML = clean;
41268 cleanWordChars : function(input) {// change the chars to hex code
41269 var he = Roo.form.HtmlEditor;
41271 var output = input;
41272 Roo.each(he.swapCodes, function(sw) {
41273 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41275 output = output.replace(swapper, sw[1]);
41282 cleanUpChildren : function (n)
41284 if (!n.childNodes.length) {
41287 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41288 this.cleanUpChild(n.childNodes[i]);
41295 cleanUpChild : function (node)
41298 //console.log(node);
41299 if (node.nodeName == "#text") {
41300 // clean up silly Windows -- stuff?
41303 if (node.nodeName == "#comment") {
41304 node.parentNode.removeChild(node);
41305 // clean up silly Windows -- stuff?
41309 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
41311 node.parentNode.removeChild(node);
41316 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
41318 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41319 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41321 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41322 // remove_keep_children = true;
41325 if (remove_keep_children) {
41326 this.cleanUpChildren(node);
41327 // inserts everything just before this node...
41328 while (node.childNodes.length) {
41329 var cn = node.childNodes[0];
41330 node.removeChild(cn);
41331 node.parentNode.insertBefore(cn, node);
41333 node.parentNode.removeChild(node);
41337 if (!node.attributes || !node.attributes.length) {
41338 this.cleanUpChildren(node);
41342 function cleanAttr(n,v)
41345 if (v.match(/^\./) || v.match(/^\//)) {
41348 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41351 if (v.match(/^#/)) {
41354 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41355 node.removeAttribute(n);
41359 function cleanStyle(n,v)
41361 if (v.match(/expression/)) { //XSS?? should we even bother..
41362 node.removeAttribute(n);
41365 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.form.HtmlEditor.cwhite : ed.cwhite;
41366 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.form.HtmlEditor.cblack : ed.cblack;
41369 var parts = v.split(/;/);
41372 Roo.each(parts, function(p) {
41373 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41377 var l = p.split(':').shift().replace(/\s+/g,'');
41378 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41381 if ( cblack.indexOf(l) > -1) {
41382 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41383 //node.removeAttribute(n);
41387 // only allow 'c whitelisted system attributes'
41388 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41389 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41390 //node.removeAttribute(n);
41400 if (clean.length) {
41401 node.setAttribute(n, clean.join(';'));
41403 node.removeAttribute(n);
41409 for (var i = node.attributes.length-1; i > -1 ; i--) {
41410 var a = node.attributes[i];
41413 if (a.name.toLowerCase().substr(0,2)=='on') {
41414 node.removeAttribute(a.name);
41417 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
41418 node.removeAttribute(a.name);
41421 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
41422 cleanAttr(a.name,a.value); // fixme..
41425 if (a.name == 'style') {
41426 cleanStyle(a.name,a.value);
41429 /// clean up MS crap..
41430 // tecnically this should be a list of valid class'es..
41433 if (a.name == 'class') {
41434 if (a.value.match(/^Mso/)) {
41435 node.className = '';
41438 if (a.value.match(/body/)) {
41439 node.className = '';
41450 this.cleanUpChildren(node);
41456 // hide stuff that is not compatible
41470 * @event specialkey
41474 * @cfg {String} fieldClass @hide
41477 * @cfg {String} focusClass @hide
41480 * @cfg {String} autoCreate @hide
41483 * @cfg {String} inputType @hide
41486 * @cfg {String} invalidClass @hide
41489 * @cfg {String} invalidText @hide
41492 * @cfg {String} msgFx @hide
41495 * @cfg {String} validateOnBlur @hide
41499 Roo.form.HtmlEditor.white = [
41500 'area', 'br', 'img', 'input', 'hr', 'wbr',
41502 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
41503 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
41504 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
41505 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
41506 'table', 'ul', 'xmp',
41508 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
41511 'dir', 'menu', 'ol', 'ul', 'dl',
41517 Roo.form.HtmlEditor.black = [
41518 // 'embed', 'object', // enable - backend responsiblity to clean thiese
41520 'base', 'basefont', 'bgsound', 'blink', 'body',
41521 'frame', 'frameset', 'head', 'html', 'ilayer',
41522 'iframe', 'layer', 'link', 'meta', 'object',
41523 'script', 'style' ,'title', 'xml' // clean later..
41525 Roo.form.HtmlEditor.clean = [
41526 'script', 'style', 'title', 'xml'
41528 Roo.form.HtmlEditor.remove = [
41533 Roo.form.HtmlEditor.ablack = [
41537 Roo.form.HtmlEditor.aclean = [
41538 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
41542 Roo.form.HtmlEditor.pwhite= [
41543 'http', 'https', 'mailto'
41546 // white listed style attributes.
41547 Roo.form.HtmlEditor.cwhite= [
41548 // 'text-align', /// default is to allow most things..
41554 // black listed style attributes.
41555 Roo.form.HtmlEditor.cblack= [
41556 // 'font-size' -- this can be set by the project
41560 Roo.form.HtmlEditor.swapCodes =[
41571 // <script type="text/javascript">
41574 * Ext JS Library 1.1.1
41575 * Copyright(c) 2006-2007, Ext JS, LLC.
41581 * @class Roo.form.HtmlEditorToolbar1
41586 new Roo.form.HtmlEditor({
41589 new Roo.form.HtmlEditorToolbar1({
41590 disable : { fonts: 1 , format: 1, ..., ... , ...],
41596 * @cfg {Object} disable List of elements to disable..
41597 * @cfg {Array} btns List of additional buttons.
41601 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
41604 Roo.form.HtmlEditor.ToolbarStandard = function(config)
41607 Roo.apply(this, config);
41609 // default disabled, based on 'good practice'..
41610 this.disable = this.disable || {};
41611 Roo.applyIf(this.disable, {
41614 specialElements : true
41618 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
41619 // dont call parent... till later.
41622 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
41630 * @cfg {Object} disable List of toolbar elements to disable
41635 * @cfg {Array} fontFamilies An array of available font families
41653 // "á" , ?? a acute?
41658 "°" // , // degrees
41660 // "é" , // e ecute
41661 // "ú" , // u ecute?
41664 specialElements : [
41666 text: "Insert Table",
41669 ihtml : '<table><tr><td>Cell</td></tr></table>'
41673 text: "Insert Image",
41676 ihtml : '<img src="about:blank"/>'
41685 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
41686 "input:submit", "input:button", "select", "textarea", "label" ],
41689 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
41691 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
41699 * @cfg {String} defaultFont default font to use.
41701 defaultFont: 'tahoma',
41703 fontSelect : false,
41706 formatCombo : false,
41708 init : function(editor)
41710 this.editor = editor;
41713 var fid = editor.frameId;
41715 function btn(id, toggle, handler){
41716 var xid = fid + '-'+ id ;
41720 cls : 'x-btn-icon x-edit-'+id,
41721 enableToggle:toggle !== false,
41722 scope: editor, // was editor...
41723 handler:handler||editor.relayBtnCmd,
41724 clickEvent:'mousedown',
41725 tooltip: etb.buttonTips[id] || undefined, ///tips ???
41732 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
41734 // stop form submits
41735 tb.el.on('click', function(e){
41736 e.preventDefault(); // what does this do?
41739 if(!this.disable.font) { // && !Roo.isSafari){
41740 /* why no safari for fonts
41741 editor.fontSelect = tb.el.createChild({
41744 cls:'x-font-select',
41745 html: this.createFontOptions()
41748 editor.fontSelect.on('change', function(){
41749 var font = editor.fontSelect.dom.value;
41750 editor.relayCmd('fontname', font);
41751 editor.deferFocus();
41755 editor.fontSelect.dom,
41761 if(!this.disable.formats){
41762 this.formatCombo = new Roo.form.ComboBox({
41763 store: new Roo.data.SimpleStore({
41766 data : this.formats // from states.js
41770 //autoCreate : {tag: "div", size: "20"},
41771 displayField:'tag',
41775 triggerAction: 'all',
41776 emptyText:'Add tag',
41777 selectOnFocus:true,
41780 'select': function(c, r, i) {
41781 editor.insertTag(r.get('tag'));
41787 tb.addField(this.formatCombo);
41791 if(!this.disable.format){
41798 if(!this.disable.fontSize){
41803 btn('increasefontsize', false, editor.adjustFont),
41804 btn('decreasefontsize', false, editor.adjustFont)
41809 if(!this.disable.colors){
41812 id:editor.frameId +'-forecolor',
41813 cls:'x-btn-icon x-edit-forecolor',
41814 clickEvent:'mousedown',
41815 tooltip: this.buttonTips['forecolor'] || undefined,
41817 menu : new Roo.menu.ColorMenu({
41818 allowReselect: true,
41819 focus: Roo.emptyFn,
41822 selectHandler: function(cp, color){
41823 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
41824 editor.deferFocus();
41827 clickEvent:'mousedown'
41830 id:editor.frameId +'backcolor',
41831 cls:'x-btn-icon x-edit-backcolor',
41832 clickEvent:'mousedown',
41833 tooltip: this.buttonTips['backcolor'] || undefined,
41835 menu : new Roo.menu.ColorMenu({
41836 focus: Roo.emptyFn,
41839 allowReselect: true,
41840 selectHandler: function(cp, color){
41842 editor.execCmd('useCSS', false);
41843 editor.execCmd('hilitecolor', color);
41844 editor.execCmd('useCSS', true);
41845 editor.deferFocus();
41847 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
41848 Roo.isSafari || Roo.isIE ? '#'+color : color);
41849 editor.deferFocus();
41853 clickEvent:'mousedown'
41858 // now add all the items...
41861 if(!this.disable.alignments){
41864 btn('justifyleft'),
41865 btn('justifycenter'),
41866 btn('justifyright')
41870 //if(!Roo.isSafari){
41871 if(!this.disable.links){
41874 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
41878 if(!this.disable.lists){
41881 btn('insertorderedlist'),
41882 btn('insertunorderedlist')
41885 if(!this.disable.sourceEdit){
41888 btn('sourceedit', true, function(btn){
41889 this.toggleSourceEdit(btn.pressed);
41896 // special menu.. - needs to be tidied up..
41897 if (!this.disable.special) {
41900 cls: 'x-edit-none',
41906 for (var i =0; i < this.specialChars.length; i++) {
41907 smenu.menu.items.push({
41909 html: this.specialChars[i],
41910 handler: function(a,b) {
41911 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
41912 //editor.insertAtCursor(a.html);
41926 if (!this.disable.cleanStyles) {
41928 cls: 'x-btn-icon x-btn-clear',
41934 for (var i =0; i < this.cleanStyles.length; i++) {
41935 cmenu.menu.items.push({
41937 html: this.cleanStyles[i],
41938 handler: function(a,b) {
41939 var c = Roo.get(editor.doc.body);
41940 c.select('[style]').each(function(s) {
41941 s.dom.style.removeProperty(a.html);
41952 if (!this.disable.specialElements) {
41955 cls: 'x-edit-none',
41960 for (var i =0; i < this.specialElements.length; i++) {
41961 semenu.menu.items.push(
41963 handler: function(a,b) {
41964 editor.insertAtCursor(this.ihtml);
41966 }, this.specialElements[i])
41978 for(var i =0; i< this.btns.length;i++) {
41979 var b = Roo.factory(this.btns[i],Roo.form);
41980 b.cls = 'x-edit-none';
41989 // disable everything...
41991 this.tb.items.each(function(item){
41992 if(item.id != editor.frameId+ '-sourceedit'){
41996 this.rendered = true;
41998 // the all the btns;
41999 editor.on('editorevent', this.updateToolbar, this);
42000 // other toolbars need to implement this..
42001 //editor.on('editmodechange', this.updateToolbar, this);
42007 * Protected method that will not generally be called directly. It triggers
42008 * a toolbar update by reading the markup state of the current selection in the editor.
42010 updateToolbar: function(){
42012 if(!this.editor.activated){
42013 this.editor.onFirstFocus();
42017 var btns = this.tb.items.map,
42018 doc = this.editor.doc,
42019 frameId = this.editor.frameId;
42021 if(!this.disable.font && !Roo.isSafari){
42023 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
42024 if(name != this.fontSelect.dom.value){
42025 this.fontSelect.dom.value = name;
42029 if(!this.disable.format){
42030 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
42031 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
42032 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
42034 if(!this.disable.alignments){
42035 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
42036 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
42037 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
42039 if(!Roo.isSafari && !this.disable.lists){
42040 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
42041 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
42044 var ans = this.editor.getAllAncestors();
42045 if (this.formatCombo) {
42048 var store = this.formatCombo.store;
42049 this.formatCombo.setValue("");
42050 for (var i =0; i < ans.length;i++) {
42051 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
42053 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
42061 // hides menus... - so this cant be on a menu...
42062 Roo.menu.MenuMgr.hideAll();
42064 //this.editorsyncValue();
42068 createFontOptions : function(){
42069 var buf = [], fs = this.fontFamilies, ff, lc;
42073 for(var i = 0, len = fs.length; i< len; i++){
42075 lc = ff.toLowerCase();
42077 '<option value="',lc,'" style="font-family:',ff,';"',
42078 (this.defaultFont == lc ? ' selected="true">' : '>'),
42083 return buf.join('');
42086 toggleSourceEdit : function(sourceEditMode){
42087 if(sourceEditMode === undefined){
42088 sourceEditMode = !this.sourceEditMode;
42090 this.sourceEditMode = sourceEditMode === true;
42091 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
42092 // just toggle the button?
42093 if(btn.pressed !== this.editor.sourceEditMode){
42094 btn.toggle(this.editor.sourceEditMode);
42098 if(this.sourceEditMode){
42099 this.tb.items.each(function(item){
42100 if(item.cmd != 'sourceedit'){
42106 if(this.initialized){
42107 this.tb.items.each(function(item){
42113 // tell the editor that it's been pressed..
42114 this.editor.toggleSourceEdit(sourceEditMode);
42118 * Object collection of toolbar tooltips for the buttons in the editor. The key
42119 * is the command id associated with that button and the value is a valid QuickTips object.
42124 title: 'Bold (Ctrl+B)',
42125 text: 'Make the selected text bold.',
42126 cls: 'x-html-editor-tip'
42129 title: 'Italic (Ctrl+I)',
42130 text: 'Make the selected text italic.',
42131 cls: 'x-html-editor-tip'
42139 title: 'Bold (Ctrl+B)',
42140 text: 'Make the selected text bold.',
42141 cls: 'x-html-editor-tip'
42144 title: 'Italic (Ctrl+I)',
42145 text: 'Make the selected text italic.',
42146 cls: 'x-html-editor-tip'
42149 title: 'Underline (Ctrl+U)',
42150 text: 'Underline the selected text.',
42151 cls: 'x-html-editor-tip'
42153 increasefontsize : {
42154 title: 'Grow Text',
42155 text: 'Increase the font size.',
42156 cls: 'x-html-editor-tip'
42158 decreasefontsize : {
42159 title: 'Shrink Text',
42160 text: 'Decrease the font size.',
42161 cls: 'x-html-editor-tip'
42164 title: 'Text Highlight Color',
42165 text: 'Change the background color of the selected text.',
42166 cls: 'x-html-editor-tip'
42169 title: 'Font Color',
42170 text: 'Change the color of the selected text.',
42171 cls: 'x-html-editor-tip'
42174 title: 'Align Text Left',
42175 text: 'Align text to the left.',
42176 cls: 'x-html-editor-tip'
42179 title: 'Center Text',
42180 text: 'Center text in the editor.',
42181 cls: 'x-html-editor-tip'
42184 title: 'Align Text Right',
42185 text: 'Align text to the right.',
42186 cls: 'x-html-editor-tip'
42188 insertunorderedlist : {
42189 title: 'Bullet List',
42190 text: 'Start a bulleted list.',
42191 cls: 'x-html-editor-tip'
42193 insertorderedlist : {
42194 title: 'Numbered List',
42195 text: 'Start a numbered list.',
42196 cls: 'x-html-editor-tip'
42199 title: 'Hyperlink',
42200 text: 'Make the selected text a hyperlink.',
42201 cls: 'x-html-editor-tip'
42204 title: 'Source Edit',
42205 text: 'Switch to source editing mode.',
42206 cls: 'x-html-editor-tip'
42210 onDestroy : function(){
42213 this.tb.items.each(function(item){
42215 item.menu.removeAll();
42217 item.menu.el.destroy();
42225 onFirstFocus: function() {
42226 this.tb.items.each(function(item){
42235 // <script type="text/javascript">
42238 * Ext JS Library 1.1.1
42239 * Copyright(c) 2006-2007, Ext JS, LLC.
42246 * @class Roo.form.HtmlEditor.ToolbarContext
42251 new Roo.form.HtmlEditor({
42254 { xtype: 'ToolbarStandard', styles : {} }
42255 { xtype: 'ToolbarContext', disable : {} }
42261 * @config : {Object} disable List of elements to disable.. (not done yet.)
42262 * @config : {Object} styles Map of styles available.
42266 Roo.form.HtmlEditor.ToolbarContext = function(config)
42269 Roo.apply(this, config);
42270 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42271 // dont call parent... till later.
42272 this.styles = this.styles || {};
42277 Roo.form.HtmlEditor.ToolbarContext.types = {
42289 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42351 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
42356 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
42366 style : 'fontFamily',
42367 displayField: 'display',
42368 optname : 'font-family',
42417 // should we really allow this??
42418 // should this just be
42429 style : 'fontFamily',
42430 displayField: 'display',
42431 optname : 'font-family',
42438 style : 'fontFamily',
42439 displayField: 'display',
42440 optname : 'font-family',
42447 style : 'fontFamily',
42448 displayField: 'display',
42449 optname : 'font-family',
42460 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
42461 Roo.form.HtmlEditor.ToolbarContext.stores = false;
42463 Roo.form.HtmlEditor.ToolbarContext.options = {
42465 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
42466 [ 'Courier New', 'Courier New'],
42467 [ 'Tahoma', 'Tahoma'],
42468 [ 'Times New Roman,serif', 'Times'],
42469 [ 'Verdana','Verdana' ]
42473 // fixme - these need to be configurable..
42476 Roo.form.HtmlEditor.ToolbarContext.types
42479 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
42487 * @cfg {Object} disable List of toolbar elements to disable
42492 * @cfg {Object} styles List of styles
42493 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
42495 * These must be defined in the page, so they get rendered correctly..
42506 init : function(editor)
42508 this.editor = editor;
42511 var fid = editor.frameId;
42513 function btn(id, toggle, handler){
42514 var xid = fid + '-'+ id ;
42518 cls : 'x-btn-icon x-edit-'+id,
42519 enableToggle:toggle !== false,
42520 scope: editor, // was editor...
42521 handler:handler||editor.relayBtnCmd,
42522 clickEvent:'mousedown',
42523 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42527 // create a new element.
42528 var wdiv = editor.wrap.createChild({
42530 }, editor.wrap.dom.firstChild.nextSibling, true);
42532 // can we do this more than once??
42534 // stop form submits
42537 // disable everything...
42538 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42539 this.toolbars = {};
42541 for (var i in ty) {
42543 this.toolbars[i] = this.buildToolbar(ty[i],i);
42545 this.tb = this.toolbars.BODY;
42547 this.buildFooter();
42548 this.footer.show();
42549 editor.on('hide', function( ) { this.footer.hide() }, this);
42550 editor.on('show', function( ) { this.footer.show() }, this);
42553 this.rendered = true;
42555 // the all the btns;
42556 editor.on('editorevent', this.updateToolbar, this);
42557 // other toolbars need to implement this..
42558 //editor.on('editmodechange', this.updateToolbar, this);
42564 * Protected method that will not generally be called directly. It triggers
42565 * a toolbar update by reading the markup state of the current selection in the editor.
42567 updateToolbar: function(editor,ev,sel){
42570 // capture mouse up - this is handy for selecting images..
42571 // perhaps should go somewhere else...
42572 if(!this.editor.activated){
42573 this.editor.onFirstFocus();
42577 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
42578 // selectNode - might want to handle IE?
42580 (ev.type == 'mouseup' || ev.type == 'click' ) &&
42581 ev.target && ev.target.tagName == 'IMG') {
42582 // they have click on an image...
42583 // let's see if we can change the selection...
42586 var nodeRange = sel.ownerDocument.createRange();
42588 nodeRange.selectNode(sel);
42590 nodeRange.selectNodeContents(sel);
42592 //nodeRange.collapse(true);
42593 var s = editor.win.getSelection();
42594 s.removeAllRanges();
42595 s.addRange(nodeRange);
42599 var updateFooter = sel ? false : true;
42602 var ans = this.editor.getAllAncestors();
42605 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42608 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
42609 sel = sel ? sel : this.editor.doc.body;
42610 sel = sel.tagName.length ? sel : this.editor.doc.body;
42613 // pick a menu that exists..
42614 var tn = sel.tagName.toUpperCase();
42615 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
42617 tn = sel.tagName.toUpperCase();
42619 var lastSel = this.tb.selectedNode
42621 this.tb.selectedNode = sel;
42623 // if current menu does not match..
42624 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
42627 ///console.log("show: " + tn);
42628 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
42631 this.tb.items.first().el.innerHTML = tn + ': ';
42634 // update attributes
42635 if (this.tb.fields) {
42636 this.tb.fields.each(function(e) {
42638 e.setValue(sel.style[e.stylename]);
42641 e.setValue(sel.getAttribute(e.attrname));
42645 var hasStyles = false;
42646 for(var i in this.styles) {
42653 var st = this.tb.fields.item(0);
42655 st.store.removeAll();
42658 var cn = sel.className.split(/\s+/);
42661 if (this.styles['*']) {
42663 Roo.each(this.styles['*'], function(v) {
42664 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42667 if (this.styles[tn]) {
42668 Roo.each(this.styles[tn], function(v) {
42669 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42673 st.store.loadData(avs);
42677 // flag our selected Node.
42678 this.tb.selectedNode = sel;
42681 Roo.menu.MenuMgr.hideAll();
42685 if (!updateFooter) {
42686 //this.footDisp.dom.innerHTML = '';
42689 // update the footer
42693 this.footerEls = ans.reverse();
42694 Roo.each(this.footerEls, function(a,i) {
42695 if (!a) { return; }
42696 html += html.length ? ' > ' : '';
42698 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
42703 var sz = this.footDisp.up('td').getSize();
42704 this.footDisp.dom.style.width = (sz.width -10) + 'px';
42705 this.footDisp.dom.style.marginLeft = '5px';
42707 this.footDisp.dom.style.overflow = 'hidden';
42709 this.footDisp.dom.innerHTML = html;
42711 //this.editorsyncValue();
42718 onDestroy : function(){
42721 this.tb.items.each(function(item){
42723 item.menu.removeAll();
42725 item.menu.el.destroy();
42733 onFirstFocus: function() {
42734 // need to do this for all the toolbars..
42735 this.tb.items.each(function(item){
42739 buildToolbar: function(tlist, nm)
42741 var editor = this.editor;
42742 // create a new element.
42743 var wdiv = editor.wrap.createChild({
42745 }, editor.wrap.dom.firstChild.nextSibling, true);
42748 var tb = new Roo.Toolbar(wdiv);
42751 tb.add(nm+ ": ");
42754 for(var i in this.styles) {
42759 if (styles && styles.length) {
42761 // this needs a multi-select checkbox...
42762 tb.addField( new Roo.form.ComboBox({
42763 store: new Roo.data.SimpleStore({
42765 fields: ['val', 'selected'],
42768 name : '-roo-edit-className',
42769 attrname : 'className',
42770 displayField: 'val',
42774 triggerAction: 'all',
42775 emptyText:'Select Style',
42776 selectOnFocus:true,
42779 'select': function(c, r, i) {
42780 // initial support only for on class per el..
42781 tb.selectedNode.className = r ? r.get('val') : '';
42782 editor.syncValue();
42789 var tbc = Roo.form.HtmlEditor.ToolbarContext;
42790 var tbops = tbc.options;
42792 for (var i in tlist) {
42794 var item = tlist[i];
42795 tb.add(item.title + ": ");
42798 //optname == used so you can configure the options available..
42799 var opts = item.opts ? item.opts : false;
42800 if (item.optname) {
42801 opts = tbops[item.optname];
42806 // opts == pulldown..
42807 tb.addField( new Roo.form.ComboBox({
42808 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
42810 fields: ['val', 'display'],
42813 name : '-roo-edit-' + i,
42815 stylename : item.style ? item.style : false,
42816 displayField: item.displayField ? item.displayField : 'val',
42817 valueField : 'val',
42819 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
42821 triggerAction: 'all',
42822 emptyText:'Select',
42823 selectOnFocus:true,
42824 width: item.width ? item.width : 130,
42826 'select': function(c, r, i) {
42828 tb.selectedNode.style[c.stylename] = r.get('val');
42831 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
42840 tb.addField( new Roo.form.TextField({
42843 //allowBlank:false,
42848 tb.addField( new Roo.form.TextField({
42849 name: '-roo-edit-' + i,
42856 'change' : function(f, nv, ov) {
42857 tb.selectedNode.setAttribute(f.attrname, nv);
42866 text: 'Remove Tag',
42869 click : function ()
42872 // undo does not work.
42874 var sn = tb.selectedNode;
42876 var pn = sn.parentNode;
42878 var stn = sn.childNodes[0];
42879 var en = sn.childNodes[sn.childNodes.length - 1 ];
42880 while (sn.childNodes.length) {
42881 var node = sn.childNodes[0];
42882 sn.removeChild(node);
42884 pn.insertBefore(node, sn);
42887 pn.removeChild(sn);
42888 var range = editor.createRange();
42890 range.setStart(stn,0);
42891 range.setEnd(en,0); //????
42892 //range.selectNode(sel);
42895 var selection = editor.getSelection();
42896 selection.removeAllRanges();
42897 selection.addRange(range);
42901 //_this.updateToolbar(null, null, pn);
42902 _this.updateToolbar(null, null, null);
42903 _this.footDisp.dom.innerHTML = '';
42913 tb.el.on('click', function(e){
42914 e.preventDefault(); // what does this do?
42916 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
42919 // dont need to disable them... as they will get hidden
42924 buildFooter : function()
42927 var fel = this.editor.wrap.createChild();
42928 this.footer = new Roo.Toolbar(fel);
42929 // toolbar has scrolly on left / right?
42930 var footDisp= new Roo.Toolbar.Fill();
42936 handler : function() {
42937 _t.footDisp.scrollTo('left',0,true)
42941 this.footer.add( footDisp );
42946 handler : function() {
42948 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
42952 var fel = Roo.get(footDisp.el);
42953 fel.addClass('x-editor-context');
42954 this.footDispWrap = fel;
42955 this.footDispWrap.overflow = 'hidden';
42957 this.footDisp = fel.createChild();
42958 this.footDispWrap.on('click', this.onContextClick, this)
42962 onContextClick : function (ev,dom)
42964 ev.preventDefault();
42965 var cn = dom.className;
42967 if (!cn.match(/x-ed-loc-/)) {
42970 var n = cn.split('-').pop();
42971 var ans = this.footerEls;
42975 var range = this.editor.createRange();
42977 range.selectNodeContents(sel);
42978 //range.selectNode(sel);
42981 var selection = this.editor.getSelection();
42982 selection.removeAllRanges();
42983 selection.addRange(range);
42987 this.updateToolbar(null, null, sel);
43004 * Ext JS Library 1.1.1
43005 * Copyright(c) 2006-2007, Ext JS, LLC.
43007 * Originally Released Under LGPL - original licence link has changed is not relivant.
43010 * <script type="text/javascript">
43014 * @class Roo.form.BasicForm
43015 * @extends Roo.util.Observable
43016 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
43018 * @param {String/HTMLElement/Roo.Element} el The form element or its id
43019 * @param {Object} config Configuration options
43021 Roo.form.BasicForm = function(el, config){
43022 this.allItems = [];
43023 this.childForms = [];
43024 Roo.apply(this, config);
43026 * The Roo.form.Field items in this form.
43027 * @type MixedCollection
43031 this.items = new Roo.util.MixedCollection(false, function(o){
43032 return o.id || (o.id = Roo.id());
43036 * @event beforeaction
43037 * Fires before any action is performed. Return false to cancel the action.
43038 * @param {Form} this
43039 * @param {Action} action The action to be performed
43041 beforeaction: true,
43043 * @event actionfailed
43044 * Fires when an action fails.
43045 * @param {Form} this
43046 * @param {Action} action The action that failed
43048 actionfailed : true,
43050 * @event actioncomplete
43051 * Fires when an action is completed.
43052 * @param {Form} this
43053 * @param {Action} action The action that completed
43055 actioncomplete : true
43060 Roo.form.BasicForm.superclass.constructor.call(this);
43063 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
43065 * @cfg {String} method
43066 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
43069 * @cfg {DataReader} reader
43070 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
43071 * This is optional as there is built-in support for processing JSON.
43074 * @cfg {DataReader} errorReader
43075 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
43076 * This is completely optional as there is built-in support for processing JSON.
43079 * @cfg {String} url
43080 * The URL to use for form actions if one isn't supplied in the action options.
43083 * @cfg {Boolean} fileUpload
43084 * Set to true if this form is a file upload.
43088 * @cfg {Object} baseParams
43089 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
43094 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
43099 activeAction : null,
43102 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
43103 * or setValues() data instead of when the form was first created.
43105 trackResetOnLoad : false,
43109 * childForms - used for multi-tab forms
43112 childForms : false,
43115 * allItems - full list of fields.
43121 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
43122 * element by passing it or its id or mask the form itself by passing in true.
43125 waitMsgTarget : false,
43128 initEl : function(el){
43129 this.el = Roo.get(el);
43130 this.id = this.el.id || Roo.id();
43131 this.el.on('submit', this.onSubmit, this);
43132 this.el.addClass('x-form');
43136 onSubmit : function(e){
43141 * Returns true if client-side validation on the form is successful.
43144 isValid : function(){
43146 this.items.each(function(f){
43155 * Returns true if any fields in this form have changed since their original load.
43158 isDirty : function(){
43160 this.items.each(function(f){
43170 * Performs a predefined action (submit or load) or custom actions you define on this form.
43171 * @param {String} actionName The name of the action type
43172 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
43173 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
43174 * accept other config options):
43176 Property Type Description
43177 ---------------- --------------- ----------------------------------------------------------------------------------
43178 url String The url for the action (defaults to the form's url)
43179 method String The form method to use (defaults to the form's method, or POST if not defined)
43180 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
43181 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
43182 validate the form on the client (defaults to false)
43184 * @return {BasicForm} this
43186 doAction : function(action, options){
43187 if(typeof action == 'string'){
43188 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
43190 if(this.fireEvent('beforeaction', this, action) !== false){
43191 this.beforeAction(action);
43192 action.run.defer(100, action);
43198 * Shortcut to do a submit action.
43199 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43200 * @return {BasicForm} this
43202 submit : function(options){
43203 this.doAction('submit', options);
43208 * Shortcut to do a load action.
43209 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43210 * @return {BasicForm} this
43212 load : function(options){
43213 this.doAction('load', options);
43218 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
43219 * @param {Record} record The record to edit
43220 * @return {BasicForm} this
43222 updateRecord : function(record){
43223 record.beginEdit();
43224 var fs = record.fields;
43225 fs.each(function(f){
43226 var field = this.findField(f.name);
43228 record.set(f.name, field.getValue());
43236 * Loads an Roo.data.Record into this form.
43237 * @param {Record} record The record to load
43238 * @return {BasicForm} this
43240 loadRecord : function(record){
43241 this.setValues(record.data);
43246 beforeAction : function(action){
43247 var o = action.options;
43250 if(this.waitMsgTarget === true){
43251 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
43252 }else if(this.waitMsgTarget){
43253 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
43254 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
43256 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
43262 afterAction : function(action, success){
43263 this.activeAction = null;
43264 var o = action.options;
43266 if(this.waitMsgTarget === true){
43268 }else if(this.waitMsgTarget){
43269 this.waitMsgTarget.unmask();
43271 Roo.MessageBox.updateProgress(1);
43272 Roo.MessageBox.hide();
43279 Roo.callback(o.success, o.scope, [this, action]);
43280 this.fireEvent('actioncomplete', this, action);
43284 // failure condition..
43285 // we have a scenario where updates need confirming.
43286 // eg. if a locking scenario exists..
43287 // we look for { errors : { needs_confirm : true }} in the response.
43289 (typeof(action.result) != 'undefined') &&
43290 (typeof(action.result.errors) != 'undefined') &&
43291 (typeof(action.result.errors.needs_confirm) != 'undefined')
43294 Roo.MessageBox.confirm(
43295 "Change requires confirmation",
43296 action.result.errorMsg,
43301 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
43311 Roo.callback(o.failure, o.scope, [this, action]);
43312 // show an error message if no failed handler is set..
43313 if (!this.hasListener('actionfailed')) {
43314 Roo.MessageBox.alert("Error",
43315 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
43316 action.result.errorMsg :
43317 "Saving Failed, please check your entries or try again"
43321 this.fireEvent('actionfailed', this, action);
43327 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
43328 * @param {String} id The value to search for
43331 findField : function(id){
43332 var field = this.items.get(id);
43334 this.items.each(function(f){
43335 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
43341 return field || null;
43345 * Add a secondary form to this one,
43346 * Used to provide tabbed forms. One form is primary, with hidden values
43347 * which mirror the elements from the other forms.
43349 * @param {Roo.form.Form} form to add.
43352 addForm : function(form)
43355 if (this.childForms.indexOf(form) > -1) {
43359 this.childForms.push(form);
43361 Roo.each(form.allItems, function (fe) {
43363 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
43364 if (this.findField(n)) { // already added..
43367 var add = new Roo.form.Hidden({
43370 add.render(this.el);
43377 * Mark fields in this form invalid in bulk.
43378 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
43379 * @return {BasicForm} this
43381 markInvalid : function(errors){
43382 if(errors instanceof Array){
43383 for(var i = 0, len = errors.length; i < len; i++){
43384 var fieldError = errors[i];
43385 var f = this.findField(fieldError.id);
43387 f.markInvalid(fieldError.msg);
43393 if(typeof errors[id] != 'function' && (field = this.findField(id))){
43394 field.markInvalid(errors[id]);
43398 Roo.each(this.childForms || [], function (f) {
43399 f.markInvalid(errors);
43406 * Set values for fields in this form in bulk.
43407 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
43408 * @return {BasicForm} this
43410 setValues : function(values){
43411 if(values instanceof Array){ // array of objects
43412 for(var i = 0, len = values.length; i < len; i++){
43414 var f = this.findField(v.id);
43416 f.setValue(v.value);
43417 if(this.trackResetOnLoad){
43418 f.originalValue = f.getValue();
43422 }else{ // object hash
43425 if(typeof values[id] != 'function' && (field = this.findField(id))){
43427 if (field.setFromData &&
43428 field.valueField &&
43429 field.displayField &&
43430 // combos' with local stores can
43431 // be queried via setValue()
43432 // to set their value..
43433 (field.store && !field.store.isLocal)
43437 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
43438 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
43439 field.setFromData(sd);
43442 field.setValue(values[id]);
43446 if(this.trackResetOnLoad){
43447 field.originalValue = field.getValue();
43453 Roo.each(this.childForms || [], function (f) {
43454 f.setValues(values);
43461 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
43462 * they are returned as an array.
43463 * @param {Boolean} asString
43466 getValues : function(asString){
43467 if (this.childForms) {
43468 // copy values from the child forms
43469 Roo.each(this.childForms, function (f) {
43470 this.setValues(f.getValues());
43476 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
43477 if(asString === true){
43480 return Roo.urlDecode(fs);
43484 * Returns the fields in this form as an object with key/value pairs.
43485 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
43488 getFieldValues : function(with_hidden)
43490 if (this.childForms) {
43491 // copy values from the child forms
43492 // should this call getFieldValues - probably not as we do not currently copy
43493 // hidden fields when we generate..
43494 Roo.each(this.childForms, function (f) {
43495 this.setValues(f.getValues());
43500 this.items.each(function(f){
43501 if (!f.getName()) {
43504 var v = f.getValue();
43505 if (f.inputType =='radio') {
43506 if (typeof(ret[f.getName()]) == 'undefined') {
43507 ret[f.getName()] = ''; // empty..
43510 if (!f.el.dom.checked) {
43514 v = f.el.dom.value;
43518 // not sure if this supported any more..
43519 if ((typeof(v) == 'object') && f.getRawValue) {
43520 v = f.getRawValue() ; // dates..
43522 // combo boxes where name != hiddenName...
43523 if (f.name != f.getName()) {
43524 ret[f.name] = f.getRawValue();
43526 ret[f.getName()] = v;
43533 * Clears all invalid messages in this form.
43534 * @return {BasicForm} this
43536 clearInvalid : function(){
43537 this.items.each(function(f){
43541 Roo.each(this.childForms || [], function (f) {
43550 * Resets this form.
43551 * @return {BasicForm} this
43553 reset : function(){
43554 this.items.each(function(f){
43558 Roo.each(this.childForms || [], function (f) {
43567 * Add Roo.form components to this form.
43568 * @param {Field} field1
43569 * @param {Field} field2 (optional)
43570 * @param {Field} etc (optional)
43571 * @return {BasicForm} this
43574 this.items.addAll(Array.prototype.slice.call(arguments, 0));
43580 * Removes a field from the items collection (does NOT remove its markup).
43581 * @param {Field} field
43582 * @return {BasicForm} this
43584 remove : function(field){
43585 this.items.remove(field);
43590 * Looks at the fields in this form, checks them for an id attribute,
43591 * and calls applyTo on the existing dom element with that id.
43592 * @return {BasicForm} this
43594 render : function(){
43595 this.items.each(function(f){
43596 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
43604 * Calls {@link Ext#apply} for all fields in this form with the passed object.
43605 * @param {Object} values
43606 * @return {BasicForm} this
43608 applyToFields : function(o){
43609 this.items.each(function(f){
43616 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
43617 * @param {Object} values
43618 * @return {BasicForm} this
43620 applyIfToFields : function(o){
43621 this.items.each(function(f){
43629 Roo.BasicForm = Roo.form.BasicForm;/*
43631 * Ext JS Library 1.1.1
43632 * Copyright(c) 2006-2007, Ext JS, LLC.
43634 * Originally Released Under LGPL - original licence link has changed is not relivant.
43637 * <script type="text/javascript">
43641 * @class Roo.form.Form
43642 * @extends Roo.form.BasicForm
43643 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
43645 * @param {Object} config Configuration options
43647 Roo.form.Form = function(config){
43649 if (config.items) {
43650 xitems = config.items;
43651 delete config.items;
43655 Roo.form.Form.superclass.constructor.call(this, null, config);
43656 this.url = this.url || this.action;
43658 this.root = new Roo.form.Layout(Roo.applyIf({
43662 this.active = this.root;
43664 * Array of all the buttons that have been added to this form via {@link addButton}
43668 this.allItems = [];
43671 * @event clientvalidation
43672 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
43673 * @param {Form} this
43674 * @param {Boolean} valid true if the form has passed client-side validation
43676 clientvalidation: true,
43679 * Fires when the form is rendered
43680 * @param {Roo.form.Form} form
43685 if (this.progressUrl) {
43686 // push a hidden field onto the list of fields..
43690 name : 'UPLOAD_IDENTIFIER'
43695 Roo.each(xitems, this.addxtype, this);
43701 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
43703 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
43706 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
43709 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
43711 buttonAlign:'center',
43714 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
43719 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
43720 * This property cascades to child containers if not set.
43725 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
43726 * fires a looping event with that state. This is required to bind buttons to the valid
43727 * state using the config value formBind:true on the button.
43729 monitorValid : false,
43732 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
43737 * @cfg {String} progressUrl - Url to return progress data
43740 progressUrl : false,
43743 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
43744 * fields are added and the column is closed. If no fields are passed the column remains open
43745 * until end() is called.
43746 * @param {Object} config The config to pass to the column
43747 * @param {Field} field1 (optional)
43748 * @param {Field} field2 (optional)
43749 * @param {Field} etc (optional)
43750 * @return Column The column container object
43752 column : function(c){
43753 var col = new Roo.form.Column(c);
43755 if(arguments.length > 1){ // duplicate code required because of Opera
43756 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43763 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
43764 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
43765 * until end() is called.
43766 * @param {Object} config The config to pass to the fieldset
43767 * @param {Field} field1 (optional)
43768 * @param {Field} field2 (optional)
43769 * @param {Field} etc (optional)
43770 * @return FieldSet The fieldset container object
43772 fieldset : function(c){
43773 var fs = new Roo.form.FieldSet(c);
43775 if(arguments.length > 1){ // duplicate code required because of Opera
43776 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43783 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
43784 * fields are added and the container is closed. If no fields are passed the container remains open
43785 * until end() is called.
43786 * @param {Object} config The config to pass to the Layout
43787 * @param {Field} field1 (optional)
43788 * @param {Field} field2 (optional)
43789 * @param {Field} etc (optional)
43790 * @return Layout The container object
43792 container : function(c){
43793 var l = new Roo.form.Layout(c);
43795 if(arguments.length > 1){ // duplicate code required because of Opera
43796 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43803 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
43804 * @param {Object} container A Roo.form.Layout or subclass of Layout
43805 * @return {Form} this
43807 start : function(c){
43808 // cascade label info
43809 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
43810 this.active.stack.push(c);
43811 c.ownerCt = this.active;
43817 * Closes the current open container
43818 * @return {Form} this
43821 if(this.active == this.root){
43824 this.active = this.active.ownerCt;
43829 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
43830 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
43831 * as the label of the field.
43832 * @param {Field} field1
43833 * @param {Field} field2 (optional)
43834 * @param {Field} etc. (optional)
43835 * @return {Form} this
43838 this.active.stack.push.apply(this.active.stack, arguments);
43839 this.allItems.push.apply(this.allItems,arguments);
43841 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
43842 if(a[i].isFormField){
43847 Roo.form.Form.superclass.add.apply(this, r);
43857 * Find any element that has been added to a form, using it's ID or name
43858 * This can include framesets, columns etc. along with regular fields..
43859 * @param {String} id - id or name to find.
43861 * @return {Element} e - or false if nothing found.
43863 findbyId : function(id)
43869 Roo.each(this.allItems, function(f){
43870 if (f.id == id || f.name == id ){
43881 * Render this form into the passed container. This should only be called once!
43882 * @param {String/HTMLElement/Element} container The element this component should be rendered into
43883 * @return {Form} this
43885 render : function(ct)
43891 var o = this.autoCreate || {
43893 method : this.method || 'POST',
43894 id : this.id || Roo.id()
43896 this.initEl(ct.createChild(o));
43898 this.root.render(this.el);
43902 this.items.each(function(f){
43903 f.render('x-form-el-'+f.id);
43906 if(this.buttons.length > 0){
43907 // tables are required to maintain order and for correct IE layout
43908 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
43909 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
43910 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
43912 var tr = tb.getElementsByTagName('tr')[0];
43913 for(var i = 0, len = this.buttons.length; i < len; i++) {
43914 var b = this.buttons[i];
43915 var td = document.createElement('td');
43916 td.className = 'x-form-btn-td';
43917 b.render(tr.appendChild(td));
43920 if(this.monitorValid){ // initialize after render
43921 this.startMonitoring();
43923 this.fireEvent('rendered', this);
43928 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
43929 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
43930 * object or a valid Roo.DomHelper element config
43931 * @param {Function} handler The function called when the button is clicked
43932 * @param {Object} scope (optional) The scope of the handler function
43933 * @return {Roo.Button}
43935 addButton : function(config, handler, scope){
43939 minWidth: this.minButtonWidth,
43942 if(typeof config == "string"){
43945 Roo.apply(bc, config);
43947 var btn = new Roo.Button(null, bc);
43948 this.buttons.push(btn);
43953 * Adds a series of form elements (using the xtype property as the factory method.
43954 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
43955 * @param {Object} config
43958 addxtype : function()
43960 var ar = Array.prototype.slice.call(arguments, 0);
43962 for(var i = 0; i < ar.length; i++) {
43964 continue; // skip -- if this happends something invalid got sent, we
43965 // should ignore it, as basically that interface element will not show up
43966 // and that should be pretty obvious!!
43969 if (Roo.form[ar[i].xtype]) {
43971 var fe = Roo.factory(ar[i], Roo.form);
43977 fe.store.form = this;
43982 this.allItems.push(fe);
43983 if (fe.items && fe.addxtype) {
43984 fe.addxtype.apply(fe, fe.items);
43994 // console.log('adding ' + ar[i].xtype);
43996 if (ar[i].xtype == 'Button') {
43997 //console.log('adding button');
43998 //console.log(ar[i]);
43999 this.addButton(ar[i]);
44000 this.allItems.push(fe);
44004 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
44005 alert('end is not supported on xtype any more, use items');
44007 // //console.log('adding end');
44015 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
44016 * option "monitorValid"
44018 startMonitoring : function(){
44021 Roo.TaskMgr.start({
44022 run : this.bindHandler,
44023 interval : this.monitorPoll || 200,
44030 * Stops monitoring of the valid state of this form
44032 stopMonitoring : function(){
44033 this.bound = false;
44037 bindHandler : function(){
44039 return false; // stops binding
44042 this.items.each(function(f){
44043 if(!f.isValid(true)){
44048 for(var i = 0, len = this.buttons.length; i < len; i++){
44049 var btn = this.buttons[i];
44050 if(btn.formBind === true && btn.disabled === valid){
44051 btn.setDisabled(!valid);
44054 this.fireEvent('clientvalidation', this, valid);
44068 Roo.Form = Roo.form.Form;
44071 * Ext JS Library 1.1.1
44072 * Copyright(c) 2006-2007, Ext JS, LLC.
44074 * Originally Released Under LGPL - original licence link has changed is not relivant.
44077 * <script type="text/javascript">
44081 * @class Roo.form.Action
44082 * Internal Class used to handle form actions
44084 * @param {Roo.form.BasicForm} el The form element or its id
44085 * @param {Object} config Configuration options
44089 // define the action interface
44090 Roo.form.Action = function(form, options){
44092 this.options = options || {};
44095 * Client Validation Failed
44098 Roo.form.Action.CLIENT_INVALID = 'client';
44100 * Server Validation Failed
44103 Roo.form.Action.SERVER_INVALID = 'server';
44105 * Connect to Server Failed
44108 Roo.form.Action.CONNECT_FAILURE = 'connect';
44110 * Reading Data from Server Failed
44113 Roo.form.Action.LOAD_FAILURE = 'load';
44115 Roo.form.Action.prototype = {
44117 failureType : undefined,
44118 response : undefined,
44119 result : undefined,
44121 // interface method
44122 run : function(options){
44126 // interface method
44127 success : function(response){
44131 // interface method
44132 handleResponse : function(response){
44136 // default connection failure
44137 failure : function(response){
44139 this.response = response;
44140 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44141 this.form.afterAction(this, false);
44144 processResponse : function(response){
44145 this.response = response;
44146 if(!response.responseText){
44149 this.result = this.handleResponse(response);
44150 return this.result;
44153 // utility functions used internally
44154 getUrl : function(appendParams){
44155 var url = this.options.url || this.form.url || this.form.el.dom.action;
44157 var p = this.getParams();
44159 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
44165 getMethod : function(){
44166 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
44169 getParams : function(){
44170 var bp = this.form.baseParams;
44171 var p = this.options.params;
44173 if(typeof p == "object"){
44174 p = Roo.urlEncode(Roo.applyIf(p, bp));
44175 }else if(typeof p == 'string' && bp){
44176 p += '&' + Roo.urlEncode(bp);
44179 p = Roo.urlEncode(bp);
44184 createCallback : function(){
44186 success: this.success,
44187 failure: this.failure,
44189 timeout: (this.form.timeout*1000),
44190 upload: this.form.fileUpload ? this.success : undefined
44195 Roo.form.Action.Submit = function(form, options){
44196 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
44199 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
44202 haveProgress : false,
44203 uploadComplete : false,
44205 // uploadProgress indicator.
44206 uploadProgress : function()
44208 if (!this.form.progressUrl) {
44212 if (!this.haveProgress) {
44213 Roo.MessageBox.progress("Uploading", "Uploading");
44215 if (this.uploadComplete) {
44216 Roo.MessageBox.hide();
44220 this.haveProgress = true;
44222 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
44224 var c = new Roo.data.Connection();
44226 url : this.form.progressUrl,
44231 success : function(req){
44232 //console.log(data);
44236 rdata = Roo.decode(req.responseText)
44238 Roo.log("Invalid data from server..");
44242 if (!rdata || !rdata.success) {
44244 Roo.MessageBox.alert(Roo.encode(rdata));
44247 var data = rdata.data;
44249 if (this.uploadComplete) {
44250 Roo.MessageBox.hide();
44255 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
44256 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
44259 this.uploadProgress.defer(2000,this);
44262 failure: function(data) {
44263 Roo.log('progress url failed ');
44274 // run get Values on the form, so it syncs any secondary forms.
44275 this.form.getValues();
44277 var o = this.options;
44278 var method = this.getMethod();
44279 var isPost = method == 'POST';
44280 if(o.clientValidation === false || this.form.isValid()){
44282 if (this.form.progressUrl) {
44283 this.form.findField('UPLOAD_IDENTIFIER').setValue(
44284 (new Date() * 1) + '' + Math.random());
44289 Roo.Ajax.request(Roo.apply(this.createCallback(), {
44290 form:this.form.el.dom,
44291 url:this.getUrl(!isPost),
44293 params:isPost ? this.getParams() : null,
44294 isUpload: this.form.fileUpload
44297 this.uploadProgress();
44299 }else if (o.clientValidation !== false){ // client validation failed
44300 this.failureType = Roo.form.Action.CLIENT_INVALID;
44301 this.form.afterAction(this, false);
44305 success : function(response)
44307 this.uploadComplete= true;
44308 if (this.haveProgress) {
44309 Roo.MessageBox.hide();
44313 var result = this.processResponse(response);
44314 if(result === true || result.success){
44315 this.form.afterAction(this, true);
44319 this.form.markInvalid(result.errors);
44320 this.failureType = Roo.form.Action.SERVER_INVALID;
44322 this.form.afterAction(this, false);
44324 failure : function(response)
44326 this.uploadComplete= true;
44327 if (this.haveProgress) {
44328 Roo.MessageBox.hide();
44331 this.response = response;
44332 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44333 this.form.afterAction(this, false);
44336 handleResponse : function(response){
44337 if(this.form.errorReader){
44338 var rs = this.form.errorReader.read(response);
44341 for(var i = 0, len = rs.records.length; i < len; i++) {
44342 var r = rs.records[i];
44343 errors[i] = r.data;
44346 if(errors.length < 1){
44350 success : rs.success,
44356 ret = Roo.decode(response.responseText);
44360 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
44370 Roo.form.Action.Load = function(form, options){
44371 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
44372 this.reader = this.form.reader;
44375 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
44380 Roo.Ajax.request(Roo.apply(
44381 this.createCallback(), {
44382 method:this.getMethod(),
44383 url:this.getUrl(false),
44384 params:this.getParams()
44388 success : function(response){
44390 var result = this.processResponse(response);
44391 if(result === true || !result.success || !result.data){
44392 this.failureType = Roo.form.Action.LOAD_FAILURE;
44393 this.form.afterAction(this, false);
44396 this.form.clearInvalid();
44397 this.form.setValues(result.data);
44398 this.form.afterAction(this, true);
44401 handleResponse : function(response){
44402 if(this.form.reader){
44403 var rs = this.form.reader.read(response);
44404 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
44406 success : rs.success,
44410 return Roo.decode(response.responseText);
44414 Roo.form.Action.ACTION_TYPES = {
44415 'load' : Roo.form.Action.Load,
44416 'submit' : Roo.form.Action.Submit
44419 * Ext JS Library 1.1.1
44420 * Copyright(c) 2006-2007, Ext JS, LLC.
44422 * Originally Released Under LGPL - original licence link has changed is not relivant.
44425 * <script type="text/javascript">
44429 * @class Roo.form.Layout
44430 * @extends Roo.Component
44431 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
44433 * @param {Object} config Configuration options
44435 Roo.form.Layout = function(config){
44437 if (config.items) {
44438 xitems = config.items;
44439 delete config.items;
44441 Roo.form.Layout.superclass.constructor.call(this, config);
44443 Roo.each(xitems, this.addxtype, this);
44447 Roo.extend(Roo.form.Layout, Roo.Component, {
44449 * @cfg {String/Object} autoCreate
44450 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
44453 * @cfg {String/Object/Function} style
44454 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
44455 * a function which returns such a specification.
44458 * @cfg {String} labelAlign
44459 * Valid values are "left," "top" and "right" (defaults to "left")
44462 * @cfg {Number} labelWidth
44463 * Fixed width in pixels of all field labels (defaults to undefined)
44466 * @cfg {Boolean} clear
44467 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
44471 * @cfg {String} labelSeparator
44472 * The separator to use after field labels (defaults to ':')
44474 labelSeparator : ':',
44476 * @cfg {Boolean} hideLabels
44477 * True to suppress the display of field labels in this layout (defaults to false)
44479 hideLabels : false,
44482 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
44487 onRender : function(ct, position){
44488 if(this.el){ // from markup
44489 this.el = Roo.get(this.el);
44490 }else { // generate
44491 var cfg = this.getAutoCreate();
44492 this.el = ct.createChild(cfg, position);
44495 this.el.applyStyles(this.style);
44497 if(this.labelAlign){
44498 this.el.addClass('x-form-label-'+this.labelAlign);
44500 if(this.hideLabels){
44501 this.labelStyle = "display:none";
44502 this.elementStyle = "padding-left:0;";
44504 if(typeof this.labelWidth == 'number'){
44505 this.labelStyle = "width:"+this.labelWidth+"px;";
44506 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
44508 if(this.labelAlign == 'top'){
44509 this.labelStyle = "width:auto;";
44510 this.elementStyle = "padding-left:0;";
44513 var stack = this.stack;
44514 var slen = stack.length;
44516 if(!this.fieldTpl){
44517 var t = new Roo.Template(
44518 '<div class="x-form-item {5}">',
44519 '<label for="{0}" style="{2}">{1}{4}</label>',
44520 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44522 '</div><div class="x-form-clear-left"></div>'
44524 t.disableFormats = true;
44526 Roo.form.Layout.prototype.fieldTpl = t;
44528 for(var i = 0; i < slen; i++) {
44529 if(stack[i].isFormField){
44530 this.renderField(stack[i]);
44532 this.renderComponent(stack[i]);
44537 this.el.createChild({cls:'x-form-clear'});
44542 renderField : function(f){
44543 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
44546 f.labelStyle||this.labelStyle||'', //2
44547 this.elementStyle||'', //3
44548 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
44549 f.itemCls||this.itemCls||'' //5
44550 ], true).getPrevSibling());
44554 renderComponent : function(c){
44555 c.render(c.isLayout ? this.el : this.el.createChild());
44558 * Adds a object form elements (using the xtype property as the factory method.)
44559 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
44560 * @param {Object} config
44562 addxtype : function(o)
44564 // create the lement.
44565 o.form = this.form;
44566 var fe = Roo.factory(o, Roo.form);
44567 this.form.allItems.push(fe);
44568 this.stack.push(fe);
44570 if (fe.isFormField) {
44571 this.form.items.add(fe);
44579 * @class Roo.form.Column
44580 * @extends Roo.form.Layout
44581 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
44583 * @param {Object} config Configuration options
44585 Roo.form.Column = function(config){
44586 Roo.form.Column.superclass.constructor.call(this, config);
44589 Roo.extend(Roo.form.Column, Roo.form.Layout, {
44591 * @cfg {Number/String} width
44592 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44595 * @cfg {String/Object} autoCreate
44596 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
44600 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
44603 onRender : function(ct, position){
44604 Roo.form.Column.superclass.onRender.call(this, ct, position);
44606 this.el.setWidth(this.width);
44613 * @class Roo.form.Row
44614 * @extends Roo.form.Layout
44615 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
44617 * @param {Object} config Configuration options
44621 Roo.form.Row = function(config){
44622 Roo.form.Row.superclass.constructor.call(this, config);
44625 Roo.extend(Roo.form.Row, Roo.form.Layout, {
44627 * @cfg {Number/String} width
44628 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44631 * @cfg {Number/String} height
44632 * The fixed height of the column in pixels or CSS value (defaults to "auto")
44634 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
44638 onRender : function(ct, position){
44639 //console.log('row render');
44641 var t = new Roo.Template(
44642 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
44643 '<label for="{0}" style="{2}">{1}{4}</label>',
44644 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44648 t.disableFormats = true;
44650 Roo.form.Layout.prototype.rowTpl = t;
44652 this.fieldTpl = this.rowTpl;
44654 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
44655 var labelWidth = 100;
44657 if ((this.labelAlign != 'top')) {
44658 if (typeof this.labelWidth == 'number') {
44659 labelWidth = this.labelWidth
44661 this.padWidth = 20 + labelWidth;
44665 Roo.form.Column.superclass.onRender.call(this, ct, position);
44667 this.el.setWidth(this.width);
44670 this.el.setHeight(this.height);
44675 renderField : function(f){
44676 f.fieldEl = this.fieldTpl.append(this.el, [
44677 f.id, f.fieldLabel,
44678 f.labelStyle||this.labelStyle||'',
44679 this.elementStyle||'',
44680 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
44681 f.itemCls||this.itemCls||'',
44682 f.width ? f.width + this.padWidth : 160 + this.padWidth
44689 * @class Roo.form.FieldSet
44690 * @extends Roo.form.Layout
44691 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
44693 * @param {Object} config Configuration options
44695 Roo.form.FieldSet = function(config){
44696 Roo.form.FieldSet.superclass.constructor.call(this, config);
44699 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
44701 * @cfg {String} legend
44702 * The text to display as the legend for the FieldSet (defaults to '')
44705 * @cfg {String/Object} autoCreate
44706 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
44710 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
44713 onRender : function(ct, position){
44714 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
44716 this.setLegend(this.legend);
44721 setLegend : function(text){
44723 this.el.child('legend').update(text);
44728 * Ext JS Library 1.1.1
44729 * Copyright(c) 2006-2007, Ext JS, LLC.
44731 * Originally Released Under LGPL - original licence link has changed is not relivant.
44734 * <script type="text/javascript">
44737 * @class Roo.form.VTypes
44738 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
44741 Roo.form.VTypes = function(){
44742 // closure these in so they are only created once.
44743 var alpha = /^[a-zA-Z_]+$/;
44744 var alphanum = /^[a-zA-Z0-9_]+$/;
44745 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
44746 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
44748 // All these messages and functions are configurable
44751 * The function used to validate email addresses
44752 * @param {String} value The email address
44754 'email' : function(v){
44755 return email.test(v);
44758 * The error text to display when the email validation function returns false
44761 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
44763 * The keystroke filter mask to be applied on email input
44766 'emailMask' : /[a-z0-9_\.\-@]/i,
44769 * The function used to validate URLs
44770 * @param {String} value The URL
44772 'url' : function(v){
44773 return url.test(v);
44776 * The error text to display when the url validation function returns false
44779 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
44782 * The function used to validate alpha values
44783 * @param {String} value The value
44785 'alpha' : function(v){
44786 return alpha.test(v);
44789 * The error text to display when the alpha validation function returns false
44792 'alphaText' : 'This field should only contain letters and _',
44794 * The keystroke filter mask to be applied on alpha input
44797 'alphaMask' : /[a-z_]/i,
44800 * The function used to validate alphanumeric values
44801 * @param {String} value The value
44803 'alphanum' : function(v){
44804 return alphanum.test(v);
44807 * The error text to display when the alphanumeric validation function returns false
44810 'alphanumText' : 'This field should only contain letters, numbers and _',
44812 * The keystroke filter mask to be applied on alphanumeric input
44815 'alphanumMask' : /[a-z0-9_]/i
44817 }();//<script type="text/javascript">
44820 * @class Roo.form.FCKeditor
44821 * @extends Roo.form.TextArea
44822 * Wrapper around the FCKEditor http://www.fckeditor.net
44824 * Creates a new FCKeditor
44825 * @param {Object} config Configuration options
44827 Roo.form.FCKeditor = function(config){
44828 Roo.form.FCKeditor.superclass.constructor.call(this, config);
44831 * @event editorinit
44832 * Fired when the editor is initialized - you can add extra handlers here..
44833 * @param {FCKeditor} this
44834 * @param {Object} the FCK object.
44841 Roo.form.FCKeditor.editors = { };
44842 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
44844 //defaultAutoCreate : {
44845 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
44849 * @cfg {Object} fck options - see fck manual for details.
44854 * @cfg {Object} fck toolbar set (Basic or Default)
44856 toolbarSet : 'Basic',
44858 * @cfg {Object} fck BasePath
44860 basePath : '/fckeditor/',
44868 onRender : function(ct, position)
44871 this.defaultAutoCreate = {
44873 style:"width:300px;height:60px;",
44874 autocomplete: "off"
44877 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
44880 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
44881 if(this.preventScrollbars){
44882 this.el.setStyle("overflow", "hidden");
44884 this.el.setHeight(this.growMin);
44887 //console.log('onrender' + this.getId() );
44888 Roo.form.FCKeditor.editors[this.getId()] = this;
44891 this.replaceTextarea() ;
44895 getEditor : function() {
44896 return this.fckEditor;
44899 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
44900 * @param {Mixed} value The value to set
44904 setValue : function(value)
44906 //console.log('setValue: ' + value);
44908 if(typeof(value) == 'undefined') { // not sure why this is happending...
44911 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44913 //if(!this.el || !this.getEditor()) {
44914 // this.value = value;
44915 //this.setValue.defer(100,this,[value]);
44919 if(!this.getEditor()) {
44923 this.getEditor().SetData(value);
44930 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
44931 * @return {Mixed} value The field value
44933 getValue : function()
44936 if (this.frame && this.frame.dom.style.display == 'none') {
44937 return Roo.form.FCKeditor.superclass.getValue.call(this);
44940 if(!this.el || !this.getEditor()) {
44942 // this.getValue.defer(100,this);
44947 var value=this.getEditor().GetData();
44948 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44949 return Roo.form.FCKeditor.superclass.getValue.call(this);
44955 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
44956 * @return {Mixed} value The field value
44958 getRawValue : function()
44960 if (this.frame && this.frame.dom.style.display == 'none') {
44961 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44964 if(!this.el || !this.getEditor()) {
44965 //this.getRawValue.defer(100,this);
44972 var value=this.getEditor().GetData();
44973 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
44974 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44978 setSize : function(w,h) {
44982 //if (this.frame && this.frame.dom.style.display == 'none') {
44983 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44986 //if(!this.el || !this.getEditor()) {
44987 // this.setSize.defer(100,this, [w,h]);
44993 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44995 this.frame.dom.setAttribute('width', w);
44996 this.frame.dom.setAttribute('height', h);
44997 this.frame.setSize(w,h);
45001 toggleSourceEdit : function(value) {
45005 this.el.dom.style.display = value ? '' : 'none';
45006 this.frame.dom.style.display = value ? 'none' : '';
45011 focus: function(tag)
45013 if (this.frame.dom.style.display == 'none') {
45014 return Roo.form.FCKeditor.superclass.focus.call(this);
45016 if(!this.el || !this.getEditor()) {
45017 this.focus.defer(100,this, [tag]);
45024 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
45025 this.getEditor().Focus();
45027 if (!this.getEditor().Selection.GetSelection()) {
45028 this.focus.defer(100,this, [tag]);
45033 var r = this.getEditor().EditorDocument.createRange();
45034 r.setStart(tgs[0],0);
45035 r.setEnd(tgs[0],0);
45036 this.getEditor().Selection.GetSelection().removeAllRanges();
45037 this.getEditor().Selection.GetSelection().addRange(r);
45038 this.getEditor().Focus();
45045 replaceTextarea : function()
45047 if ( document.getElementById( this.getId() + '___Frame' ) )
45049 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
45051 // We must check the elements firstly using the Id and then the name.
45052 var oTextarea = document.getElementById( this.getId() );
45054 var colElementsByName = document.getElementsByName( this.getId() ) ;
45056 oTextarea.style.display = 'none' ;
45058 if ( oTextarea.tabIndex ) {
45059 this.TabIndex = oTextarea.tabIndex ;
45062 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
45063 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
45064 this.frame = Roo.get(this.getId() + '___Frame')
45067 _getConfigHtml : function()
45071 for ( var o in this.fckconfig ) {
45072 sConfig += sConfig.length > 0 ? '&' : '';
45073 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
45076 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
45080 _getIFrameHtml : function()
45082 var sFile = 'fckeditor.html' ;
45083 /* no idea what this is about..
45086 if ( (/fcksource=true/i).test( window.top.location.search ) )
45087 sFile = 'fckeditor.original.html' ;
45092 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
45093 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
45096 var html = '<iframe id="' + this.getId() +
45097 '___Frame" src="' + sLink +
45098 '" width="' + this.width +
45099 '" height="' + this.height + '"' +
45100 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
45101 ' frameborder="0" scrolling="no"></iframe>' ;
45106 _insertHtmlBefore : function( html, element )
45108 if ( element.insertAdjacentHTML ) {
45110 element.insertAdjacentHTML( 'beforeBegin', html ) ;
45112 var oRange = document.createRange() ;
45113 oRange.setStartBefore( element ) ;
45114 var oFragment = oRange.createContextualFragment( html );
45115 element.parentNode.insertBefore( oFragment, element ) ;
45128 //Roo.reg('fckeditor', Roo.form.FCKeditor);
45130 function FCKeditor_OnComplete(editorInstance){
45131 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
45132 f.fckEditor = editorInstance;
45133 //console.log("loaded");
45134 f.fireEvent('editorinit', f, editorInstance);
45154 //<script type="text/javascript">
45156 * @class Roo.form.GridField
45157 * @extends Roo.form.Field
45158 * Embed a grid (or editable grid into a form)
45161 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
45163 * xgrid.store = Roo.data.Store
45164 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
45165 * xgrid.store.reader = Roo.data.JsonReader
45169 * Creates a new GridField
45170 * @param {Object} config Configuration options
45172 Roo.form.GridField = function(config){
45173 Roo.form.GridField.superclass.constructor.call(this, config);
45177 Roo.extend(Roo.form.GridField, Roo.form.Field, {
45179 * @cfg {Number} width - used to restrict width of grid..
45183 * @cfg {Number} height - used to restrict height of grid..
45187 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
45193 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45194 * {tag: "input", type: "checkbox", autocomplete: "off"})
45196 // defaultAutoCreate : { tag: 'div' },
45197 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45199 * @cfg {String} addTitle Text to include for adding a title.
45203 onResize : function(){
45204 Roo.form.Field.superclass.onResize.apply(this, arguments);
45207 initEvents : function(){
45208 // Roo.form.Checkbox.superclass.initEvents.call(this);
45209 // has no events...
45214 getResizeEl : function(){
45218 getPositionEl : function(){
45223 onRender : function(ct, position){
45225 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
45226 var style = this.style;
45229 Roo.form.GridField.superclass.onRender.call(this, ct, position);
45230 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
45231 this.viewEl = this.wrap.createChild({ tag: 'div' });
45233 this.viewEl.applyStyles(style);
45236 this.viewEl.setWidth(this.width);
45239 this.viewEl.setHeight(this.height);
45241 //if(this.inputValue !== undefined){
45242 //this.setValue(this.value);
45245 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
45248 this.grid.render();
45249 this.grid.getDataSource().on('remove', this.refreshValue, this);
45250 this.grid.getDataSource().on('update', this.refreshValue, this);
45251 this.grid.on('afteredit', this.refreshValue, this);
45257 * Sets the value of the item.
45258 * @param {String} either an object or a string..
45260 setValue : function(v){
45262 v = v || []; // empty set..
45263 // this does not seem smart - it really only affects memoryproxy grids..
45264 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
45265 var ds = this.grid.getDataSource();
45266 // assumes a json reader..
45268 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
45269 ds.loadData( data);
45271 // clear selection so it does not get stale.
45272 if (this.grid.sm) {
45273 this.grid.sm.clearSelections();
45276 Roo.form.GridField.superclass.setValue.call(this, v);
45277 this.refreshValue();
45278 // should load data in the grid really....
45282 refreshValue: function() {
45284 this.grid.getDataSource().each(function(r) {
45287 this.el.dom.value = Roo.encode(val);
45295 * Ext JS Library 1.1.1
45296 * Copyright(c) 2006-2007, Ext JS, LLC.
45298 * Originally Released Under LGPL - original licence link has changed is not relivant.
45301 * <script type="text/javascript">
45304 * @class Roo.form.DisplayField
45305 * @extends Roo.form.Field
45306 * A generic Field to display non-editable data.
45308 * Creates a new Display Field item.
45309 * @param {Object} config Configuration options
45311 Roo.form.DisplayField = function(config){
45312 Roo.form.DisplayField.superclass.constructor.call(this, config);
45316 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
45317 inputType: 'hidden',
45323 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45325 focusClass : undefined,
45327 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45329 fieldClass: 'x-form-field',
45332 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
45334 valueRenderer: undefined,
45338 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45339 * {tag: "input", type: "checkbox", autocomplete: "off"})
45342 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45344 onResize : function(){
45345 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
45349 initEvents : function(){
45350 // Roo.form.Checkbox.superclass.initEvents.call(this);
45351 // has no events...
45356 getResizeEl : function(){
45360 getPositionEl : function(){
45365 onRender : function(ct, position){
45367 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
45368 //if(this.inputValue !== undefined){
45369 this.wrap = this.el.wrap();
45371 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
45373 if (this.bodyStyle) {
45374 this.viewEl.applyStyles(this.bodyStyle);
45376 //this.viewEl.setStyle('padding', '2px');
45378 this.setValue(this.value);
45383 initValue : Roo.emptyFn,
45388 onClick : function(){
45393 * Sets the checked state of the checkbox.
45394 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
45396 setValue : function(v){
45398 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
45399 // this might be called before we have a dom element..
45400 if (!this.viewEl) {
45403 this.viewEl.dom.innerHTML = html;
45404 Roo.form.DisplayField.superclass.setValue.call(this, v);
45414 * @class Roo.form.DayPicker
45415 * @extends Roo.form.Field
45416 * A Day picker show [M] [T] [W] ....
45418 * Creates a new Day Picker
45419 * @param {Object} config Configuration options
45421 Roo.form.DayPicker= function(config){
45422 Roo.form.DayPicker.superclass.constructor.call(this, config);
45426 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
45428 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45430 focusClass : undefined,
45432 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45434 fieldClass: "x-form-field",
45437 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45438 * {tag: "input", type: "checkbox", autocomplete: "off"})
45440 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
45443 actionMode : 'viewEl',
45447 inputType : 'hidden',
45450 inputElement: false, // real input element?
45451 basedOn: false, // ????
45453 isFormField: true, // not sure where this is needed!!!!
45455 onResize : function(){
45456 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
45457 if(!this.boxLabel){
45458 this.el.alignTo(this.wrap, 'c-c');
45462 initEvents : function(){
45463 Roo.form.Checkbox.superclass.initEvents.call(this);
45464 this.el.on("click", this.onClick, this);
45465 this.el.on("change", this.onClick, this);
45469 getResizeEl : function(){
45473 getPositionEl : function(){
45479 onRender : function(ct, position){
45480 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
45482 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
45484 var r1 = '<table><tr>';
45485 var r2 = '<tr class="x-form-daypick-icons">';
45486 for (var i=0; i < 7; i++) {
45487 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
45488 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
45491 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
45492 viewEl.select('img').on('click', this.onClick, this);
45493 this.viewEl = viewEl;
45496 // this will not work on Chrome!!!
45497 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
45498 this.el.on('propertychange', this.setFromHidden, this); //ie
45506 initValue : Roo.emptyFn,
45509 * Returns the checked state of the checkbox.
45510 * @return {Boolean} True if checked, else false
45512 getValue : function(){
45513 return this.el.dom.value;
45518 onClick : function(e){
45519 //this.setChecked(!this.checked);
45520 Roo.get(e.target).toggleClass('x-menu-item-checked');
45521 this.refreshValue();
45522 //if(this.el.dom.checked != this.checked){
45523 // this.setValue(this.el.dom.checked);
45528 refreshValue : function()
45531 this.viewEl.select('img',true).each(function(e,i,n) {
45532 val += e.is(".x-menu-item-checked") ? String(n) : '';
45534 this.setValue(val, true);
45538 * Sets the checked state of the checkbox.
45539 * On is always based on a string comparison between inputValue and the param.
45540 * @param {Boolean/String} value - the value to set
45541 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
45543 setValue : function(v,suppressEvent){
45544 if (!this.el.dom) {
45547 var old = this.el.dom.value ;
45548 this.el.dom.value = v;
45549 if (suppressEvent) {
45553 // update display..
45554 this.viewEl.select('img',true).each(function(e,i,n) {
45556 var on = e.is(".x-menu-item-checked");
45557 var newv = v.indexOf(String(n)) > -1;
45559 e.toggleClass('x-menu-item-checked');
45565 this.fireEvent('change', this, v, old);
45570 // handle setting of hidden value by some other method!!?!?
45571 setFromHidden: function()
45576 //console.log("SET FROM HIDDEN");
45577 //alert('setFrom hidden');
45578 this.setValue(this.el.dom.value);
45581 onDestroy : function()
45584 Roo.get(this.viewEl).remove();
45587 Roo.form.DayPicker.superclass.onDestroy.call(this);
45591 * RooJS Library 1.1.1
45592 * Copyright(c) 2008-2011 Alan Knowles
45599 * @class Roo.form.ComboCheck
45600 * @extends Roo.form.ComboBox
45601 * A combobox for multiple select items.
45603 * FIXME - could do with a reset button..
45606 * Create a new ComboCheck
45607 * @param {Object} config Configuration options
45609 Roo.form.ComboCheck = function(config){
45610 Roo.form.ComboCheck.superclass.constructor.call(this, config);
45611 // should verify some data...
45613 // hiddenName = required..
45614 // displayField = required
45615 // valudField == required
45616 var req= [ 'hiddenName', 'displayField', 'valueField' ];
45618 Roo.each(req, function(e) {
45619 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
45620 throw "Roo.form.ComboCheck : missing value for: " + e;
45627 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
45632 selectedClass: 'x-menu-item-checked',
45635 onRender : function(ct, position){
45641 var cls = 'x-combo-list';
45644 this.tpl = new Roo.Template({
45645 html : '<div class="'+cls+'-item x-menu-check-item">' +
45646 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
45647 '<span>{' + this.displayField + '}</span>' +
45654 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
45655 this.view.singleSelect = false;
45656 this.view.multiSelect = true;
45657 this.view.toggleSelect = true;
45658 this.pageTb.add(new Roo.Toolbar.Fill(), {
45661 handler: function()
45668 onViewOver : function(e, t){
45674 onViewClick : function(doFocus,index){
45678 select: function () {
45679 //Roo.log("SELECT CALLED");
45682 selectByValue : function(xv, scrollIntoView){
45683 var ar = this.getValueArray();
45686 Roo.each(ar, function(v) {
45687 if(v === undefined || v === null){
45690 var r = this.findRecord(this.valueField, v);
45692 sels.push(this.store.indexOf(r))
45696 this.view.select(sels);
45702 onSelect : function(record, index){
45703 // Roo.log("onselect Called");
45704 // this is only called by the clear button now..
45705 this.view.clearSelections();
45706 this.setValue('[]');
45707 if (this.value != this.valueBefore) {
45708 this.fireEvent('change', this, this.value, this.valueBefore);
45709 this.valueBefore = this.value;
45712 getValueArray : function()
45717 //Roo.log(this.value);
45718 if (typeof(this.value) == 'undefined') {
45721 var ar = Roo.decode(this.value);
45722 return ar instanceof Array ? ar : []; //?? valid?
45725 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
45730 expand : function ()
45733 Roo.form.ComboCheck.superclass.expand.call(this);
45734 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
45735 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
45740 collapse : function(){
45741 Roo.form.ComboCheck.superclass.collapse.call(this);
45742 var sl = this.view.getSelectedIndexes();
45743 var st = this.store;
45747 Roo.each(sl, function(i) {
45749 nv.push(r.get(this.valueField));
45751 this.setValue(Roo.encode(nv));
45752 if (this.value != this.valueBefore) {
45754 this.fireEvent('change', this, this.value, this.valueBefore);
45755 this.valueBefore = this.value;
45760 setValue : function(v){
45764 var vals = this.getValueArray();
45766 Roo.each(vals, function(k) {
45767 var r = this.findRecord(this.valueField, k);
45769 tv.push(r.data[this.displayField]);
45770 }else if(this.valueNotFoundText !== undefined){
45771 tv.push( this.valueNotFoundText );
45776 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
45777 this.hiddenField.value = v;
45783 * Ext JS Library 1.1.1
45784 * Copyright(c) 2006-2007, Ext JS, LLC.
45786 * Originally Released Under LGPL - original licence link has changed is not relivant.
45789 * <script type="text/javascript">
45793 * @class Roo.form.Signature
45794 * @extends Roo.form.Field
45798 * @param {Object} config Configuration options
45801 Roo.form.Signature = function(config){
45802 Roo.form.Signature.superclass.constructor.call(this, config);
45804 this.addEvents({// not in used??
45807 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
45808 * @param {Roo.form.Signature} combo This combo box
45813 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
45814 * @param {Roo.form.ComboBox} combo This combo box
45815 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
45821 Roo.extend(Roo.form.Signature, Roo.form.Field, {
45823 * @cfg {Object} labels Label to use when rendering a form.
45827 * confirm : "Confirm"
45832 confirm : "Confirm"
45835 * @cfg {Number} width The signature panel width (defaults to 300)
45839 * @cfg {Number} height The signature panel height (defaults to 100)
45843 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
45845 allowBlank : false,
45848 // {Object} signPanel The signature SVG panel element (defaults to {})
45850 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
45851 isMouseDown : false,
45852 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
45853 isConfirmed : false,
45854 // {String} signatureTmp SVG mapping string (defaults to empty string)
45858 defaultAutoCreate : { // modified by initCompnoent..
45864 onRender : function(ct, position){
45866 Roo.form.Signature.superclass.onRender.call(this, ct, position);
45868 this.wrap = this.el.wrap({
45869 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
45872 this.createToolbar(this);
45873 this.signPanel = this.wrap.createChild({
45875 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
45879 this.svgID = Roo.id();
45880 this.svgEl = this.signPanel.createChild({
45881 xmlns : 'http://www.w3.org/2000/svg',
45883 id : this.svgID + "-svg",
45885 height: this.height,
45886 viewBox: '0 0 '+this.width+' '+this.height,
45890 id: this.svgID + "-svg-r",
45892 height: this.height,
45897 id: this.svgID + "-svg-l",
45899 y1: (this.height*0.8), // start set the line in 80% of height
45900 x2: this.width, // end
45901 y2: (this.height*0.8), // end set the line in 80% of height
45903 'stroke-width': "1",
45904 'stroke-dasharray': "3",
45905 'shape-rendering': "crispEdges",
45906 'pointer-events': "none"
45910 id: this.svgID + "-svg-p",
45912 'stroke-width': "3",
45914 'pointer-events': 'none'
45919 this.svgBox = this.svgEl.dom.getScreenCTM();
45921 createSVG : function(){
45922 var svg = this.signPanel;
45923 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
45926 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
45927 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
45928 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
45929 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
45930 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
45931 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
45932 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
45935 isTouchEvent : function(e){
45936 return e.type.match(/^touch/);
45938 getCoords : function (e) {
45939 var pt = this.svgEl.dom.createSVGPoint();
45942 if (this.isTouchEvent(e)) {
45943 pt.x = e.targetTouches[0].clientX
45944 pt.y = e.targetTouches[0].clientY;
45946 var a = this.svgEl.dom.getScreenCTM();
45947 var b = a.inverse();
45948 var mx = pt.matrixTransform(b);
45949 return mx.x + ',' + mx.y;
45951 //mouse event headler
45952 down : function (e) {
45953 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
45954 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
45956 this.isMouseDown = true;
45958 e.preventDefault();
45960 move : function (e) {
45961 if (this.isMouseDown) {
45962 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
45963 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
45966 e.preventDefault();
45968 up : function (e) {
45969 this.isMouseDown = false;
45970 var sp = this.signatureTmp.split(' ');
45973 if(!sp[sp.length-2].match(/^L/)){
45977 this.signatureTmp = sp.join(" ");
45980 if(this.getValue() != this.signatureTmp){
45981 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
45982 this.isConfirmed = false;
45984 e.preventDefault();
45988 * Protected method that will not generally be called directly. It
45989 * is called when the editor creates its toolbar. Override this method if you need to
45990 * add custom toolbar buttons.
45991 * @param {HtmlEditor} editor
45993 createToolbar : function(editor){
45994 function btn(id, toggle, handler){
45995 var xid = fid + '-'+ id ;
45999 cls : 'x-btn-icon x-edit-'+id,
46000 enableToggle:toggle !== false,
46001 scope: editor, // was editor...
46002 handler:handler||editor.relayBtnCmd,
46003 clickEvent:'mousedown',
46004 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46010 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46014 cls : ' x-signature-btn x-signature-'+id,
46015 scope: editor, // was editor...
46016 handler: this.reset,
46017 clickEvent:'mousedown',
46018 text: this.labels.clear
46025 cls : ' x-signature-btn x-signature-'+id,
46026 scope: editor, // was editor...
46027 handler: this.confirmHandler,
46028 clickEvent:'mousedown',
46029 text: this.labels.confirm
46036 * when user is clicked confirm then show this image.....
46038 * @return {String} Image Data URI
46040 getImageDataURI : function(){
46041 var svg = this.svgEl.dom.parentNode.innerHTML;
46042 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
46047 * @return {Boolean} this.isConfirmed
46049 getConfirmed : function(){
46050 return this.isConfirmed;
46054 * @return {Number} this.width
46056 getWidth : function(){
46061 * @return {Number} this.height
46063 getHeight : function(){
46064 return this.height;
46067 getSignature : function(){
46068 return this.signatureTmp;
46071 reset : function(){
46072 this.signatureTmp = '';
46073 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46074 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
46075 this.isConfirmed = false;
46076 Roo.form.Signature.superclass.reset.call(this);
46078 setSignature : function(s){
46079 this.signatureTmp = s;
46080 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46081 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
46083 this.isConfirmed = false;
46084 Roo.form.Signature.superclass.reset.call(this);
46087 // Roo.log(this.signPanel.dom.contentWindow.up())
46090 setConfirmed : function(){
46094 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
46097 confirmHandler : function(){
46098 if(!this.getSignature()){
46102 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
46103 this.setValue(this.getSignature());
46104 this.isConfirmed = true;
46106 this.fireEvent('confirm', this);
46109 // Subclasses should provide the validation implementation by overriding this
46110 validateValue : function(value){
46111 if(this.allowBlank){
46115 if(this.isConfirmed){
46122 * Ext JS Library 1.1.1
46123 * Copyright(c) 2006-2007, Ext JS, LLC.
46125 * Originally Released Under LGPL - original licence link has changed is not relivant.
46128 * <script type="text/javascript">
46133 * @class Roo.form.ComboBox
46134 * @extends Roo.form.TriggerField
46135 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
46137 * Create a new ComboBox.
46138 * @param {Object} config Configuration options
46140 Roo.form.Select = function(config){
46141 Roo.form.Select.superclass.constructor.call(this, config);
46145 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
46147 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
46150 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
46151 * rendering into an Roo.Editor, defaults to false)
46154 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
46155 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
46158 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
46161 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
46162 * the dropdown list (defaults to undefined, with no header element)
46166 * @cfg {String/Roo.Template} tpl The template to use to render the output
46170 defaultAutoCreate : {tag: "select" },
46172 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
46174 listWidth: undefined,
46176 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
46177 * mode = 'remote' or 'text' if mode = 'local')
46179 displayField: undefined,
46181 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
46182 * mode = 'remote' or 'value' if mode = 'local').
46183 * Note: use of a valueField requires the user make a selection
46184 * in order for a value to be mapped.
46186 valueField: undefined,
46190 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
46191 * field's data value (defaults to the underlying DOM element's name)
46193 hiddenName: undefined,
46195 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
46199 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
46201 selectedClass: 'x-combo-selected',
46203 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
46204 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
46205 * which displays a downward arrow icon).
46207 triggerClass : 'x-form-arrow-trigger',
46209 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
46213 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
46214 * anchor positions (defaults to 'tl-bl')
46216 listAlign: 'tl-bl?',
46218 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
46222 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
46223 * query specified by the allQuery config option (defaults to 'query')
46225 triggerAction: 'query',
46227 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
46228 * (defaults to 4, does not apply if editable = false)
46232 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
46233 * delay (typeAheadDelay) if it matches a known value (defaults to false)
46237 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
46238 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
46242 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
46243 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
46247 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
46248 * when editable = true (defaults to false)
46250 selectOnFocus:false,
46252 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
46254 queryParam: 'query',
46256 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
46257 * when mode = 'remote' (defaults to 'Loading...')
46259 loadingText: 'Loading...',
46261 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
46265 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
46269 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
46270 * traditional select (defaults to true)
46274 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
46278 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
46282 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
46283 * listWidth has a higher value)
46287 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
46288 * allow the user to set arbitrary text into the field (defaults to false)
46290 forceSelection:false,
46292 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
46293 * if typeAhead = true (defaults to 250)
46295 typeAheadDelay : 250,
46297 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
46298 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
46300 valueNotFoundText : undefined,
46303 * @cfg {String} defaultValue The value displayed after loading the store.
46308 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
46310 blockFocus : false,
46313 * @cfg {Boolean} disableClear Disable showing of clear button.
46315 disableClear : false,
46317 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
46319 alwaysQuery : false,
46325 // element that contains real text value.. (when hidden is used..)
46328 onRender : function(ct, position){
46329 Roo.form.Field.prototype.onRender.call(this, ct, position);
46332 this.store.on('beforeload', this.onBeforeLoad, this);
46333 this.store.on('load', this.onLoad, this);
46334 this.store.on('loadexception', this.onLoadException, this);
46335 this.store.load({});
46343 initEvents : function(){
46344 //Roo.form.ComboBox.superclass.initEvents.call(this);
46348 onDestroy : function(){
46351 this.store.un('beforeload', this.onBeforeLoad, this);
46352 this.store.un('load', this.onLoad, this);
46353 this.store.un('loadexception', this.onLoadException, this);
46355 //Roo.form.ComboBox.superclass.onDestroy.call(this);
46359 fireKey : function(e){
46360 if(e.isNavKeyPress() && !this.list.isVisible()){
46361 this.fireEvent("specialkey", this, e);
46366 onResize: function(w, h){
46374 * Allow or prevent the user from directly editing the field text. If false is passed,
46375 * the user will only be able to select from the items defined in the dropdown list. This method
46376 * is the runtime equivalent of setting the 'editable' config option at config time.
46377 * @param {Boolean} value True to allow the user to directly edit the field text
46379 setEditable : function(value){
46384 onBeforeLoad : function(){
46386 Roo.log("Select before load");
46389 this.innerList.update(this.loadingText ?
46390 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
46391 //this.restrictHeight();
46392 this.selectedIndex = -1;
46396 onLoad : function(){
46399 var dom = this.el.dom;
46400 dom.innerHTML = '';
46401 var od = dom.ownerDocument;
46403 if (this.emptyText) {
46404 var op = od.createElement('option');
46405 op.setAttribute('value', '');
46406 op.innerHTML = String.format('{0}', this.emptyText);
46407 dom.appendChild(op);
46409 if(this.store.getCount() > 0){
46411 var vf = this.valueField;
46412 var df = this.displayField;
46413 this.store.data.each(function(r) {
46414 // which colmsn to use... testing - cdoe / title..
46415 var op = od.createElement('option');
46416 op.setAttribute('value', r.data[vf]);
46417 op.innerHTML = String.format('{0}', r.data[df]);
46418 dom.appendChild(op);
46420 if (typeof(this.defaultValue != 'undefined')) {
46421 this.setValue(this.defaultValue);
46426 //this.onEmptyResults();
46431 onLoadException : function()
46433 dom.innerHTML = '';
46435 Roo.log("Select on load exception");
46439 Roo.log(this.store.reader.jsonData);
46440 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
46441 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
46447 onTypeAhead : function(){
46452 onSelect : function(record, index){
46453 Roo.log('on select?');
46455 if(this.fireEvent('beforeselect', this, record, index) !== false){
46456 this.setFromData(index > -1 ? record.data : false);
46458 this.fireEvent('select', this, record, index);
46463 * Returns the currently selected field value or empty string if no value is set.
46464 * @return {String} value The selected value
46466 getValue : function(){
46467 var dom = this.el.dom;
46468 this.value = dom.options[dom.selectedIndex].value;
46474 * Clears any text/value currently set in the field
46476 clearValue : function(){
46478 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
46483 * Sets the specified value into the field. If the value finds a match, the corresponding record text
46484 * will be displayed in the field. If the value does not match the data value of an existing item,
46485 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
46486 * Otherwise the field will be blank (although the value will still be set).
46487 * @param {String} value The value to match
46489 setValue : function(v){
46490 var d = this.el.dom;
46491 for (var i =0; i < d.options.length;i++) {
46492 if (v == d.options[i].value) {
46493 d.selectedIndex = i;
46501 * @property {Object} the last set data for the element
46506 * Sets the value of the field based on a object which is related to the record format for the store.
46507 * @param {Object} value the value to set as. or false on reset?
46509 setFromData : function(o){
46510 Roo.log('setfrom data?');
46516 reset : function(){
46520 findRecord : function(prop, value){
46525 if(this.store.getCount() > 0){
46526 this.store.each(function(r){
46527 if(r.data[prop] == value){
46537 getName: function()
46539 // returns hidden if it's set..
46540 if (!this.rendered) {return ''};
46541 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
46549 onEmptyResults : function(){
46550 Roo.log('empty results');
46555 * Returns true if the dropdown list is expanded, else false.
46557 isExpanded : function(){
46562 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
46563 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
46564 * @param {String} value The data value of the item to select
46565 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
46566 * selected item if it is not currently in view (defaults to true)
46567 * @return {Boolean} True if the value matched an item in the list, else false
46569 selectByValue : function(v, scrollIntoView){
46570 Roo.log('select By Value');
46573 if(v !== undefined && v !== null){
46574 var r = this.findRecord(this.valueField || this.displayField, v);
46576 this.select(this.store.indexOf(r), scrollIntoView);
46584 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
46585 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
46586 * @param {Number} index The zero-based index of the list item to select
46587 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
46588 * selected item if it is not currently in view (defaults to true)
46590 select : function(index, scrollIntoView){
46591 Roo.log('select ');
46594 this.selectedIndex = index;
46595 this.view.select(index);
46596 if(scrollIntoView !== false){
46597 var el = this.view.getNode(index);
46599 this.innerList.scrollChildIntoView(el, false);
46607 validateBlur : function(){
46614 initQuery : function(){
46615 this.doQuery(this.getRawValue());
46619 doForce : function(){
46620 if(this.el.dom.value.length > 0){
46621 this.el.dom.value =
46622 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
46628 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
46629 * query allowing the query action to be canceled if needed.
46630 * @param {String} query The SQL query to execute
46631 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
46632 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
46633 * saved in the current store (defaults to false)
46635 doQuery : function(q, forceAll){
46637 Roo.log('doQuery?');
46638 if(q === undefined || q === null){
46643 forceAll: forceAll,
46647 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
46651 forceAll = qe.forceAll;
46652 if(forceAll === true || (q.length >= this.minChars)){
46653 if(this.lastQuery != q || this.alwaysQuery){
46654 this.lastQuery = q;
46655 if(this.mode == 'local'){
46656 this.selectedIndex = -1;
46658 this.store.clearFilter();
46660 this.store.filter(this.displayField, q);
46664 this.store.baseParams[this.queryParam] = q;
46666 params: this.getParams(q)
46671 this.selectedIndex = -1;
46678 getParams : function(q){
46680 //p[this.queryParam] = q;
46683 p.limit = this.pageSize;
46689 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
46691 collapse : function(){
46696 collapseIf : function(e){
46701 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
46703 expand : function(){
46711 * @cfg {Boolean} grow
46715 * @cfg {Number} growMin
46719 * @cfg {Number} growMax
46727 setWidth : function()
46731 getResizeEl : function(){
46734 });//<script type="text/javasscript">
46738 * @class Roo.DDView
46739 * A DnD enabled version of Roo.View.
46740 * @param {Element/String} container The Element in which to create the View.
46741 * @param {String} tpl The template string used to create the markup for each element of the View
46742 * @param {Object} config The configuration properties. These include all the config options of
46743 * {@link Roo.View} plus some specific to this class.<br>
46745 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
46746 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
46748 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
46749 .x-view-drag-insert-above {
46750 border-top:1px dotted #3366cc;
46752 .x-view-drag-insert-below {
46753 border-bottom:1px dotted #3366cc;
46759 Roo.DDView = function(container, tpl, config) {
46760 Roo.DDView.superclass.constructor.apply(this, arguments);
46761 this.getEl().setStyle("outline", "0px none");
46762 this.getEl().unselectable();
46763 if (this.dragGroup) {
46764 this.setDraggable(this.dragGroup.split(","));
46766 if (this.dropGroup) {
46767 this.setDroppable(this.dropGroup.split(","));
46769 if (this.deletable) {
46770 this.setDeletable();
46772 this.isDirtyFlag = false;
46778 Roo.extend(Roo.DDView, Roo.View, {
46779 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
46780 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
46781 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
46782 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
46786 reset: Roo.emptyFn,
46788 clearInvalid: Roo.form.Field.prototype.clearInvalid,
46790 validate: function() {
46794 destroy: function() {
46795 this.purgeListeners();
46796 this.getEl.removeAllListeners();
46797 this.getEl().remove();
46798 if (this.dragZone) {
46799 if (this.dragZone.destroy) {
46800 this.dragZone.destroy();
46803 if (this.dropZone) {
46804 if (this.dropZone.destroy) {
46805 this.dropZone.destroy();
46810 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
46811 getName: function() {
46815 /** Loads the View from a JSON string representing the Records to put into the Store. */
46816 setValue: function(v) {
46818 throw "DDView.setValue(). DDView must be constructed with a valid Store";
46821 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
46822 this.store.proxy = new Roo.data.MemoryProxy(data);
46826 /** @return {String} a parenthesised list of the ids of the Records in the View. */
46827 getValue: function() {
46829 this.store.each(function(rec) {
46830 result += rec.id + ',';
46832 return result.substr(0, result.length - 1) + ')';
46835 getIds: function() {
46836 var i = 0, result = new Array(this.store.getCount());
46837 this.store.each(function(rec) {
46838 result[i++] = rec.id;
46843 isDirty: function() {
46844 return this.isDirtyFlag;
46848 * Part of the Roo.dd.DropZone interface. If no target node is found, the
46849 * whole Element becomes the target, and this causes the drop gesture to append.
46851 getTargetFromEvent : function(e) {
46852 var target = e.getTarget();
46853 while ((target !== null) && (target.parentNode != this.el.dom)) {
46854 target = target.parentNode;
46857 target = this.el.dom.lastChild || this.el.dom;
46863 * Create the drag data which consists of an object which has the property "ddel" as
46864 * the drag proxy element.
46866 getDragData : function(e) {
46867 var target = this.findItemFromChild(e.getTarget());
46869 this.handleSelection(e);
46870 var selNodes = this.getSelectedNodes();
46873 copy: this.copy || (this.allowCopy && e.ctrlKey),
46877 var selectedIndices = this.getSelectedIndexes();
46878 for (var i = 0; i < selectedIndices.length; i++) {
46879 dragData.records.push(this.store.getAt(selectedIndices[i]));
46881 if (selNodes.length == 1) {
46882 dragData.ddel = target.cloneNode(true); // the div element
46884 var div = document.createElement('div'); // create the multi element drag "ghost"
46885 div.className = 'multi-proxy';
46886 for (var i = 0, len = selNodes.length; i < len; i++) {
46887 div.appendChild(selNodes[i].cloneNode(true));
46889 dragData.ddel = div;
46891 //console.log(dragData)
46892 //console.log(dragData.ddel.innerHTML)
46895 //console.log('nodragData')
46899 /** Specify to which ddGroup items in this DDView may be dragged. */
46900 setDraggable: function(ddGroup) {
46901 if (ddGroup instanceof Array) {
46902 Roo.each(ddGroup, this.setDraggable, this);
46905 if (this.dragZone) {
46906 this.dragZone.addToGroup(ddGroup);
46908 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
46909 containerScroll: true,
46913 // Draggability implies selection. DragZone's mousedown selects the element.
46914 if (!this.multiSelect) { this.singleSelect = true; }
46916 // Wire the DragZone's handlers up to methods in *this*
46917 this.dragZone.getDragData = this.getDragData.createDelegate(this);
46921 /** Specify from which ddGroup this DDView accepts drops. */
46922 setDroppable: function(ddGroup) {
46923 if (ddGroup instanceof Array) {
46924 Roo.each(ddGroup, this.setDroppable, this);
46927 if (this.dropZone) {
46928 this.dropZone.addToGroup(ddGroup);
46930 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
46931 containerScroll: true,
46935 // Wire the DropZone's handlers up to methods in *this*
46936 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
46937 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
46938 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
46939 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
46940 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
46944 /** Decide whether to drop above or below a View node. */
46945 getDropPoint : function(e, n, dd){
46946 if (n == this.el.dom) { return "above"; }
46947 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
46948 var c = t + (b - t) / 2;
46949 var y = Roo.lib.Event.getPageY(e);
46957 onNodeEnter : function(n, dd, e, data){
46961 onNodeOver : function(n, dd, e, data){
46962 var pt = this.getDropPoint(e, n, dd);
46963 // set the insert point style on the target node
46964 var dragElClass = this.dropNotAllowed;
46967 if (pt == "above"){
46968 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
46969 targetElClass = "x-view-drag-insert-above";
46971 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
46972 targetElClass = "x-view-drag-insert-below";
46974 if (this.lastInsertClass != targetElClass){
46975 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
46976 this.lastInsertClass = targetElClass;
46979 return dragElClass;
46982 onNodeOut : function(n, dd, e, data){
46983 this.removeDropIndicators(n);
46986 onNodeDrop : function(n, dd, e, data){
46987 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
46990 var pt = this.getDropPoint(e, n, dd);
46991 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
46992 if (pt == "below") { insertAt++; }
46993 for (var i = 0; i < data.records.length; i++) {
46994 var r = data.records[i];
46995 var dup = this.store.getById(r.id);
46996 if (dup && (dd != this.dragZone)) {
46997 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
47000 this.store.insert(insertAt++, r.copy());
47002 data.source.isDirtyFlag = true;
47004 this.store.insert(insertAt++, r);
47006 this.isDirtyFlag = true;
47009 this.dragZone.cachedTarget = null;
47013 removeDropIndicators : function(n){
47015 Roo.fly(n).removeClass([
47016 "x-view-drag-insert-above",
47017 "x-view-drag-insert-below"]);
47018 this.lastInsertClass = "_noclass";
47023 * Utility method. Add a delete option to the DDView's context menu.
47024 * @param {String} imageUrl The URL of the "delete" icon image.
47026 setDeletable: function(imageUrl) {
47027 if (!this.singleSelect && !this.multiSelect) {
47028 this.singleSelect = true;
47030 var c = this.getContextMenu();
47031 this.contextMenu.on("itemclick", function(item) {
47034 this.remove(this.getSelectedIndexes());
47038 this.contextMenu.add({
47045 /** Return the context menu for this DDView. */
47046 getContextMenu: function() {
47047 if (!this.contextMenu) {
47048 // Create the View's context menu
47049 this.contextMenu = new Roo.menu.Menu({
47050 id: this.id + "-contextmenu"
47052 this.el.on("contextmenu", this.showContextMenu, this);
47054 return this.contextMenu;
47057 disableContextMenu: function() {
47058 if (this.contextMenu) {
47059 this.el.un("contextmenu", this.showContextMenu, this);
47063 showContextMenu: function(e, item) {
47064 item = this.findItemFromChild(e.getTarget());
47067 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
47068 this.contextMenu.showAt(e.getXY());
47073 * Remove {@link Roo.data.Record}s at the specified indices.
47074 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
47076 remove: function(selectedIndices) {
47077 selectedIndices = [].concat(selectedIndices);
47078 for (var i = 0; i < selectedIndices.length; i++) {
47079 var rec = this.store.getAt(selectedIndices[i]);
47080 this.store.remove(rec);
47085 * Double click fires the event, but also, if this is draggable, and there is only one other
47086 * related DropZone, it transfers the selected node.
47088 onDblClick : function(e){
47089 var item = this.findItemFromChild(e.getTarget());
47091 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
47094 if (this.dragGroup) {
47095 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
47096 while (targets.indexOf(this.dropZone) > -1) {
47097 targets.remove(this.dropZone);
47099 if (targets.length == 1) {
47100 this.dragZone.cachedTarget = null;
47101 var el = Roo.get(targets[0].getEl());
47102 var box = el.getBox(true);
47103 targets[0].onNodeDrop(el.dom, {
47105 xy: [box.x, box.y + box.height - 1]
47106 }, null, this.getDragData(e));
47112 handleSelection: function(e) {
47113 this.dragZone.cachedTarget = null;
47114 var item = this.findItemFromChild(e.getTarget());
47116 this.clearSelections(true);
47119 if (item && (this.multiSelect || this.singleSelect)){
47120 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
47121 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
47122 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
47123 this.unselect(item);
47125 this.select(item, this.multiSelect && e.ctrlKey);
47126 this.lastSelection = item;
47131 onItemClick : function(item, index, e){
47132 if(this.fireEvent("beforeclick", this, index, item, e) === false){
47138 unselect : function(nodeInfo, suppressEvent){
47139 var node = this.getNode(nodeInfo);
47140 if(node && this.isSelected(node)){
47141 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
47142 Roo.fly(node).removeClass(this.selectedClass);
47143 this.selections.remove(node);
47144 if(!suppressEvent){
47145 this.fireEvent("selectionchange", this, this.selections);
47153 * Ext JS Library 1.1.1
47154 * Copyright(c) 2006-2007, Ext JS, LLC.
47156 * Originally Released Under LGPL - original licence link has changed is not relivant.
47159 * <script type="text/javascript">
47163 * @class Roo.LayoutManager
47164 * @extends Roo.util.Observable
47165 * Base class for layout managers.
47167 Roo.LayoutManager = function(container, config){
47168 Roo.LayoutManager.superclass.constructor.call(this);
47169 this.el = Roo.get(container);
47170 // ie scrollbar fix
47171 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
47172 document.body.scroll = "no";
47173 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
47174 this.el.position('relative');
47176 this.id = this.el.id;
47177 this.el.addClass("x-layout-container");
47178 /** false to disable window resize monitoring @type Boolean */
47179 this.monitorWindowResize = true;
47184 * Fires when a layout is performed.
47185 * @param {Roo.LayoutManager} this
47189 * @event regionresized
47190 * Fires when the user resizes a region.
47191 * @param {Roo.LayoutRegion} region The resized region
47192 * @param {Number} newSize The new size (width for east/west, height for north/south)
47194 "regionresized" : true,
47196 * @event regioncollapsed
47197 * Fires when a region is collapsed.
47198 * @param {Roo.LayoutRegion} region The collapsed region
47200 "regioncollapsed" : true,
47202 * @event regionexpanded
47203 * Fires when a region is expanded.
47204 * @param {Roo.LayoutRegion} region The expanded region
47206 "regionexpanded" : true
47208 this.updating = false;
47209 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47212 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
47214 * Returns true if this layout is currently being updated
47215 * @return {Boolean}
47217 isUpdating : function(){
47218 return this.updating;
47222 * Suspend the LayoutManager from doing auto-layouts while
47223 * making multiple add or remove calls
47225 beginUpdate : function(){
47226 this.updating = true;
47230 * Restore auto-layouts and optionally disable the manager from performing a layout
47231 * @param {Boolean} noLayout true to disable a layout update
47233 endUpdate : function(noLayout){
47234 this.updating = false;
47240 layout: function(){
47244 onRegionResized : function(region, newSize){
47245 this.fireEvent("regionresized", region, newSize);
47249 onRegionCollapsed : function(region){
47250 this.fireEvent("regioncollapsed", region);
47253 onRegionExpanded : function(region){
47254 this.fireEvent("regionexpanded", region);
47258 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
47259 * performs box-model adjustments.
47260 * @return {Object} The size as an object {width: (the width), height: (the height)}
47262 getViewSize : function(){
47264 if(this.el.dom != document.body){
47265 size = this.el.getSize();
47267 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
47269 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
47270 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
47275 * Returns the Element this layout is bound to.
47276 * @return {Roo.Element}
47278 getEl : function(){
47283 * Returns the specified region.
47284 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
47285 * @return {Roo.LayoutRegion}
47287 getRegion : function(target){
47288 return this.regions[target.toLowerCase()];
47291 onWindowResize : function(){
47292 if(this.monitorWindowResize){
47298 * Ext JS Library 1.1.1
47299 * Copyright(c) 2006-2007, Ext JS, LLC.
47301 * Originally Released Under LGPL - original licence link has changed is not relivant.
47304 * <script type="text/javascript">
47307 * @class Roo.BorderLayout
47308 * @extends Roo.LayoutManager
47309 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
47310 * please see: <br><br>
47311 * <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>
47312 * <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>
47315 var layout = new Roo.BorderLayout(document.body, {
47349 preferredTabWidth: 150
47354 var CP = Roo.ContentPanel;
47356 layout.beginUpdate();
47357 layout.add("north", new CP("north", "North"));
47358 layout.add("south", new CP("south", {title: "South", closable: true}));
47359 layout.add("west", new CP("west", {title: "West"}));
47360 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
47361 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
47362 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
47363 layout.getRegion("center").showPanel("center1");
47364 layout.endUpdate();
47367 <b>The container the layout is rendered into can be either the body element or any other element.
47368 If it is not the body element, the container needs to either be an absolute positioned element,
47369 or you will need to add "position:relative" to the css of the container. You will also need to specify
47370 the container size if it is not the body element.</b>
47373 * Create a new BorderLayout
47374 * @param {String/HTMLElement/Element} container The container this layout is bound to
47375 * @param {Object} config Configuration options
47377 Roo.BorderLayout = function(container, config){
47378 config = config || {};
47379 Roo.BorderLayout.superclass.constructor.call(this, container, config);
47380 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
47381 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
47382 var target = this.factory.validRegions[i];
47383 if(config[target]){
47384 this.addRegion(target, config[target]);
47389 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
47391 * Creates and adds a new region if it doesn't already exist.
47392 * @param {String} target The target region key (north, south, east, west or center).
47393 * @param {Object} config The regions config object
47394 * @return {BorderLayoutRegion} The new region
47396 addRegion : function(target, config){
47397 if(!this.regions[target]){
47398 var r = this.factory.create(target, this, config);
47399 this.bindRegion(target, r);
47401 return this.regions[target];
47405 bindRegion : function(name, r){
47406 this.regions[name] = r;
47407 r.on("visibilitychange", this.layout, this);
47408 r.on("paneladded", this.layout, this);
47409 r.on("panelremoved", this.layout, this);
47410 r.on("invalidated", this.layout, this);
47411 r.on("resized", this.onRegionResized, this);
47412 r.on("collapsed", this.onRegionCollapsed, this);
47413 r.on("expanded", this.onRegionExpanded, this);
47417 * Performs a layout update.
47419 layout : function(){
47420 if(this.updating) return;
47421 var size = this.getViewSize();
47422 var w = size.width;
47423 var h = size.height;
47428 //var x = 0, y = 0;
47430 var rs = this.regions;
47431 var north = rs["north"];
47432 var south = rs["south"];
47433 var west = rs["west"];
47434 var east = rs["east"];
47435 var center = rs["center"];
47436 //if(this.hideOnLayout){ // not supported anymore
47437 //c.el.setStyle("display", "none");
47439 if(north && north.isVisible()){
47440 var b = north.getBox();
47441 var m = north.getMargins();
47442 b.width = w - (m.left+m.right);
47445 centerY = b.height + b.y + m.bottom;
47446 centerH -= centerY;
47447 north.updateBox(this.safeBox(b));
47449 if(south && south.isVisible()){
47450 var b = south.getBox();
47451 var m = south.getMargins();
47452 b.width = w - (m.left+m.right);
47454 var totalHeight = (b.height + m.top + m.bottom);
47455 b.y = h - totalHeight + m.top;
47456 centerH -= totalHeight;
47457 south.updateBox(this.safeBox(b));
47459 if(west && west.isVisible()){
47460 var b = west.getBox();
47461 var m = west.getMargins();
47462 b.height = centerH - (m.top+m.bottom);
47464 b.y = centerY + m.top;
47465 var totalWidth = (b.width + m.left + m.right);
47466 centerX += totalWidth;
47467 centerW -= totalWidth;
47468 west.updateBox(this.safeBox(b));
47470 if(east && east.isVisible()){
47471 var b = east.getBox();
47472 var m = east.getMargins();
47473 b.height = centerH - (m.top+m.bottom);
47474 var totalWidth = (b.width + m.left + m.right);
47475 b.x = w - totalWidth + m.left;
47476 b.y = centerY + m.top;
47477 centerW -= totalWidth;
47478 east.updateBox(this.safeBox(b));
47481 var m = center.getMargins();
47483 x: centerX + m.left,
47484 y: centerY + m.top,
47485 width: centerW - (m.left+m.right),
47486 height: centerH - (m.top+m.bottom)
47488 //if(this.hideOnLayout){
47489 //center.el.setStyle("display", "block");
47491 center.updateBox(this.safeBox(centerBox));
47494 this.fireEvent("layout", this);
47498 safeBox : function(box){
47499 box.width = Math.max(0, box.width);
47500 box.height = Math.max(0, box.height);
47505 * Adds a ContentPanel (or subclass) to this layout.
47506 * @param {String} target The target region key (north, south, east, west or center).
47507 * @param {Roo.ContentPanel} panel The panel to add
47508 * @return {Roo.ContentPanel} The added panel
47510 add : function(target, panel){
47512 target = target.toLowerCase();
47513 return this.regions[target].add(panel);
47517 * Remove a ContentPanel (or subclass) to this layout.
47518 * @param {String} target The target region key (north, south, east, west or center).
47519 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
47520 * @return {Roo.ContentPanel} The removed panel
47522 remove : function(target, panel){
47523 target = target.toLowerCase();
47524 return this.regions[target].remove(panel);
47528 * Searches all regions for a panel with the specified id
47529 * @param {String} panelId
47530 * @return {Roo.ContentPanel} The panel or null if it wasn't found
47532 findPanel : function(panelId){
47533 var rs = this.regions;
47534 for(var target in rs){
47535 if(typeof rs[target] != "function"){
47536 var p = rs[target].getPanel(panelId);
47546 * Searches all regions for a panel with the specified id and activates (shows) it.
47547 * @param {String/ContentPanel} panelId The panels id or the panel itself
47548 * @return {Roo.ContentPanel} The shown panel or null
47550 showPanel : function(panelId) {
47551 var rs = this.regions;
47552 for(var target in rs){
47553 var r = rs[target];
47554 if(typeof r != "function"){
47555 if(r.hasPanel(panelId)){
47556 return r.showPanel(panelId);
47564 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
47565 * @param {Roo.state.Provider} provider (optional) An alternate state provider
47567 restoreState : function(provider){
47569 provider = Roo.state.Manager;
47571 var sm = new Roo.LayoutStateManager();
47572 sm.init(this, provider);
47576 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
47577 * object should contain properties for each region to add ContentPanels to, and each property's value should be
47578 * a valid ContentPanel config object. Example:
47580 // Create the main layout
47581 var layout = new Roo.BorderLayout('main-ct', {
47592 // Create and add multiple ContentPanels at once via configs
47595 id: 'source-files',
47597 title:'Ext Source Files',
47610 * @param {Object} regions An object containing ContentPanel configs by region name
47612 batchAdd : function(regions){
47613 this.beginUpdate();
47614 for(var rname in regions){
47615 var lr = this.regions[rname];
47617 this.addTypedPanels(lr, regions[rname]);
47624 addTypedPanels : function(lr, ps){
47625 if(typeof ps == 'string'){
47626 lr.add(new Roo.ContentPanel(ps));
47628 else if(ps instanceof Array){
47629 for(var i =0, len = ps.length; i < len; i++){
47630 this.addTypedPanels(lr, ps[i]);
47633 else if(!ps.events){ // raw config?
47635 delete ps.el; // prevent conflict
47636 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
47638 else { // panel object assumed!
47643 * Adds a xtype elements to the layout.
47647 xtype : 'ContentPanel',
47654 xtype : 'NestedLayoutPanel',
47660 items : [ ... list of content panels or nested layout panels.. ]
47664 * @param {Object} cfg Xtype definition of item to add.
47666 addxtype : function(cfg)
47668 // basically accepts a pannel...
47669 // can accept a layout region..!?!?
47670 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
47672 if (!cfg.xtype.match(/Panel$/)) {
47677 if (typeof(cfg.region) == 'undefined') {
47678 Roo.log("Failed to add Panel, region was not set");
47682 var region = cfg.region;
47688 xitems = cfg.items;
47695 case 'ContentPanel': // ContentPanel (el, cfg)
47696 case 'ScrollPanel': // ContentPanel (el, cfg)
47698 if(cfg.autoCreate) {
47699 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
47701 var el = this.el.createChild();
47702 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
47705 this.add(region, ret);
47709 case 'TreePanel': // our new panel!
47710 cfg.el = this.el.createChild();
47711 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
47712 this.add(region, ret);
47715 case 'NestedLayoutPanel':
47716 // create a new Layout (which is a Border Layout...
47717 var el = this.el.createChild();
47718 var clayout = cfg.layout;
47720 clayout.items = clayout.items || [];
47721 // replace this exitems with the clayout ones..
47722 xitems = clayout.items;
47725 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
47726 cfg.background = false;
47728 var layout = new Roo.BorderLayout(el, clayout);
47730 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
47731 //console.log('adding nested layout panel ' + cfg.toSource());
47732 this.add(region, ret);
47733 nb = {}; /// find first...
47738 // needs grid and region
47740 //var el = this.getRegion(region).el.createChild();
47741 var el = this.el.createChild();
47742 // create the grid first...
47744 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
47746 if (region == 'center' && this.active ) {
47747 cfg.background = false;
47749 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
47751 this.add(region, ret);
47752 if (cfg.background) {
47753 ret.on('activate', function(gp) {
47754 if (!gp.grid.rendered) {
47769 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
47771 // GridPanel (grid, cfg)
47774 this.beginUpdate();
47778 Roo.each(xitems, function(i) {
47779 region = nb && i.region ? i.region : false;
47781 var add = ret.addxtype(i);
47784 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
47785 if (!i.background) {
47786 abn[region] = nb[region] ;
47793 // make the last non-background panel active..
47794 //if (nb) { Roo.log(abn); }
47797 for(var r in abn) {
47798 region = this.getRegion(r);
47800 // tried using nb[r], but it does not work..
47802 region.showPanel(abn[r]);
47813 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
47814 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
47815 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
47816 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
47819 var CP = Roo.ContentPanel;
47821 var layout = Roo.BorderLayout.create({
47825 panels: [new CP("north", "North")]
47834 panels: [new CP("west", {title: "West"})]
47843 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
47852 panels: [new CP("south", {title: "South", closable: true})]
47859 preferredTabWidth: 150,
47861 new CP("center1", {title: "Close Me", closable: true}),
47862 new CP("center2", {title: "Center Panel", closable: false})
47867 layout.getRegion("center").showPanel("center1");
47872 Roo.BorderLayout.create = function(config, targetEl){
47873 var layout = new Roo.BorderLayout(targetEl || document.body, config);
47874 layout.beginUpdate();
47875 var regions = Roo.BorderLayout.RegionFactory.validRegions;
47876 for(var j = 0, jlen = regions.length; j < jlen; j++){
47877 var lr = regions[j];
47878 if(layout.regions[lr] && config[lr].panels){
47879 var r = layout.regions[lr];
47880 var ps = config[lr].panels;
47881 layout.addTypedPanels(r, ps);
47884 layout.endUpdate();
47889 Roo.BorderLayout.RegionFactory = {
47891 validRegions : ["north","south","east","west","center"],
47894 create : function(target, mgr, config){
47895 target = target.toLowerCase();
47896 if(config.lightweight || config.basic){
47897 return new Roo.BasicLayoutRegion(mgr, config, target);
47901 return new Roo.NorthLayoutRegion(mgr, config);
47903 return new Roo.SouthLayoutRegion(mgr, config);
47905 return new Roo.EastLayoutRegion(mgr, config);
47907 return new Roo.WestLayoutRegion(mgr, config);
47909 return new Roo.CenterLayoutRegion(mgr, config);
47911 throw 'Layout region "'+target+'" not supported.';
47915 * Ext JS Library 1.1.1
47916 * Copyright(c) 2006-2007, Ext JS, LLC.
47918 * Originally Released Under LGPL - original licence link has changed is not relivant.
47921 * <script type="text/javascript">
47925 * @class Roo.BasicLayoutRegion
47926 * @extends Roo.util.Observable
47927 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
47928 * and does not have a titlebar, tabs or any other features. All it does is size and position
47929 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
47931 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
47933 this.position = pos;
47936 * @scope Roo.BasicLayoutRegion
47940 * @event beforeremove
47941 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
47942 * @param {Roo.LayoutRegion} this
47943 * @param {Roo.ContentPanel} panel The panel
47944 * @param {Object} e The cancel event object
47946 "beforeremove" : true,
47948 * @event invalidated
47949 * Fires when the layout for this region is changed.
47950 * @param {Roo.LayoutRegion} this
47952 "invalidated" : true,
47954 * @event visibilitychange
47955 * Fires when this region is shown or hidden
47956 * @param {Roo.LayoutRegion} this
47957 * @param {Boolean} visibility true or false
47959 "visibilitychange" : true,
47961 * @event paneladded
47962 * Fires when a panel is added.
47963 * @param {Roo.LayoutRegion} this
47964 * @param {Roo.ContentPanel} panel The panel
47966 "paneladded" : true,
47968 * @event panelremoved
47969 * Fires when a panel is removed.
47970 * @param {Roo.LayoutRegion} this
47971 * @param {Roo.ContentPanel} panel The panel
47973 "panelremoved" : true,
47976 * Fires when this region is collapsed.
47977 * @param {Roo.LayoutRegion} this
47979 "collapsed" : true,
47982 * Fires when this region is expanded.
47983 * @param {Roo.LayoutRegion} this
47988 * Fires when this region is slid into view.
47989 * @param {Roo.LayoutRegion} this
47991 "slideshow" : true,
47994 * Fires when this region slides out of view.
47995 * @param {Roo.LayoutRegion} this
47997 "slidehide" : true,
47999 * @event panelactivated
48000 * Fires when a panel is activated.
48001 * @param {Roo.LayoutRegion} this
48002 * @param {Roo.ContentPanel} panel The activated panel
48004 "panelactivated" : true,
48007 * Fires when the user resizes this region.
48008 * @param {Roo.LayoutRegion} this
48009 * @param {Number} newSize The new size (width for east/west, height for north/south)
48013 /** A collection of panels in this region. @type Roo.util.MixedCollection */
48014 this.panels = new Roo.util.MixedCollection();
48015 this.panels.getKey = this.getPanelId.createDelegate(this);
48017 this.activePanel = null;
48018 // ensure listeners are added...
48020 if (config.listeners || config.events) {
48021 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
48022 listeners : config.listeners || {},
48023 events : config.events || {}
48027 if(skipConfig !== true){
48028 this.applyConfig(config);
48032 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
48033 getPanelId : function(p){
48037 applyConfig : function(config){
48038 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48039 this.config = config;
48044 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
48045 * the width, for horizontal (north, south) the height.
48046 * @param {Number} newSize The new width or height
48048 resizeTo : function(newSize){
48049 var el = this.el ? this.el :
48050 (this.activePanel ? this.activePanel.getEl() : null);
48052 switch(this.position){
48055 el.setWidth(newSize);
48056 this.fireEvent("resized", this, newSize);
48060 el.setHeight(newSize);
48061 this.fireEvent("resized", this, newSize);
48067 getBox : function(){
48068 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
48071 getMargins : function(){
48072 return this.margins;
48075 updateBox : function(box){
48077 var el = this.activePanel.getEl();
48078 el.dom.style.left = box.x + "px";
48079 el.dom.style.top = box.y + "px";
48080 this.activePanel.setSize(box.width, box.height);
48084 * Returns the container element for this region.
48085 * @return {Roo.Element}
48087 getEl : function(){
48088 return this.activePanel;
48092 * Returns true if this region is currently visible.
48093 * @return {Boolean}
48095 isVisible : function(){
48096 return this.activePanel ? true : false;
48099 setActivePanel : function(panel){
48100 panel = this.getPanel(panel);
48101 if(this.activePanel && this.activePanel != panel){
48102 this.activePanel.setActiveState(false);
48103 this.activePanel.getEl().setLeftTop(-10000,-10000);
48105 this.activePanel = panel;
48106 panel.setActiveState(true);
48108 panel.setSize(this.box.width, this.box.height);
48110 this.fireEvent("panelactivated", this, panel);
48111 this.fireEvent("invalidated");
48115 * Show the specified panel.
48116 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
48117 * @return {Roo.ContentPanel} The shown panel or null
48119 showPanel : function(panel){
48120 if(panel = this.getPanel(panel)){
48121 this.setActivePanel(panel);
48127 * Get the active panel for this region.
48128 * @return {Roo.ContentPanel} The active panel or null
48130 getActivePanel : function(){
48131 return this.activePanel;
48135 * Add the passed ContentPanel(s)
48136 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48137 * @return {Roo.ContentPanel} The panel added (if only one was added)
48139 add : function(panel){
48140 if(arguments.length > 1){
48141 for(var i = 0, len = arguments.length; i < len; i++) {
48142 this.add(arguments[i]);
48146 if(this.hasPanel(panel)){
48147 this.showPanel(panel);
48150 var el = panel.getEl();
48151 if(el.dom.parentNode != this.mgr.el.dom){
48152 this.mgr.el.dom.appendChild(el.dom);
48154 if(panel.setRegion){
48155 panel.setRegion(this);
48157 this.panels.add(panel);
48158 el.setStyle("position", "absolute");
48159 if(!panel.background){
48160 this.setActivePanel(panel);
48161 if(this.config.initialSize && this.panels.getCount()==1){
48162 this.resizeTo(this.config.initialSize);
48165 this.fireEvent("paneladded", this, panel);
48170 * Returns true if the panel is in this region.
48171 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48172 * @return {Boolean}
48174 hasPanel : function(panel){
48175 if(typeof panel == "object"){ // must be panel obj
48176 panel = panel.getId();
48178 return this.getPanel(panel) ? true : false;
48182 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48183 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48184 * @param {Boolean} preservePanel Overrides the config preservePanel option
48185 * @return {Roo.ContentPanel} The panel that was removed
48187 remove : function(panel, preservePanel){
48188 panel = this.getPanel(panel);
48193 this.fireEvent("beforeremove", this, panel, e);
48194 if(e.cancel === true){
48197 var panelId = panel.getId();
48198 this.panels.removeKey(panelId);
48203 * Returns the panel specified or null if it's not in this region.
48204 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48205 * @return {Roo.ContentPanel}
48207 getPanel : function(id){
48208 if(typeof id == "object"){ // must be panel obj
48211 return this.panels.get(id);
48215 * Returns this regions position (north/south/east/west/center).
48218 getPosition: function(){
48219 return this.position;
48223 * Ext JS Library 1.1.1
48224 * Copyright(c) 2006-2007, Ext JS, LLC.
48226 * Originally Released Under LGPL - original licence link has changed is not relivant.
48229 * <script type="text/javascript">
48233 * @class Roo.LayoutRegion
48234 * @extends Roo.BasicLayoutRegion
48235 * This class represents a region in a layout manager.
48236 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
48237 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
48238 * @cfg {Boolean} floatable False to disable floating (defaults to true)
48239 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
48240 * @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})
48241 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
48242 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
48243 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
48244 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
48245 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
48246 * @cfg {String} title The title for the region (overrides panel titles)
48247 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
48248 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
48249 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
48250 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
48251 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
48252 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
48253 * the space available, similar to FireFox 1.5 tabs (defaults to false)
48254 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
48255 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
48256 * @cfg {Boolean} showPin True to show a pin button
48257 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
48258 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
48259 * @cfg {Boolean} disableTabTips True to disable tab tooltips
48260 * @cfg {Number} width For East/West panels
48261 * @cfg {Number} height For North/South panels
48262 * @cfg {Boolean} split To show the splitter
48263 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
48265 Roo.LayoutRegion = function(mgr, config, pos){
48266 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
48267 var dh = Roo.DomHelper;
48268 /** This region's container element
48269 * @type Roo.Element */
48270 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
48271 /** This region's title element
48272 * @type Roo.Element */
48274 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
48275 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
48276 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
48278 this.titleEl.enableDisplayMode();
48279 /** This region's title text element
48280 * @type HTMLElement */
48281 this.titleTextEl = this.titleEl.dom.firstChild;
48282 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
48283 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
48284 this.closeBtn.enableDisplayMode();
48285 this.closeBtn.on("click", this.closeClicked, this);
48286 this.closeBtn.hide();
48288 this.createBody(config);
48289 this.visible = true;
48290 this.collapsed = false;
48292 if(config.hideWhenEmpty){
48294 this.on("paneladded", this.validateVisibility, this);
48295 this.on("panelremoved", this.validateVisibility, this);
48297 this.applyConfig(config);
48300 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
48302 createBody : function(){
48303 /** This region's body element
48304 * @type Roo.Element */
48305 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
48308 applyConfig : function(c){
48309 if(c.collapsible && this.position != "center" && !this.collapsedEl){
48310 var dh = Roo.DomHelper;
48311 if(c.titlebar !== false){
48312 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
48313 this.collapseBtn.on("click", this.collapse, this);
48314 this.collapseBtn.enableDisplayMode();
48316 if(c.showPin === true || this.showPin){
48317 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
48318 this.stickBtn.enableDisplayMode();
48319 this.stickBtn.on("click", this.expand, this);
48320 this.stickBtn.hide();
48323 /** This region's collapsed element
48324 * @type Roo.Element */
48325 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
48326 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
48328 if(c.floatable !== false){
48329 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
48330 this.collapsedEl.on("click", this.collapseClick, this);
48333 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
48334 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
48335 id: "message", unselectable: "on", style:{"float":"left"}});
48336 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
48338 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
48339 this.expandBtn.on("click", this.expand, this);
48341 if(this.collapseBtn){
48342 this.collapseBtn.setVisible(c.collapsible == true);
48344 this.cmargins = c.cmargins || this.cmargins ||
48345 (this.position == "west" || this.position == "east" ?
48346 {top: 0, left: 2, right:2, bottom: 0} :
48347 {top: 2, left: 0, right:0, bottom: 2});
48348 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48349 this.bottomTabs = c.tabPosition != "top";
48350 this.autoScroll = c.autoScroll || false;
48351 if(this.autoScroll){
48352 this.bodyEl.setStyle("overflow", "auto");
48354 this.bodyEl.setStyle("overflow", "hidden");
48356 //if(c.titlebar !== false){
48357 if((!c.titlebar && !c.title) || c.titlebar === false){
48358 this.titleEl.hide();
48360 this.titleEl.show();
48362 this.titleTextEl.innerHTML = c.title;
48366 this.duration = c.duration || .30;
48367 this.slideDuration = c.slideDuration || .45;
48370 this.collapse(true);
48377 * Returns true if this region is currently visible.
48378 * @return {Boolean}
48380 isVisible : function(){
48381 return this.visible;
48385 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
48386 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
48388 setCollapsedTitle : function(title){
48389 title = title || " ";
48390 if(this.collapsedTitleTextEl){
48391 this.collapsedTitleTextEl.innerHTML = title;
48395 getBox : function(){
48397 if(!this.collapsed){
48398 b = this.el.getBox(false, true);
48400 b = this.collapsedEl.getBox(false, true);
48405 getMargins : function(){
48406 return this.collapsed ? this.cmargins : this.margins;
48409 highlight : function(){
48410 this.el.addClass("x-layout-panel-dragover");
48413 unhighlight : function(){
48414 this.el.removeClass("x-layout-panel-dragover");
48417 updateBox : function(box){
48419 if(!this.collapsed){
48420 this.el.dom.style.left = box.x + "px";
48421 this.el.dom.style.top = box.y + "px";
48422 this.updateBody(box.width, box.height);
48424 this.collapsedEl.dom.style.left = box.x + "px";
48425 this.collapsedEl.dom.style.top = box.y + "px";
48426 this.collapsedEl.setSize(box.width, box.height);
48429 this.tabs.autoSizeTabs();
48433 updateBody : function(w, h){
48435 this.el.setWidth(w);
48436 w -= this.el.getBorderWidth("rl");
48437 if(this.config.adjustments){
48438 w += this.config.adjustments[0];
48442 this.el.setHeight(h);
48443 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
48444 h -= this.el.getBorderWidth("tb");
48445 if(this.config.adjustments){
48446 h += this.config.adjustments[1];
48448 this.bodyEl.setHeight(h);
48450 h = this.tabs.syncHeight(h);
48453 if(this.panelSize){
48454 w = w !== null ? w : this.panelSize.width;
48455 h = h !== null ? h : this.panelSize.height;
48457 if(this.activePanel){
48458 var el = this.activePanel.getEl();
48459 w = w !== null ? w : el.getWidth();
48460 h = h !== null ? h : el.getHeight();
48461 this.panelSize = {width: w, height: h};
48462 this.activePanel.setSize(w, h);
48464 if(Roo.isIE && this.tabs){
48465 this.tabs.el.repaint();
48470 * Returns the container element for this region.
48471 * @return {Roo.Element}
48473 getEl : function(){
48478 * Hides this region.
48481 if(!this.collapsed){
48482 this.el.dom.style.left = "-2000px";
48485 this.collapsedEl.dom.style.left = "-2000px";
48486 this.collapsedEl.hide();
48488 this.visible = false;
48489 this.fireEvent("visibilitychange", this, false);
48493 * Shows this region if it was previously hidden.
48496 if(!this.collapsed){
48499 this.collapsedEl.show();
48501 this.visible = true;
48502 this.fireEvent("visibilitychange", this, true);
48505 closeClicked : function(){
48506 if(this.activePanel){
48507 this.remove(this.activePanel);
48511 collapseClick : function(e){
48513 e.stopPropagation();
48516 e.stopPropagation();
48522 * Collapses this region.
48523 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
48525 collapse : function(skipAnim){
48526 if(this.collapsed) return;
48527 this.collapsed = true;
48529 this.split.el.hide();
48531 if(this.config.animate && skipAnim !== true){
48532 this.fireEvent("invalidated", this);
48533 this.animateCollapse();
48535 this.el.setLocation(-20000,-20000);
48537 this.collapsedEl.show();
48538 this.fireEvent("collapsed", this);
48539 this.fireEvent("invalidated", this);
48543 animateCollapse : function(){
48548 * Expands this region if it was previously collapsed.
48549 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
48550 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
48552 expand : function(e, skipAnim){
48553 if(e) e.stopPropagation();
48554 if(!this.collapsed || this.el.hasActiveFx()) return;
48556 this.afterSlideIn();
48559 this.collapsed = false;
48560 if(this.config.animate && skipAnim !== true){
48561 this.animateExpand();
48565 this.split.el.show();
48567 this.collapsedEl.setLocation(-2000,-2000);
48568 this.collapsedEl.hide();
48569 this.fireEvent("invalidated", this);
48570 this.fireEvent("expanded", this);
48574 animateExpand : function(){
48578 initTabs : function()
48580 this.bodyEl.setStyle("overflow", "hidden");
48581 var ts = new Roo.TabPanel(
48584 tabPosition: this.bottomTabs ? 'bottom' : 'top',
48585 disableTooltips: this.config.disableTabTips,
48586 toolbar : this.config.toolbar
48589 if(this.config.hideTabs){
48590 ts.stripWrap.setDisplayed(false);
48593 ts.resizeTabs = this.config.resizeTabs === true;
48594 ts.minTabWidth = this.config.minTabWidth || 40;
48595 ts.maxTabWidth = this.config.maxTabWidth || 250;
48596 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
48597 ts.monitorResize = false;
48598 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
48599 ts.bodyEl.addClass('x-layout-tabs-body');
48600 this.panels.each(this.initPanelAsTab, this);
48603 initPanelAsTab : function(panel){
48604 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
48605 this.config.closeOnTab && panel.isClosable());
48606 if(panel.tabTip !== undefined){
48607 ti.setTooltip(panel.tabTip);
48609 ti.on("activate", function(){
48610 this.setActivePanel(panel);
48612 if(this.config.closeOnTab){
48613 ti.on("beforeclose", function(t, e){
48615 this.remove(panel);
48621 updatePanelTitle : function(panel, title){
48622 if(this.activePanel == panel){
48623 this.updateTitle(title);
48626 var ti = this.tabs.getTab(panel.getEl().id);
48628 if(panel.tabTip !== undefined){
48629 ti.setTooltip(panel.tabTip);
48634 updateTitle : function(title){
48635 if(this.titleTextEl && !this.config.title){
48636 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
48640 setActivePanel : function(panel){
48641 panel = this.getPanel(panel);
48642 if(this.activePanel && this.activePanel != panel){
48643 this.activePanel.setActiveState(false);
48645 this.activePanel = panel;
48646 panel.setActiveState(true);
48647 if(this.panelSize){
48648 panel.setSize(this.panelSize.width, this.panelSize.height);
48651 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
48653 this.updateTitle(panel.getTitle());
48655 this.fireEvent("invalidated", this);
48657 this.fireEvent("panelactivated", this, panel);
48661 * Shows the specified panel.
48662 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
48663 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
48665 showPanel : function(panel){
48666 if(panel = this.getPanel(panel)){
48668 var tab = this.tabs.getTab(panel.getEl().id);
48669 if(tab.isHidden()){
48670 this.tabs.unhideTab(tab.id);
48674 this.setActivePanel(panel);
48681 * Get the active panel for this region.
48682 * @return {Roo.ContentPanel} The active panel or null
48684 getActivePanel : function(){
48685 return this.activePanel;
48688 validateVisibility : function(){
48689 if(this.panels.getCount() < 1){
48690 this.updateTitle(" ");
48691 this.closeBtn.hide();
48694 if(!this.isVisible()){
48701 * Adds the passed ContentPanel(s) to this region.
48702 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48703 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
48705 add : function(panel){
48706 if(arguments.length > 1){
48707 for(var i = 0, len = arguments.length; i < len; i++) {
48708 this.add(arguments[i]);
48712 if(this.hasPanel(panel)){
48713 this.showPanel(panel);
48716 panel.setRegion(this);
48717 this.panels.add(panel);
48718 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
48719 this.bodyEl.dom.appendChild(panel.getEl().dom);
48720 if(panel.background !== true){
48721 this.setActivePanel(panel);
48723 this.fireEvent("paneladded", this, panel);
48729 this.initPanelAsTab(panel);
48731 if(panel.background !== true){
48732 this.tabs.activate(panel.getEl().id);
48734 this.fireEvent("paneladded", this, panel);
48739 * Hides the tab for the specified panel.
48740 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48742 hidePanel : function(panel){
48743 if(this.tabs && (panel = this.getPanel(panel))){
48744 this.tabs.hideTab(panel.getEl().id);
48749 * Unhides the tab for a previously hidden panel.
48750 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48752 unhidePanel : function(panel){
48753 if(this.tabs && (panel = this.getPanel(panel))){
48754 this.tabs.unhideTab(panel.getEl().id);
48758 clearPanels : function(){
48759 while(this.panels.getCount() > 0){
48760 this.remove(this.panels.first());
48765 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48766 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48767 * @param {Boolean} preservePanel Overrides the config preservePanel option
48768 * @return {Roo.ContentPanel} The panel that was removed
48770 remove : function(panel, preservePanel){
48771 panel = this.getPanel(panel);
48776 this.fireEvent("beforeremove", this, panel, e);
48777 if(e.cancel === true){
48780 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
48781 var panelId = panel.getId();
48782 this.panels.removeKey(panelId);
48784 document.body.appendChild(panel.getEl().dom);
48787 this.tabs.removeTab(panel.getEl().id);
48788 }else if (!preservePanel){
48789 this.bodyEl.dom.removeChild(panel.getEl().dom);
48791 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
48792 var p = this.panels.first();
48793 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
48794 tempEl.appendChild(p.getEl().dom);
48795 this.bodyEl.update("");
48796 this.bodyEl.dom.appendChild(p.getEl().dom);
48798 this.updateTitle(p.getTitle());
48800 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
48801 this.setActivePanel(p);
48803 panel.setRegion(null);
48804 if(this.activePanel == panel){
48805 this.activePanel = null;
48807 if(this.config.autoDestroy !== false && preservePanel !== true){
48808 try{panel.destroy();}catch(e){}
48810 this.fireEvent("panelremoved", this, panel);
48815 * Returns the TabPanel component used by this region
48816 * @return {Roo.TabPanel}
48818 getTabs : function(){
48822 createTool : function(parentEl, className){
48823 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
48824 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
48825 btn.addClassOnOver("x-layout-tools-button-over");
48830 * Ext JS Library 1.1.1
48831 * Copyright(c) 2006-2007, Ext JS, LLC.
48833 * Originally Released Under LGPL - original licence link has changed is not relivant.
48836 * <script type="text/javascript">
48842 * @class Roo.SplitLayoutRegion
48843 * @extends Roo.LayoutRegion
48844 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
48846 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
48847 this.cursor = cursor;
48848 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
48851 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
48852 splitTip : "Drag to resize.",
48853 collapsibleSplitTip : "Drag to resize. Double click to hide.",
48854 useSplitTips : false,
48856 applyConfig : function(config){
48857 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
48860 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
48861 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
48862 /** The SplitBar for this region
48863 * @type Roo.SplitBar */
48864 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
48865 this.split.on("moved", this.onSplitMove, this);
48866 this.split.useShim = config.useShim === true;
48867 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
48868 if(this.useSplitTips){
48869 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
48871 if(config.collapsible){
48872 this.split.el.on("dblclick", this.collapse, this);
48875 if(typeof config.minSize != "undefined"){
48876 this.split.minSize = config.minSize;
48878 if(typeof config.maxSize != "undefined"){
48879 this.split.maxSize = config.maxSize;
48881 if(config.hideWhenEmpty || config.hidden || config.collapsed){
48882 this.hideSplitter();
48887 getHMaxSize : function(){
48888 var cmax = this.config.maxSize || 10000;
48889 var center = this.mgr.getRegion("center");
48890 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
48893 getVMaxSize : function(){
48894 var cmax = this.config.maxSize || 10000;
48895 var center = this.mgr.getRegion("center");
48896 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
48899 onSplitMove : function(split, newSize){
48900 this.fireEvent("resized", this, newSize);
48904 * Returns the {@link Roo.SplitBar} for this region.
48905 * @return {Roo.SplitBar}
48907 getSplitBar : function(){
48912 this.hideSplitter();
48913 Roo.SplitLayoutRegion.superclass.hide.call(this);
48916 hideSplitter : function(){
48918 this.split.el.setLocation(-2000,-2000);
48919 this.split.el.hide();
48925 this.split.el.show();
48927 Roo.SplitLayoutRegion.superclass.show.call(this);
48930 beforeSlide: function(){
48931 if(Roo.isGecko){// firefox overflow auto bug workaround
48932 this.bodyEl.clip();
48933 if(this.tabs) this.tabs.bodyEl.clip();
48934 if(this.activePanel){
48935 this.activePanel.getEl().clip();
48937 if(this.activePanel.beforeSlide){
48938 this.activePanel.beforeSlide();
48944 afterSlide : function(){
48945 if(Roo.isGecko){// firefox overflow auto bug workaround
48946 this.bodyEl.unclip();
48947 if(this.tabs) this.tabs.bodyEl.unclip();
48948 if(this.activePanel){
48949 this.activePanel.getEl().unclip();
48950 if(this.activePanel.afterSlide){
48951 this.activePanel.afterSlide();
48957 initAutoHide : function(){
48958 if(this.autoHide !== false){
48959 if(!this.autoHideHd){
48960 var st = new Roo.util.DelayedTask(this.slideIn, this);
48961 this.autoHideHd = {
48962 "mouseout": function(e){
48963 if(!e.within(this.el, true)){
48967 "mouseover" : function(e){
48973 this.el.on(this.autoHideHd);
48977 clearAutoHide : function(){
48978 if(this.autoHide !== false){
48979 this.el.un("mouseout", this.autoHideHd.mouseout);
48980 this.el.un("mouseover", this.autoHideHd.mouseover);
48984 clearMonitor : function(){
48985 Roo.get(document).un("click", this.slideInIf, this);
48988 // these names are backwards but not changed for compat
48989 slideOut : function(){
48990 if(this.isSlid || this.el.hasActiveFx()){
48993 this.isSlid = true;
48994 if(this.collapseBtn){
48995 this.collapseBtn.hide();
48997 this.closeBtnState = this.closeBtn.getStyle('display');
48998 this.closeBtn.hide();
49000 this.stickBtn.show();
49003 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
49004 this.beforeSlide();
49005 this.el.setStyle("z-index", 10001);
49006 this.el.slideIn(this.getSlideAnchor(), {
49007 callback: function(){
49009 this.initAutoHide();
49010 Roo.get(document).on("click", this.slideInIf, this);
49011 this.fireEvent("slideshow", this);
49018 afterSlideIn : function(){
49019 this.clearAutoHide();
49020 this.isSlid = false;
49021 this.clearMonitor();
49022 this.el.setStyle("z-index", "");
49023 if(this.collapseBtn){
49024 this.collapseBtn.show();
49026 this.closeBtn.setStyle('display', this.closeBtnState);
49028 this.stickBtn.hide();
49030 this.fireEvent("slidehide", this);
49033 slideIn : function(cb){
49034 if(!this.isSlid || this.el.hasActiveFx()){
49038 this.isSlid = false;
49039 this.beforeSlide();
49040 this.el.slideOut(this.getSlideAnchor(), {
49041 callback: function(){
49042 this.el.setLeftTop(-10000, -10000);
49044 this.afterSlideIn();
49052 slideInIf : function(e){
49053 if(!e.within(this.el)){
49058 animateCollapse : function(){
49059 this.beforeSlide();
49060 this.el.setStyle("z-index", 20000);
49061 var anchor = this.getSlideAnchor();
49062 this.el.slideOut(anchor, {
49063 callback : function(){
49064 this.el.setStyle("z-index", "");
49065 this.collapsedEl.slideIn(anchor, {duration:.3});
49067 this.el.setLocation(-10000,-10000);
49069 this.fireEvent("collapsed", this);
49076 animateExpand : function(){
49077 this.beforeSlide();
49078 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
49079 this.el.setStyle("z-index", 20000);
49080 this.collapsedEl.hide({
49083 this.el.slideIn(this.getSlideAnchor(), {
49084 callback : function(){
49085 this.el.setStyle("z-index", "");
49088 this.split.el.show();
49090 this.fireEvent("invalidated", this);
49091 this.fireEvent("expanded", this);
49119 getAnchor : function(){
49120 return this.anchors[this.position];
49123 getCollapseAnchor : function(){
49124 return this.canchors[this.position];
49127 getSlideAnchor : function(){
49128 return this.sanchors[this.position];
49131 getAlignAdj : function(){
49132 var cm = this.cmargins;
49133 switch(this.position){
49149 getExpandAdj : function(){
49150 var c = this.collapsedEl, cm = this.cmargins;
49151 switch(this.position){
49153 return [-(cm.right+c.getWidth()+cm.left), 0];
49156 return [cm.right+c.getWidth()+cm.left, 0];
49159 return [0, -(cm.top+cm.bottom+c.getHeight())];
49162 return [0, cm.top+cm.bottom+c.getHeight()];
49168 * Ext JS Library 1.1.1
49169 * Copyright(c) 2006-2007, Ext JS, LLC.
49171 * Originally Released Under LGPL - original licence link has changed is not relivant.
49174 * <script type="text/javascript">
49177 * These classes are private internal classes
49179 Roo.CenterLayoutRegion = function(mgr, config){
49180 Roo.LayoutRegion.call(this, mgr, config, "center");
49181 this.visible = true;
49182 this.minWidth = config.minWidth || 20;
49183 this.minHeight = config.minHeight || 20;
49186 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
49188 // center panel can't be hidden
49192 // center panel can't be hidden
49195 getMinWidth: function(){
49196 return this.minWidth;
49199 getMinHeight: function(){
49200 return this.minHeight;
49205 Roo.NorthLayoutRegion = function(mgr, config){
49206 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
49208 this.split.placement = Roo.SplitBar.TOP;
49209 this.split.orientation = Roo.SplitBar.VERTICAL;
49210 this.split.el.addClass("x-layout-split-v");
49212 var size = config.initialSize || config.height;
49213 if(typeof size != "undefined"){
49214 this.el.setHeight(size);
49217 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
49218 orientation: Roo.SplitBar.VERTICAL,
49219 getBox : function(){
49220 if(this.collapsed){
49221 return this.collapsedEl.getBox();
49223 var box = this.el.getBox();
49225 box.height += this.split.el.getHeight();
49230 updateBox : function(box){
49231 if(this.split && !this.collapsed){
49232 box.height -= this.split.el.getHeight();
49233 this.split.el.setLeft(box.x);
49234 this.split.el.setTop(box.y+box.height);
49235 this.split.el.setWidth(box.width);
49237 if(this.collapsed){
49238 this.updateBody(box.width, null);
49240 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49244 Roo.SouthLayoutRegion = function(mgr, config){
49245 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
49247 this.split.placement = Roo.SplitBar.BOTTOM;
49248 this.split.orientation = Roo.SplitBar.VERTICAL;
49249 this.split.el.addClass("x-layout-split-v");
49251 var size = config.initialSize || config.height;
49252 if(typeof size != "undefined"){
49253 this.el.setHeight(size);
49256 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
49257 orientation: Roo.SplitBar.VERTICAL,
49258 getBox : function(){
49259 if(this.collapsed){
49260 return this.collapsedEl.getBox();
49262 var box = this.el.getBox();
49264 var sh = this.split.el.getHeight();
49271 updateBox : function(box){
49272 if(this.split && !this.collapsed){
49273 var sh = this.split.el.getHeight();
49276 this.split.el.setLeft(box.x);
49277 this.split.el.setTop(box.y-sh);
49278 this.split.el.setWidth(box.width);
49280 if(this.collapsed){
49281 this.updateBody(box.width, null);
49283 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49287 Roo.EastLayoutRegion = function(mgr, config){
49288 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
49290 this.split.placement = Roo.SplitBar.RIGHT;
49291 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49292 this.split.el.addClass("x-layout-split-h");
49294 var size = config.initialSize || config.width;
49295 if(typeof size != "undefined"){
49296 this.el.setWidth(size);
49299 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
49300 orientation: Roo.SplitBar.HORIZONTAL,
49301 getBox : function(){
49302 if(this.collapsed){
49303 return this.collapsedEl.getBox();
49305 var box = this.el.getBox();
49307 var sw = this.split.el.getWidth();
49314 updateBox : function(box){
49315 if(this.split && !this.collapsed){
49316 var sw = this.split.el.getWidth();
49318 this.split.el.setLeft(box.x);
49319 this.split.el.setTop(box.y);
49320 this.split.el.setHeight(box.height);
49323 if(this.collapsed){
49324 this.updateBody(null, box.height);
49326 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49330 Roo.WestLayoutRegion = function(mgr, config){
49331 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
49333 this.split.placement = Roo.SplitBar.LEFT;
49334 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49335 this.split.el.addClass("x-layout-split-h");
49337 var size = config.initialSize || config.width;
49338 if(typeof size != "undefined"){
49339 this.el.setWidth(size);
49342 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
49343 orientation: Roo.SplitBar.HORIZONTAL,
49344 getBox : function(){
49345 if(this.collapsed){
49346 return this.collapsedEl.getBox();
49348 var box = this.el.getBox();
49350 box.width += this.split.el.getWidth();
49355 updateBox : function(box){
49356 if(this.split && !this.collapsed){
49357 var sw = this.split.el.getWidth();
49359 this.split.el.setLeft(box.x+box.width);
49360 this.split.el.setTop(box.y);
49361 this.split.el.setHeight(box.height);
49363 if(this.collapsed){
49364 this.updateBody(null, box.height);
49366 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49371 * Ext JS Library 1.1.1
49372 * Copyright(c) 2006-2007, Ext JS, LLC.
49374 * Originally Released Under LGPL - original licence link has changed is not relivant.
49377 * <script type="text/javascript">
49382 * Private internal class for reading and applying state
49384 Roo.LayoutStateManager = function(layout){
49385 // default empty state
49394 Roo.LayoutStateManager.prototype = {
49395 init : function(layout, provider){
49396 this.provider = provider;
49397 var state = provider.get(layout.id+"-layout-state");
49399 var wasUpdating = layout.isUpdating();
49401 layout.beginUpdate();
49403 for(var key in state){
49404 if(typeof state[key] != "function"){
49405 var rstate = state[key];
49406 var r = layout.getRegion(key);
49409 r.resizeTo(rstate.size);
49411 if(rstate.collapsed == true){
49414 r.expand(null, true);
49420 layout.endUpdate();
49422 this.state = state;
49424 this.layout = layout;
49425 layout.on("regionresized", this.onRegionResized, this);
49426 layout.on("regioncollapsed", this.onRegionCollapsed, this);
49427 layout.on("regionexpanded", this.onRegionExpanded, this);
49430 storeState : function(){
49431 this.provider.set(this.layout.id+"-layout-state", this.state);
49434 onRegionResized : function(region, newSize){
49435 this.state[region.getPosition()].size = newSize;
49439 onRegionCollapsed : function(region){
49440 this.state[region.getPosition()].collapsed = true;
49444 onRegionExpanded : function(region){
49445 this.state[region.getPosition()].collapsed = false;
49450 * Ext JS Library 1.1.1
49451 * Copyright(c) 2006-2007, Ext JS, LLC.
49453 * Originally Released Under LGPL - original licence link has changed is not relivant.
49456 * <script type="text/javascript">
49459 * @class Roo.ContentPanel
49460 * @extends Roo.util.Observable
49461 * A basic ContentPanel element.
49462 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
49463 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
49464 * @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
49465 * @cfg {Boolean} closable True if the panel can be closed/removed
49466 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
49467 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
49468 * @cfg {Toolbar} toolbar A toolbar for this panel
49469 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
49470 * @cfg {String} title The title for this panel
49471 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
49472 * @cfg {String} url Calls {@link #setUrl} with this value
49473 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
49474 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
49475 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
49476 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
49479 * Create a new ContentPanel.
49480 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
49481 * @param {String/Object} config A string to set only the title or a config object
49482 * @param {String} content (optional) Set the HTML content for this panel
49483 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
49485 Roo.ContentPanel = function(el, config, content){
49489 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
49493 if (config && config.parentLayout) {
49494 el = config.parentLayout.el.createChild();
49497 if(el.autoCreate){ // xtype is available if this is called from factory
49501 this.el = Roo.get(el);
49502 if(!this.el && config && config.autoCreate){
49503 if(typeof config.autoCreate == "object"){
49504 if(!config.autoCreate.id){
49505 config.autoCreate.id = config.id||el;
49507 this.el = Roo.DomHelper.append(document.body,
49508 config.autoCreate, true);
49510 this.el = Roo.DomHelper.append(document.body,
49511 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
49514 this.closable = false;
49515 this.loaded = false;
49516 this.active = false;
49517 if(typeof config == "string"){
49518 this.title = config;
49520 Roo.apply(this, config);
49523 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
49524 this.wrapEl = this.el.wrap();
49525 this.toolbar.container = this.el.insertSibling(false, 'before');
49526 this.toolbar = new Roo.Toolbar(this.toolbar);
49529 // xtype created footer. - not sure if will work as we normally have to render first..
49530 if (this.footer && !this.footer.el && this.footer.xtype) {
49531 if (!this.wrapEl) {
49532 this.wrapEl = this.el.wrap();
49535 this.footer.container = this.wrapEl.createChild();
49537 this.footer = Roo.factory(this.footer, Roo);
49542 this.resizeEl = Roo.get(this.resizeEl, true);
49544 this.resizeEl = this.el;
49546 // handle view.xtype
49554 * Fires when this panel is activated.
49555 * @param {Roo.ContentPanel} this
49559 * @event deactivate
49560 * Fires when this panel is activated.
49561 * @param {Roo.ContentPanel} this
49563 "deactivate" : true,
49567 * Fires when this panel is resized if fitToFrame is true.
49568 * @param {Roo.ContentPanel} this
49569 * @param {Number} width The width after any component adjustments
49570 * @param {Number} height The height after any component adjustments
49576 * Fires when this tab is created
49577 * @param {Roo.ContentPanel} this
49588 if(this.autoScroll){
49589 this.resizeEl.setStyle("overflow", "auto");
49591 // fix randome scrolling
49592 this.el.on('scroll', function() {
49593 Roo.log('fix random scolling');
49594 this.scrollTo('top',0);
49597 content = content || this.content;
49599 this.setContent(content);
49601 if(config && config.url){
49602 this.setUrl(this.url, this.params, this.loadOnce);
49607 Roo.ContentPanel.superclass.constructor.call(this);
49609 if (this.view && typeof(this.view.xtype) != 'undefined') {
49610 this.view.el = this.el.appendChild(document.createElement("div"));
49611 this.view = Roo.factory(this.view);
49612 this.view.render && this.view.render(false, '');
49616 this.fireEvent('render', this);
49619 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
49621 setRegion : function(region){
49622 this.region = region;
49624 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
49626 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
49631 * Returns the toolbar for this Panel if one was configured.
49632 * @return {Roo.Toolbar}
49634 getToolbar : function(){
49635 return this.toolbar;
49638 setActiveState : function(active){
49639 this.active = active;
49641 this.fireEvent("deactivate", this);
49643 this.fireEvent("activate", this);
49647 * Updates this panel's element
49648 * @param {String} content The new content
49649 * @param {Boolean} loadScripts (optional) true to look for and process scripts
49651 setContent : function(content, loadScripts){
49652 this.el.update(content, loadScripts);
49655 ignoreResize : function(w, h){
49656 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
49659 this.lastSize = {width: w, height: h};
49664 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
49665 * @return {Roo.UpdateManager} The UpdateManager
49667 getUpdateManager : function(){
49668 return this.el.getUpdateManager();
49671 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
49672 * @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:
49675 url: "your-url.php",
49676 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
49677 callback: yourFunction,
49678 scope: yourObject, //(optional scope)
49681 text: "Loading...",
49686 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
49687 * 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.
49688 * @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}
49689 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
49690 * @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.
49691 * @return {Roo.ContentPanel} this
49694 var um = this.el.getUpdateManager();
49695 um.update.apply(um, arguments);
49701 * 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.
49702 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
49703 * @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)
49704 * @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)
49705 * @return {Roo.UpdateManager} The UpdateManager
49707 setUrl : function(url, params, loadOnce){
49708 if(this.refreshDelegate){
49709 this.removeListener("activate", this.refreshDelegate);
49711 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
49712 this.on("activate", this.refreshDelegate);
49713 return this.el.getUpdateManager();
49716 _handleRefresh : function(url, params, loadOnce){
49717 if(!loadOnce || !this.loaded){
49718 var updater = this.el.getUpdateManager();
49719 updater.update(url, params, this._setLoaded.createDelegate(this));
49723 _setLoaded : function(){
49724 this.loaded = true;
49728 * Returns this panel's id
49731 getId : function(){
49736 * Returns this panel's element - used by regiosn to add.
49737 * @return {Roo.Element}
49739 getEl : function(){
49740 return this.wrapEl || this.el;
49743 adjustForComponents : function(width, height)
49745 //Roo.log('adjustForComponents ');
49746 if(this.resizeEl != this.el){
49747 width -= this.el.getFrameWidth('lr');
49748 height -= this.el.getFrameWidth('tb');
49751 var te = this.toolbar.getEl();
49752 height -= te.getHeight();
49753 te.setWidth(width);
49756 var te = this.footer.getEl();
49757 Roo.log("footer:" + te.getHeight());
49759 height -= te.getHeight();
49760 te.setWidth(width);
49764 if(this.adjustments){
49765 width += this.adjustments[0];
49766 height += this.adjustments[1];
49768 return {"width": width, "height": height};
49771 setSize : function(width, height){
49772 if(this.fitToFrame && !this.ignoreResize(width, height)){
49773 if(this.fitContainer && this.resizeEl != this.el){
49774 this.el.setSize(width, height);
49776 var size = this.adjustForComponents(width, height);
49777 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
49778 this.fireEvent('resize', this, size.width, size.height);
49783 * Returns this panel's title
49786 getTitle : function(){
49791 * Set this panel's title
49792 * @param {String} title
49794 setTitle : function(title){
49795 this.title = title;
49797 this.region.updatePanelTitle(this, title);
49802 * Returns true is this panel was configured to be closable
49803 * @return {Boolean}
49805 isClosable : function(){
49806 return this.closable;
49809 beforeSlide : function(){
49811 this.resizeEl.clip();
49814 afterSlide : function(){
49816 this.resizeEl.unclip();
49820 * Force a content refresh from the URL specified in the {@link #setUrl} method.
49821 * Will fail silently if the {@link #setUrl} method has not been called.
49822 * This does not activate the panel, just updates its content.
49824 refresh : function(){
49825 if(this.refreshDelegate){
49826 this.loaded = false;
49827 this.refreshDelegate();
49832 * Destroys this panel
49834 destroy : function(){
49835 this.el.removeAllListeners();
49836 var tempEl = document.createElement("span");
49837 tempEl.appendChild(this.el.dom);
49838 tempEl.innerHTML = "";
49844 * form - if the content panel contains a form - this is a reference to it.
49845 * @type {Roo.form.Form}
49849 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
49850 * This contains a reference to it.
49856 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
49866 * @param {Object} cfg Xtype definition of item to add.
49869 addxtype : function(cfg) {
49871 if (cfg.xtype.match(/^Form$/)) {
49874 //if (this.footer) {
49875 // el = this.footer.container.insertSibling(false, 'before');
49877 el = this.el.createChild();
49880 this.form = new Roo.form.Form(cfg);
49883 if ( this.form.allItems.length) this.form.render(el.dom);
49886 // should only have one of theses..
49887 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
49888 // views.. should not be just added - used named prop 'view''
49890 cfg.el = this.el.appendChild(document.createElement("div"));
49893 var ret = new Roo.factory(cfg);
49895 ret.render && ret.render(false, ''); // render blank..
49904 * @class Roo.GridPanel
49905 * @extends Roo.ContentPanel
49907 * Create a new GridPanel.
49908 * @param {Roo.grid.Grid} grid The grid for this panel
49909 * @param {String/Object} config A string to set only the panel's title, or a config object
49911 Roo.GridPanel = function(grid, config){
49914 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
49915 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
49917 this.wrapper.dom.appendChild(grid.getGridEl().dom);
49919 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
49922 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
49924 // xtype created footer. - not sure if will work as we normally have to render first..
49925 if (this.footer && !this.footer.el && this.footer.xtype) {
49927 this.footer.container = this.grid.getView().getFooterPanel(true);
49928 this.footer.dataSource = this.grid.dataSource;
49929 this.footer = Roo.factory(this.footer, Roo);
49933 grid.monitorWindowResize = false; // turn off autosizing
49934 grid.autoHeight = false;
49935 grid.autoWidth = false;
49937 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
49940 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
49941 getId : function(){
49942 return this.grid.id;
49946 * Returns the grid for this panel
49947 * @return {Roo.grid.Grid}
49949 getGrid : function(){
49953 setSize : function(width, height){
49954 if(!this.ignoreResize(width, height)){
49955 var grid = this.grid;
49956 var size = this.adjustForComponents(width, height);
49957 grid.getGridEl().setSize(size.width, size.height);
49962 beforeSlide : function(){
49963 this.grid.getView().scroller.clip();
49966 afterSlide : function(){
49967 this.grid.getView().scroller.unclip();
49970 destroy : function(){
49971 this.grid.destroy();
49973 Roo.GridPanel.superclass.destroy.call(this);
49979 * @class Roo.NestedLayoutPanel
49980 * @extends Roo.ContentPanel
49982 * Create a new NestedLayoutPanel.
49985 * @param {Roo.BorderLayout} layout The layout for this panel
49986 * @param {String/Object} config A string to set only the title or a config object
49988 Roo.NestedLayoutPanel = function(layout, config)
49990 // construct with only one argument..
49991 /* FIXME - implement nicer consturctors
49992 if (layout.layout) {
49994 layout = config.layout;
49995 delete config.layout;
49997 if (layout.xtype && !layout.getEl) {
49998 // then layout needs constructing..
49999 layout = Roo.factory(layout, Roo);
50004 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
50006 layout.monitorWindowResize = false; // turn off autosizing
50007 this.layout = layout;
50008 this.layout.getEl().addClass("x-layout-nested-layout");
50015 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
50017 setSize : function(width, height){
50018 if(!this.ignoreResize(width, height)){
50019 var size = this.adjustForComponents(width, height);
50020 var el = this.layout.getEl();
50021 el.setSize(size.width, size.height);
50022 var touch = el.dom.offsetWidth;
50023 this.layout.layout();
50024 // ie requires a double layout on the first pass
50025 if(Roo.isIE && !this.initialized){
50026 this.initialized = true;
50027 this.layout.layout();
50032 // activate all subpanels if not currently active..
50034 setActiveState : function(active){
50035 this.active = active;
50037 this.fireEvent("deactivate", this);
50041 this.fireEvent("activate", this);
50042 // not sure if this should happen before or after..
50043 if (!this.layout) {
50044 return; // should not happen..
50047 for (var r in this.layout.regions) {
50048 reg = this.layout.getRegion(r);
50049 if (reg.getActivePanel()) {
50050 //reg.showPanel(reg.getActivePanel()); // force it to activate..
50051 reg.setActivePanel(reg.getActivePanel());
50054 if (!reg.panels.length) {
50057 reg.showPanel(reg.getPanel(0));
50066 * Returns the nested BorderLayout for this panel
50067 * @return {Roo.BorderLayout}
50069 getLayout : function(){
50070 return this.layout;
50074 * Adds a xtype elements to the layout of the nested panel
50078 xtype : 'ContentPanel',
50085 xtype : 'NestedLayoutPanel',
50091 items : [ ... list of content panels or nested layout panels.. ]
50095 * @param {Object} cfg Xtype definition of item to add.
50097 addxtype : function(cfg) {
50098 return this.layout.addxtype(cfg);
50103 Roo.ScrollPanel = function(el, config, content){
50104 config = config || {};
50105 config.fitToFrame = true;
50106 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
50108 this.el.dom.style.overflow = "hidden";
50109 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
50110 this.el.removeClass("x-layout-inactive-content");
50111 this.el.on("mousewheel", this.onWheel, this);
50113 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
50114 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
50115 up.unselectable(); down.unselectable();
50116 up.on("click", this.scrollUp, this);
50117 down.on("click", this.scrollDown, this);
50118 up.addClassOnOver("x-scroller-btn-over");
50119 down.addClassOnOver("x-scroller-btn-over");
50120 up.addClassOnClick("x-scroller-btn-click");
50121 down.addClassOnClick("x-scroller-btn-click");
50122 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
50124 this.resizeEl = this.el;
50125 this.el = wrap; this.up = up; this.down = down;
50128 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
50130 wheelIncrement : 5,
50131 scrollUp : function(){
50132 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
50135 scrollDown : function(){
50136 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
50139 afterScroll : function(){
50140 var el = this.resizeEl;
50141 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
50142 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50143 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50146 setSize : function(){
50147 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
50148 this.afterScroll();
50151 onWheel : function(e){
50152 var d = e.getWheelDelta();
50153 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
50154 this.afterScroll();
50158 setContent : function(content, loadScripts){
50159 this.resizeEl.update(content, loadScripts);
50173 * @class Roo.TreePanel
50174 * @extends Roo.ContentPanel
50176 * Create a new TreePanel. - defaults to fit/scoll contents.
50177 * @param {String/Object} config A string to set only the panel's title, or a config object
50178 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
50180 Roo.TreePanel = function(config){
50181 var el = config.el;
50182 var tree = config.tree;
50183 delete config.tree;
50184 delete config.el; // hopefull!
50186 // wrapper for IE7 strict & safari scroll issue
50188 var treeEl = el.createChild();
50189 config.resizeEl = treeEl;
50193 Roo.TreePanel.superclass.constructor.call(this, el, config);
50196 this.tree = new Roo.tree.TreePanel(treeEl , tree);
50197 //console.log(tree);
50198 this.on('activate', function()
50200 if (this.tree.rendered) {
50203 //console.log('render tree');
50204 this.tree.render();
50206 // this should not be needed.. - it's actually the 'el' that resizes?
50207 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
50209 //this.on('resize', function (cp, w, h) {
50210 // this.tree.innerCt.setWidth(w);
50211 // this.tree.innerCt.setHeight(h);
50212 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
50219 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
50236 * Ext JS Library 1.1.1
50237 * Copyright(c) 2006-2007, Ext JS, LLC.
50239 * Originally Released Under LGPL - original licence link has changed is not relivant.
50242 * <script type="text/javascript">
50247 * @class Roo.ReaderLayout
50248 * @extends Roo.BorderLayout
50249 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
50250 * center region containing two nested regions (a top one for a list view and one for item preview below),
50251 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
50252 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
50253 * expedites the setup of the overall layout and regions for this common application style.
50256 var reader = new Roo.ReaderLayout();
50257 var CP = Roo.ContentPanel; // shortcut for adding
50259 reader.beginUpdate();
50260 reader.add("north", new CP("north", "North"));
50261 reader.add("west", new CP("west", {title: "West"}));
50262 reader.add("east", new CP("east", {title: "East"}));
50264 reader.regions.listView.add(new CP("listView", "List"));
50265 reader.regions.preview.add(new CP("preview", "Preview"));
50266 reader.endUpdate();
50269 * Create a new ReaderLayout
50270 * @param {Object} config Configuration options
50271 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
50272 * document.body if omitted)
50274 Roo.ReaderLayout = function(config, renderTo){
50275 var c = config || {size:{}};
50276 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
50277 north: c.north !== false ? Roo.apply({
50281 }, c.north) : false,
50282 west: c.west !== false ? Roo.apply({
50290 margins:{left:5,right:0,bottom:5,top:5},
50291 cmargins:{left:5,right:5,bottom:5,top:5}
50292 }, c.west) : false,
50293 east: c.east !== false ? Roo.apply({
50301 margins:{left:0,right:5,bottom:5,top:5},
50302 cmargins:{left:5,right:5,bottom:5,top:5}
50303 }, c.east) : false,
50304 center: Roo.apply({
50305 tabPosition: 'top',
50309 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
50313 this.el.addClass('x-reader');
50315 this.beginUpdate();
50317 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
50318 south: c.preview !== false ? Roo.apply({
50325 cmargins:{top:5,left:0, right:0, bottom:0}
50326 }, c.preview) : false,
50327 center: Roo.apply({
50333 this.add('center', new Roo.NestedLayoutPanel(inner,
50334 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
50338 this.regions.preview = inner.getRegion('south');
50339 this.regions.listView = inner.getRegion('center');
50342 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
50344 * Ext JS Library 1.1.1
50345 * Copyright(c) 2006-2007, Ext JS, LLC.
50347 * Originally Released Under LGPL - original licence link has changed is not relivant.
50350 * <script type="text/javascript">
50354 * @class Roo.grid.Grid
50355 * @extends Roo.util.Observable
50356 * This class represents the primary interface of a component based grid control.
50357 * <br><br>Usage:<pre><code>
50358 var grid = new Roo.grid.Grid("my-container-id", {
50361 selModel: mySelectionModel,
50362 autoSizeColumns: true,
50363 monitorWindowResize: false,
50364 trackMouseOver: true
50369 * <b>Common Problems:</b><br/>
50370 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
50371 * element will correct this<br/>
50372 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
50373 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
50374 * are unpredictable.<br/>
50375 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
50376 * grid to calculate dimensions/offsets.<br/>
50378 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50379 * The container MUST have some type of size defined for the grid to fill. The container will be
50380 * automatically set to position relative if it isn't already.
50381 * @param {Object} config A config object that sets properties on this grid.
50383 Roo.grid.Grid = function(container, config){
50384 // initialize the container
50385 this.container = Roo.get(container);
50386 this.container.update("");
50387 this.container.setStyle("overflow", "hidden");
50388 this.container.addClass('x-grid-container');
50390 this.id = this.container.id;
50392 Roo.apply(this, config);
50393 // check and correct shorthanded configs
50395 this.dataSource = this.ds;
50399 this.colModel = this.cm;
50403 this.selModel = this.sm;
50407 if (this.selModel) {
50408 this.selModel = Roo.factory(this.selModel, Roo.grid);
50409 this.sm = this.selModel;
50410 this.sm.xmodule = this.xmodule || false;
50412 if (typeof(this.colModel.config) == 'undefined') {
50413 this.colModel = new Roo.grid.ColumnModel(this.colModel);
50414 this.cm = this.colModel;
50415 this.cm.xmodule = this.xmodule || false;
50417 if (this.dataSource) {
50418 this.dataSource= Roo.factory(this.dataSource, Roo.data);
50419 this.ds = this.dataSource;
50420 this.ds.xmodule = this.xmodule || false;
50427 this.container.setWidth(this.width);
50431 this.container.setHeight(this.height);
50438 * The raw click event for the entire grid.
50439 * @param {Roo.EventObject} e
50444 * The raw dblclick event for the entire grid.
50445 * @param {Roo.EventObject} e
50449 * @event contextmenu
50450 * The raw contextmenu event for the entire grid.
50451 * @param {Roo.EventObject} e
50453 "contextmenu" : true,
50456 * The raw mousedown event for the entire grid.
50457 * @param {Roo.EventObject} e
50459 "mousedown" : true,
50462 * The raw mouseup event for the entire grid.
50463 * @param {Roo.EventObject} e
50468 * The raw mouseover event for the entire grid.
50469 * @param {Roo.EventObject} e
50471 "mouseover" : true,
50474 * The raw mouseout event for the entire grid.
50475 * @param {Roo.EventObject} e
50480 * The raw keypress event for the entire grid.
50481 * @param {Roo.EventObject} e
50486 * The raw keydown event for the entire grid.
50487 * @param {Roo.EventObject} e
50495 * Fires when a cell is clicked
50496 * @param {Grid} this
50497 * @param {Number} rowIndex
50498 * @param {Number} columnIndex
50499 * @param {Roo.EventObject} e
50501 "cellclick" : true,
50503 * @event celldblclick
50504 * Fires when a cell is double clicked
50505 * @param {Grid} this
50506 * @param {Number} rowIndex
50507 * @param {Number} columnIndex
50508 * @param {Roo.EventObject} e
50510 "celldblclick" : true,
50513 * Fires when a row is clicked
50514 * @param {Grid} this
50515 * @param {Number} rowIndex
50516 * @param {Roo.EventObject} e
50520 * @event rowdblclick
50521 * Fires when a row is double clicked
50522 * @param {Grid} this
50523 * @param {Number} rowIndex
50524 * @param {Roo.EventObject} e
50526 "rowdblclick" : true,
50528 * @event headerclick
50529 * Fires when a header is clicked
50530 * @param {Grid} this
50531 * @param {Number} columnIndex
50532 * @param {Roo.EventObject} e
50534 "headerclick" : true,
50536 * @event headerdblclick
50537 * Fires when a header cell is double clicked
50538 * @param {Grid} this
50539 * @param {Number} columnIndex
50540 * @param {Roo.EventObject} e
50542 "headerdblclick" : true,
50544 * @event rowcontextmenu
50545 * Fires when a row is right clicked
50546 * @param {Grid} this
50547 * @param {Number} rowIndex
50548 * @param {Roo.EventObject} e
50550 "rowcontextmenu" : true,
50552 * @event cellcontextmenu
50553 * Fires when a cell is right clicked
50554 * @param {Grid} this
50555 * @param {Number} rowIndex
50556 * @param {Number} cellIndex
50557 * @param {Roo.EventObject} e
50559 "cellcontextmenu" : true,
50561 * @event headercontextmenu
50562 * Fires when a header is right clicked
50563 * @param {Grid} this
50564 * @param {Number} columnIndex
50565 * @param {Roo.EventObject} e
50567 "headercontextmenu" : true,
50569 * @event bodyscroll
50570 * Fires when the body element is scrolled
50571 * @param {Number} scrollLeft
50572 * @param {Number} scrollTop
50574 "bodyscroll" : true,
50576 * @event columnresize
50577 * Fires when the user resizes a column
50578 * @param {Number} columnIndex
50579 * @param {Number} newSize
50581 "columnresize" : true,
50583 * @event columnmove
50584 * Fires when the user moves a column
50585 * @param {Number} oldIndex
50586 * @param {Number} newIndex
50588 "columnmove" : true,
50591 * Fires when row(s) start being dragged
50592 * @param {Grid} this
50593 * @param {Roo.GridDD} dd The drag drop object
50594 * @param {event} e The raw browser event
50596 "startdrag" : true,
50599 * Fires when a drag operation is complete
50600 * @param {Grid} this
50601 * @param {Roo.GridDD} dd The drag drop object
50602 * @param {event} e The raw browser event
50607 * Fires when dragged row(s) are dropped on a valid DD target
50608 * @param {Grid} this
50609 * @param {Roo.GridDD} dd The drag drop object
50610 * @param {String} targetId The target drag drop object
50611 * @param {event} e The raw browser event
50616 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
50617 * @param {Grid} this
50618 * @param {Roo.GridDD} dd The drag drop object
50619 * @param {String} targetId The target drag drop object
50620 * @param {event} e The raw browser event
50625 * Fires when the dragged row(s) first cross another DD target while being dragged
50626 * @param {Grid} this
50627 * @param {Roo.GridDD} dd The drag drop object
50628 * @param {String} targetId The target drag drop object
50629 * @param {event} e The raw browser event
50631 "dragenter" : true,
50634 * Fires when the dragged row(s) leave another DD target while being dragged
50635 * @param {Grid} this
50636 * @param {Roo.GridDD} dd The drag drop object
50637 * @param {String} targetId The target drag drop object
50638 * @param {event} e The raw browser event
50643 * Fires when a row is rendered, so you can change add a style to it.
50644 * @param {GridView} gridview The grid view
50645 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
50651 * Fires when the grid is rendered
50652 * @param {Grid} grid
50657 Roo.grid.Grid.superclass.constructor.call(this);
50659 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
50662 * @cfg {String} ddGroup - drag drop group.
50666 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
50668 minColumnWidth : 25,
50671 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
50672 * <b>on initial render.</b> It is more efficient to explicitly size the columns
50673 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
50675 autoSizeColumns : false,
50678 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
50680 autoSizeHeaders : true,
50683 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
50685 monitorWindowResize : true,
50688 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
50689 * rows measured to get a columns size. Default is 0 (all rows).
50691 maxRowsToMeasure : 0,
50694 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
50696 trackMouseOver : true,
50699 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
50703 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
50705 enableDragDrop : false,
50708 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
50710 enableColumnMove : true,
50713 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
50715 enableColumnHide : true,
50718 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
50720 enableRowHeightSync : false,
50723 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
50728 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
50730 autoHeight : false,
50733 * @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.
50735 autoExpandColumn : false,
50738 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
50741 autoExpandMin : 50,
50744 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
50746 autoExpandMax : 1000,
50749 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
50754 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
50758 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
50768 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
50769 * of a fixed width. Default is false.
50772 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
50775 * Called once after all setup has been completed and the grid is ready to be rendered.
50776 * @return {Roo.grid.Grid} this
50778 render : function()
50780 var c = this.container;
50781 // try to detect autoHeight/width mode
50782 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
50783 this.autoHeight = true;
50785 var view = this.getView();
50788 c.on("click", this.onClick, this);
50789 c.on("dblclick", this.onDblClick, this);
50790 c.on("contextmenu", this.onContextMenu, this);
50791 c.on("keydown", this.onKeyDown, this);
50793 c.on("touchstart", this.onTouchStart, this);
50796 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
50798 this.getSelectionModel().init(this);
50803 this.loadMask = new Roo.LoadMask(this.container,
50804 Roo.apply({store:this.dataSource}, this.loadMask));
50808 if (this.toolbar && this.toolbar.xtype) {
50809 this.toolbar.container = this.getView().getHeaderPanel(true);
50810 this.toolbar = new Roo.Toolbar(this.toolbar);
50812 if (this.footer && this.footer.xtype) {
50813 this.footer.dataSource = this.getDataSource();
50814 this.footer.container = this.getView().getFooterPanel(true);
50815 this.footer = Roo.factory(this.footer, Roo);
50817 if (this.dropTarget && this.dropTarget.xtype) {
50818 delete this.dropTarget.xtype;
50819 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
50823 this.rendered = true;
50824 this.fireEvent('render', this);
50829 * Reconfigures the grid to use a different Store and Column Model.
50830 * The View will be bound to the new objects and refreshed.
50831 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
50832 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
50834 reconfigure : function(dataSource, colModel){
50836 this.loadMask.destroy();
50837 this.loadMask = new Roo.LoadMask(this.container,
50838 Roo.apply({store:dataSource}, this.loadMask));
50840 this.view.bind(dataSource, colModel);
50841 this.dataSource = dataSource;
50842 this.colModel = colModel;
50843 this.view.refresh(true);
50847 onKeyDown : function(e){
50848 this.fireEvent("keydown", e);
50852 * Destroy this grid.
50853 * @param {Boolean} removeEl True to remove the element
50855 destroy : function(removeEl, keepListeners){
50857 this.loadMask.destroy();
50859 var c = this.container;
50860 c.removeAllListeners();
50861 this.view.destroy();
50862 this.colModel.purgeListeners();
50863 if(!keepListeners){
50864 this.purgeListeners();
50867 if(removeEl === true){
50873 processEvent : function(name, e){
50874 // does this fire select???
50875 Roo.log('grid:processEvent ' + name);
50877 if (name != 'touchstart' ) {
50878 this.fireEvent(name, e);
50881 var t = e.getTarget();
50883 var header = v.findHeaderIndex(t);
50884 if(header !== false){
50885 this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
50887 var row = v.findRowIndex(t);
50888 var cell = v.findCellIndex(t);
50889 if (name == 'touchstart') {
50890 // first touch is always a click.
50891 // hopefull this happens after selection is updated.?
50894 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
50895 var cs = this.selModel.getSelectedCell();
50896 if (row == cs[0] && cell == cs[1]){
50900 if (typeof(this.selModel.getSelections) != 'undefined') {
50901 var cs = this.selModel.getSelections();
50902 var ds = this.dataSource;
50903 if (cs.length == 1 && ds.getAt(row) == cs[0]){
50914 this.fireEvent("row" + name, this, row, e);
50915 if(cell !== false){
50916 this.fireEvent("cell" + name, this, row, cell, e);
50923 onClick : function(e){
50924 this.processEvent("click", e);
50927 onTouchStart : function(e){
50928 this.processEvent("touchstart", e);
50932 onContextMenu : function(e, t){
50933 this.processEvent("contextmenu", e);
50937 onDblClick : function(e){
50938 this.processEvent("dblclick", e);
50942 walkCells : function(row, col, step, fn, scope){
50943 var cm = this.colModel, clen = cm.getColumnCount();
50944 var ds = this.dataSource, rlen = ds.getCount(), first = true;
50956 if(fn.call(scope || this, row, col, cm) === true){
50974 if(fn.call(scope || this, row, col, cm) === true){
50986 getSelections : function(){
50987 return this.selModel.getSelections();
50991 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
50992 * but if manual update is required this method will initiate it.
50994 autoSize : function(){
50996 this.view.layout();
50997 if(this.view.adjustForScroll){
50998 this.view.adjustForScroll();
51004 * Returns the grid's underlying element.
51005 * @return {Element} The element
51007 getGridEl : function(){
51008 return this.container;
51011 // private for compatibility, overridden by editor grid
51012 stopEditing : function(){},
51015 * Returns the grid's SelectionModel.
51016 * @return {SelectionModel}
51018 getSelectionModel : function(){
51019 if(!this.selModel){
51020 this.selModel = new Roo.grid.RowSelectionModel();
51022 return this.selModel;
51026 * Returns the grid's DataSource.
51027 * @return {DataSource}
51029 getDataSource : function(){
51030 return this.dataSource;
51034 * Returns the grid's ColumnModel.
51035 * @return {ColumnModel}
51037 getColumnModel : function(){
51038 return this.colModel;
51042 * Returns the grid's GridView object.
51043 * @return {GridView}
51045 getView : function(){
51047 this.view = new Roo.grid.GridView(this.viewConfig);
51052 * Called to get grid's drag proxy text, by default returns this.ddText.
51055 getDragDropText : function(){
51056 var count = this.selModel.getCount();
51057 return String.format(this.ddText, count, count == 1 ? '' : 's');
51061 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
51062 * %0 is replaced with the number of selected rows.
51065 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
51067 * Ext JS Library 1.1.1
51068 * Copyright(c) 2006-2007, Ext JS, LLC.
51070 * Originally Released Under LGPL - original licence link has changed is not relivant.
51073 * <script type="text/javascript">
51076 Roo.grid.AbstractGridView = function(){
51080 "beforerowremoved" : true,
51081 "beforerowsinserted" : true,
51082 "beforerefresh" : true,
51083 "rowremoved" : true,
51084 "rowsinserted" : true,
51085 "rowupdated" : true,
51088 Roo.grid.AbstractGridView.superclass.constructor.call(this);
51091 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
51092 rowClass : "x-grid-row",
51093 cellClass : "x-grid-cell",
51094 tdClass : "x-grid-td",
51095 hdClass : "x-grid-hd",
51096 splitClass : "x-grid-hd-split",
51098 init: function(grid){
51100 var cid = this.grid.getGridEl().id;
51101 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
51102 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
51103 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
51104 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
51107 getColumnRenderers : function(){
51108 var renderers = [];
51109 var cm = this.grid.colModel;
51110 var colCount = cm.getColumnCount();
51111 for(var i = 0; i < colCount; i++){
51112 renderers[i] = cm.getRenderer(i);
51117 getColumnIds : function(){
51119 var cm = this.grid.colModel;
51120 var colCount = cm.getColumnCount();
51121 for(var i = 0; i < colCount; i++){
51122 ids[i] = cm.getColumnId(i);
51127 getDataIndexes : function(){
51128 if(!this.indexMap){
51129 this.indexMap = this.buildIndexMap();
51131 return this.indexMap.colToData;
51134 getColumnIndexByDataIndex : function(dataIndex){
51135 if(!this.indexMap){
51136 this.indexMap = this.buildIndexMap();
51138 return this.indexMap.dataToCol[dataIndex];
51142 * Set a css style for a column dynamically.
51143 * @param {Number} colIndex The index of the column
51144 * @param {String} name The css property name
51145 * @param {String} value The css value
51147 setCSSStyle : function(colIndex, name, value){
51148 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
51149 Roo.util.CSS.updateRule(selector, name, value);
51152 generateRules : function(cm){
51153 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
51154 Roo.util.CSS.removeStyleSheet(rulesId);
51155 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51156 var cid = cm.getColumnId(i);
51157 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
51158 this.tdSelector, cid, " {\n}\n",
51159 this.hdSelector, cid, " {\n}\n",
51160 this.splitSelector, cid, " {\n}\n");
51162 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
51166 * Ext JS Library 1.1.1
51167 * Copyright(c) 2006-2007, Ext JS, LLC.
51169 * Originally Released Under LGPL - original licence link has changed is not relivant.
51172 * <script type="text/javascript">
51176 // This is a support class used internally by the Grid components
51177 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
51179 this.view = grid.getView();
51180 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51181 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
51183 this.setHandleElId(Roo.id(hd));
51184 this.setOuterHandleElId(Roo.id(hd2));
51186 this.scroll = false;
51188 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
51190 getDragData : function(e){
51191 var t = Roo.lib.Event.getTarget(e);
51192 var h = this.view.findHeaderCell(t);
51194 return {ddel: h.firstChild, header:h};
51199 onInitDrag : function(e){
51200 this.view.headersDisabled = true;
51201 var clone = this.dragData.ddel.cloneNode(true);
51202 clone.id = Roo.id();
51203 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
51204 this.proxy.update(clone);
51208 afterValidDrop : function(){
51210 setTimeout(function(){
51211 v.headersDisabled = false;
51215 afterInvalidDrop : function(){
51217 setTimeout(function(){
51218 v.headersDisabled = false;
51224 * Ext JS Library 1.1.1
51225 * Copyright(c) 2006-2007, Ext JS, LLC.
51227 * Originally Released Under LGPL - original licence link has changed is not relivant.
51230 * <script type="text/javascript">
51233 // This is a support class used internally by the Grid components
51234 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
51236 this.view = grid.getView();
51237 // split the proxies so they don't interfere with mouse events
51238 this.proxyTop = Roo.DomHelper.append(document.body, {
51239 cls:"col-move-top", html:" "
51241 this.proxyBottom = Roo.DomHelper.append(document.body, {
51242 cls:"col-move-bottom", html:" "
51244 this.proxyTop.hide = this.proxyBottom.hide = function(){
51245 this.setLeftTop(-100,-100);
51246 this.setStyle("visibility", "hidden");
51248 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51249 // temporarily disabled
51250 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
51251 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
51253 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
51254 proxyOffsets : [-4, -9],
51255 fly: Roo.Element.fly,
51257 getTargetFromEvent : function(e){
51258 var t = Roo.lib.Event.getTarget(e);
51259 var cindex = this.view.findCellIndex(t);
51260 if(cindex !== false){
51261 return this.view.getHeaderCell(cindex);
51266 nextVisible : function(h){
51267 var v = this.view, cm = this.grid.colModel;
51270 if(!cm.isHidden(v.getCellIndex(h))){
51278 prevVisible : function(h){
51279 var v = this.view, cm = this.grid.colModel;
51282 if(!cm.isHidden(v.getCellIndex(h))){
51290 positionIndicator : function(h, n, e){
51291 var x = Roo.lib.Event.getPageX(e);
51292 var r = Roo.lib.Dom.getRegion(n.firstChild);
51293 var px, pt, py = r.top + this.proxyOffsets[1];
51294 if((r.right - x) <= (r.right-r.left)/2){
51295 px = r.right+this.view.borderWidth;
51301 var oldIndex = this.view.getCellIndex(h);
51302 var newIndex = this.view.getCellIndex(n);
51304 if(this.grid.colModel.isFixed(newIndex)){
51308 var locked = this.grid.colModel.isLocked(newIndex);
51313 if(oldIndex < newIndex){
51316 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
51319 px += this.proxyOffsets[0];
51320 this.proxyTop.setLeftTop(px, py);
51321 this.proxyTop.show();
51322 if(!this.bottomOffset){
51323 this.bottomOffset = this.view.mainHd.getHeight();
51325 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
51326 this.proxyBottom.show();
51330 onNodeEnter : function(n, dd, e, data){
51331 if(data.header != n){
51332 this.positionIndicator(data.header, n, e);
51336 onNodeOver : function(n, dd, e, data){
51337 var result = false;
51338 if(data.header != n){
51339 result = this.positionIndicator(data.header, n, e);
51342 this.proxyTop.hide();
51343 this.proxyBottom.hide();
51345 return result ? this.dropAllowed : this.dropNotAllowed;
51348 onNodeOut : function(n, dd, e, data){
51349 this.proxyTop.hide();
51350 this.proxyBottom.hide();
51353 onNodeDrop : function(n, dd, e, data){
51354 var h = data.header;
51356 var cm = this.grid.colModel;
51357 var x = Roo.lib.Event.getPageX(e);
51358 var r = Roo.lib.Dom.getRegion(n.firstChild);
51359 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
51360 var oldIndex = this.view.getCellIndex(h);
51361 var newIndex = this.view.getCellIndex(n);
51362 var locked = cm.isLocked(newIndex);
51366 if(oldIndex < newIndex){
51369 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
51372 cm.setLocked(oldIndex, locked, true);
51373 cm.moveColumn(oldIndex, newIndex);
51374 this.grid.fireEvent("columnmove", oldIndex, newIndex);
51382 * Ext JS Library 1.1.1
51383 * Copyright(c) 2006-2007, Ext JS, LLC.
51385 * Originally Released Under LGPL - original licence link has changed is not relivant.
51388 * <script type="text/javascript">
51392 * @class Roo.grid.GridView
51393 * @extends Roo.util.Observable
51396 * @param {Object} config
51398 Roo.grid.GridView = function(config){
51399 Roo.grid.GridView.superclass.constructor.call(this);
51402 Roo.apply(this, config);
51405 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
51407 unselectable : 'unselectable="on"',
51408 unselectableCls : 'x-unselectable',
51411 rowClass : "x-grid-row",
51413 cellClass : "x-grid-col",
51415 tdClass : "x-grid-td",
51417 hdClass : "x-grid-hd",
51419 splitClass : "x-grid-split",
51421 sortClasses : ["sort-asc", "sort-desc"],
51423 enableMoveAnim : false,
51427 dh : Roo.DomHelper,
51429 fly : Roo.Element.fly,
51431 css : Roo.util.CSS,
51437 scrollIncrement : 22,
51439 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
51441 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
51443 bind : function(ds, cm){
51445 this.ds.un("load", this.onLoad, this);
51446 this.ds.un("datachanged", this.onDataChange, this);
51447 this.ds.un("add", this.onAdd, this);
51448 this.ds.un("remove", this.onRemove, this);
51449 this.ds.un("update", this.onUpdate, this);
51450 this.ds.un("clear", this.onClear, this);
51453 ds.on("load", this.onLoad, this);
51454 ds.on("datachanged", this.onDataChange, this);
51455 ds.on("add", this.onAdd, this);
51456 ds.on("remove", this.onRemove, this);
51457 ds.on("update", this.onUpdate, this);
51458 ds.on("clear", this.onClear, this);
51463 this.cm.un("widthchange", this.onColWidthChange, this);
51464 this.cm.un("headerchange", this.onHeaderChange, this);
51465 this.cm.un("hiddenchange", this.onHiddenChange, this);
51466 this.cm.un("columnmoved", this.onColumnMove, this);
51467 this.cm.un("columnlockchange", this.onColumnLock, this);
51470 this.generateRules(cm);
51471 cm.on("widthchange", this.onColWidthChange, this);
51472 cm.on("headerchange", this.onHeaderChange, this);
51473 cm.on("hiddenchange", this.onHiddenChange, this);
51474 cm.on("columnmoved", this.onColumnMove, this);
51475 cm.on("columnlockchange", this.onColumnLock, this);
51480 init: function(grid){
51481 Roo.grid.GridView.superclass.init.call(this, grid);
51483 this.bind(grid.dataSource, grid.colModel);
51485 grid.on("headerclick", this.handleHeaderClick, this);
51487 if(grid.trackMouseOver){
51488 grid.on("mouseover", this.onRowOver, this);
51489 grid.on("mouseout", this.onRowOut, this);
51491 grid.cancelTextSelection = function(){};
51492 this.gridId = grid.id;
51494 var tpls = this.templates || {};
51497 tpls.master = new Roo.Template(
51498 '<div class="x-grid" hidefocus="true">',
51499 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
51500 '<div class="x-grid-topbar"></div>',
51501 '<div class="x-grid-scroller"><div></div></div>',
51502 '<div class="x-grid-locked">',
51503 '<div class="x-grid-header">{lockedHeader}</div>',
51504 '<div class="x-grid-body">{lockedBody}</div>',
51506 '<div class="x-grid-viewport">',
51507 '<div class="x-grid-header">{header}</div>',
51508 '<div class="x-grid-body">{body}</div>',
51510 '<div class="x-grid-bottombar"></div>',
51512 '<div class="x-grid-resize-proxy"> </div>',
51515 tpls.master.disableformats = true;
51519 tpls.header = new Roo.Template(
51520 '<table border="0" cellspacing="0" cellpadding="0">',
51521 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
51524 tpls.header.disableformats = true;
51526 tpls.header.compile();
51529 tpls.hcell = new Roo.Template(
51530 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
51531 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
51534 tpls.hcell.disableFormats = true;
51536 tpls.hcell.compile();
51539 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
51540 this.unselectableCls + '" ' + this.unselectable +'> </div>');
51541 tpls.hsplit.disableFormats = true;
51543 tpls.hsplit.compile();
51546 tpls.body = new Roo.Template(
51547 '<table border="0" cellspacing="0" cellpadding="0">',
51548 "<tbody>{rows}</tbody>",
51551 tpls.body.disableFormats = true;
51553 tpls.body.compile();
51556 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
51557 tpls.row.disableFormats = true;
51559 tpls.row.compile();
51562 tpls.cell = new Roo.Template(
51563 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
51564 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
51565 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
51568 tpls.cell.disableFormats = true;
51570 tpls.cell.compile();
51572 this.templates = tpls;
51575 // remap these for backwards compat
51576 onColWidthChange : function(){
51577 this.updateColumns.apply(this, arguments);
51579 onHeaderChange : function(){
51580 this.updateHeaders.apply(this, arguments);
51582 onHiddenChange : function(){
51583 this.handleHiddenChange.apply(this, arguments);
51585 onColumnMove : function(){
51586 this.handleColumnMove.apply(this, arguments);
51588 onColumnLock : function(){
51589 this.handleLockChange.apply(this, arguments);
51592 onDataChange : function(){
51594 this.updateHeaderSortState();
51597 onClear : function(){
51601 onUpdate : function(ds, record){
51602 this.refreshRow(record);
51605 refreshRow : function(record){
51606 var ds = this.ds, index;
51607 if(typeof record == 'number'){
51609 record = ds.getAt(index);
51611 index = ds.indexOf(record);
51613 this.insertRows(ds, index, index, true);
51614 this.onRemove(ds, record, index+1, true);
51615 this.syncRowHeights(index, index);
51617 this.fireEvent("rowupdated", this, index, record);
51620 onAdd : function(ds, records, index){
51621 this.insertRows(ds, index, index + (records.length-1));
51624 onRemove : function(ds, record, index, isUpdate){
51625 if(isUpdate !== true){
51626 this.fireEvent("beforerowremoved", this, index, record);
51628 var bt = this.getBodyTable(), lt = this.getLockedTable();
51629 if(bt.rows[index]){
51630 bt.firstChild.removeChild(bt.rows[index]);
51632 if(lt.rows[index]){
51633 lt.firstChild.removeChild(lt.rows[index]);
51635 if(isUpdate !== true){
51636 this.stripeRows(index);
51637 this.syncRowHeights(index, index);
51639 this.fireEvent("rowremoved", this, index, record);
51643 onLoad : function(){
51644 this.scrollToTop();
51648 * Scrolls the grid to the top
51650 scrollToTop : function(){
51652 this.scroller.dom.scrollTop = 0;
51658 * Gets a panel in the header of the grid that can be used for toolbars etc.
51659 * After modifying the contents of this panel a call to grid.autoSize() may be
51660 * required to register any changes in size.
51661 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
51662 * @return Roo.Element
51664 getHeaderPanel : function(doShow){
51666 this.headerPanel.show();
51668 return this.headerPanel;
51672 * Gets a panel in the footer of the grid that can be used for toolbars etc.
51673 * After modifying the contents of this panel a call to grid.autoSize() may be
51674 * required to register any changes in size.
51675 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
51676 * @return Roo.Element
51678 getFooterPanel : function(doShow){
51680 this.footerPanel.show();
51682 return this.footerPanel;
51685 initElements : function(){
51686 var E = Roo.Element;
51687 var el = this.grid.getGridEl().dom.firstChild;
51688 var cs = el.childNodes;
51690 this.el = new E(el);
51692 this.focusEl = new E(el.firstChild);
51693 this.focusEl.swallowEvent("click", true);
51695 this.headerPanel = new E(cs[1]);
51696 this.headerPanel.enableDisplayMode("block");
51698 this.scroller = new E(cs[2]);
51699 this.scrollSizer = new E(this.scroller.dom.firstChild);
51701 this.lockedWrap = new E(cs[3]);
51702 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
51703 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
51705 this.mainWrap = new E(cs[4]);
51706 this.mainHd = new E(this.mainWrap.dom.firstChild);
51707 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
51709 this.footerPanel = new E(cs[5]);
51710 this.footerPanel.enableDisplayMode("block");
51712 this.resizeProxy = new E(cs[6]);
51714 this.headerSelector = String.format(
51715 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
51716 this.lockedHd.id, this.mainHd.id
51719 this.splitterSelector = String.format(
51720 '#{0} div.x-grid-split, #{1} div.x-grid-split',
51721 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
51724 idToCssName : function(s)
51726 return s.replace(/[^a-z0-9]+/ig, '-');
51729 getHeaderCell : function(index){
51730 return Roo.DomQuery.select(this.headerSelector)[index];
51733 getHeaderCellMeasure : function(index){
51734 return this.getHeaderCell(index).firstChild;
51737 getHeaderCellText : function(index){
51738 return this.getHeaderCell(index).firstChild.firstChild;
51741 getLockedTable : function(){
51742 return this.lockedBody.dom.firstChild;
51745 getBodyTable : function(){
51746 return this.mainBody.dom.firstChild;
51749 getLockedRow : function(index){
51750 return this.getLockedTable().rows[index];
51753 getRow : function(index){
51754 return this.getBodyTable().rows[index];
51757 getRowComposite : function(index){
51759 this.rowEl = new Roo.CompositeElementLite();
51761 var els = [], lrow, mrow;
51762 if(lrow = this.getLockedRow(index)){
51765 if(mrow = this.getRow(index)){
51768 this.rowEl.elements = els;
51772 * Gets the 'td' of the cell
51774 * @param {Integer} rowIndex row to select
51775 * @param {Integer} colIndex column to select
51779 getCell : function(rowIndex, colIndex){
51780 var locked = this.cm.getLockedCount();
51782 if(colIndex < locked){
51783 source = this.lockedBody.dom.firstChild;
51785 source = this.mainBody.dom.firstChild;
51786 colIndex -= locked;
51788 return source.rows[rowIndex].childNodes[colIndex];
51791 getCellText : function(rowIndex, colIndex){
51792 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
51795 getCellBox : function(cell){
51796 var b = this.fly(cell).getBox();
51797 if(Roo.isOpera){ // opera fails to report the Y
51798 b.y = cell.offsetTop + this.mainBody.getY();
51803 getCellIndex : function(cell){
51804 var id = String(cell.className).match(this.cellRE);
51806 return parseInt(id[1], 10);
51811 findHeaderIndex : function(n){
51812 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
51813 return r ? this.getCellIndex(r) : false;
51816 findHeaderCell : function(n){
51817 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
51818 return r ? r : false;
51821 findRowIndex : function(n){
51825 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
51826 return r ? r.rowIndex : false;
51829 findCellIndex : function(node){
51830 var stop = this.el.dom;
51831 while(node && node != stop){
51832 if(this.findRE.test(node.className)){
51833 return this.getCellIndex(node);
51835 node = node.parentNode;
51840 getColumnId : function(index){
51841 return this.cm.getColumnId(index);
51844 getSplitters : function()
51846 if(this.splitterSelector){
51847 return Roo.DomQuery.select(this.splitterSelector);
51853 getSplitter : function(index){
51854 return this.getSplitters()[index];
51857 onRowOver : function(e, t){
51859 if((row = this.findRowIndex(t)) !== false){
51860 this.getRowComposite(row).addClass("x-grid-row-over");
51864 onRowOut : function(e, t){
51866 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
51867 this.getRowComposite(row).removeClass("x-grid-row-over");
51871 renderHeaders : function(){
51873 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
51874 var cb = [], lb = [], sb = [], lsb = [], p = {};
51875 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51876 p.cellId = "x-grid-hd-0-" + i;
51877 p.splitId = "x-grid-csplit-0-" + i;
51878 p.id = cm.getColumnId(i);
51879 p.title = cm.getColumnTooltip(i) || "";
51880 p.value = cm.getColumnHeader(i) || "";
51881 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
51882 if(!cm.isLocked(i)){
51883 cb[cb.length] = ct.apply(p);
51884 sb[sb.length] = st.apply(p);
51886 lb[lb.length] = ct.apply(p);
51887 lsb[lsb.length] = st.apply(p);
51890 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
51891 ht.apply({cells: cb.join(""), splits:sb.join("")})];
51894 updateHeaders : function(){
51895 var html = this.renderHeaders();
51896 this.lockedHd.update(html[0]);
51897 this.mainHd.update(html[1]);
51901 * Focuses the specified row.
51902 * @param {Number} row The row index
51904 focusRow : function(row)
51906 //Roo.log('GridView.focusRow');
51907 var x = this.scroller.dom.scrollLeft;
51908 this.focusCell(row, 0, false);
51909 this.scroller.dom.scrollLeft = x;
51913 * Focuses the specified cell.
51914 * @param {Number} row The row index
51915 * @param {Number} col The column index
51916 * @param {Boolean} hscroll false to disable horizontal scrolling
51918 focusCell : function(row, col, hscroll)
51920 //Roo.log('GridView.focusCell');
51921 var el = this.ensureVisible(row, col, hscroll);
51922 this.focusEl.alignTo(el, "tl-tl");
51924 this.focusEl.focus();
51926 this.focusEl.focus.defer(1, this.focusEl);
51931 * Scrolls the specified cell into view
51932 * @param {Number} row The row index
51933 * @param {Number} col The column index
51934 * @param {Boolean} hscroll false to disable horizontal scrolling
51936 ensureVisible : function(row, col, hscroll)
51938 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
51939 //return null; //disable for testing.
51940 if(typeof row != "number"){
51941 row = row.rowIndex;
51943 if(row < 0 && row >= this.ds.getCount()){
51946 col = (col !== undefined ? col : 0);
51947 var cm = this.grid.colModel;
51948 while(cm.isHidden(col)){
51952 var el = this.getCell(row, col);
51956 var c = this.scroller.dom;
51958 var ctop = parseInt(el.offsetTop, 10);
51959 var cleft = parseInt(el.offsetLeft, 10);
51960 var cbot = ctop + el.offsetHeight;
51961 var cright = cleft + el.offsetWidth;
51963 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
51964 var stop = parseInt(c.scrollTop, 10);
51965 var sleft = parseInt(c.scrollLeft, 10);
51966 var sbot = stop + ch;
51967 var sright = sleft + c.clientWidth;
51969 Roo.log('GridView.ensureVisible:' +
51971 ' c.clientHeight:' + c.clientHeight +
51972 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
51980 c.scrollTop = ctop;
51981 //Roo.log("set scrolltop to ctop DISABLE?");
51982 }else if(cbot > sbot){
51983 //Roo.log("set scrolltop to cbot-ch");
51984 c.scrollTop = cbot-ch;
51987 if(hscroll !== false){
51989 c.scrollLeft = cleft;
51990 }else if(cright > sright){
51991 c.scrollLeft = cright-c.clientWidth;
51998 updateColumns : function(){
51999 this.grid.stopEditing();
52000 var cm = this.grid.colModel, colIds = this.getColumnIds();
52001 //var totalWidth = cm.getTotalWidth();
52003 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52004 //if(cm.isHidden(i)) continue;
52005 var w = cm.getColumnWidth(i);
52006 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52007 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52009 this.updateSplitters();
52012 generateRules : function(cm){
52013 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
52014 Roo.util.CSS.removeStyleSheet(rulesId);
52015 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52016 var cid = cm.getColumnId(i);
52018 if(cm.config[i].align){
52019 align = 'text-align:'+cm.config[i].align+';';
52022 if(cm.isHidden(i)){
52023 hidden = 'display:none;';
52025 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
52027 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
52028 this.hdSelector, cid, " {\n", align, width, "}\n",
52029 this.tdSelector, cid, " {\n",hidden,"\n}\n",
52030 this.splitSelector, cid, " {\n", hidden , "\n}\n");
52032 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52035 updateSplitters : function(){
52036 var cm = this.cm, s = this.getSplitters();
52037 if(s){ // splitters not created yet
52038 var pos = 0, locked = true;
52039 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52040 if(cm.isHidden(i)) continue;
52041 var w = cm.getColumnWidth(i); // make sure it's a number
52042 if(!cm.isLocked(i) && locked){
52047 s[i].style.left = (pos-this.splitOffset) + "px";
52052 handleHiddenChange : function(colModel, colIndex, hidden){
52054 this.hideColumn(colIndex);
52056 this.unhideColumn(colIndex);
52060 hideColumn : function(colIndex){
52061 var cid = this.getColumnId(colIndex);
52062 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
52063 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
52065 this.updateHeaders();
52067 this.updateSplitters();
52071 unhideColumn : function(colIndex){
52072 var cid = this.getColumnId(colIndex);
52073 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
52074 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
52077 this.updateHeaders();
52079 this.updateSplitters();
52083 insertRows : function(dm, firstRow, lastRow, isUpdate){
52084 if(firstRow == 0 && lastRow == dm.getCount()-1){
52088 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
52090 var s = this.getScrollState();
52091 var markup = this.renderRows(firstRow, lastRow);
52092 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
52093 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
52094 this.restoreScroll(s);
52096 this.fireEvent("rowsinserted", this, firstRow, lastRow);
52097 this.syncRowHeights(firstRow, lastRow);
52098 this.stripeRows(firstRow);
52104 bufferRows : function(markup, target, index){
52105 var before = null, trows = target.rows, tbody = target.tBodies[0];
52106 if(index < trows.length){
52107 before = trows[index];
52109 var b = document.createElement("div");
52110 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
52111 var rows = b.firstChild.rows;
52112 for(var i = 0, len = rows.length; i < len; i++){
52114 tbody.insertBefore(rows[0], before);
52116 tbody.appendChild(rows[0]);
52123 deleteRows : function(dm, firstRow, lastRow){
52124 if(dm.getRowCount()<1){
52125 this.fireEvent("beforerefresh", this);
52126 this.mainBody.update("");
52127 this.lockedBody.update("");
52128 this.fireEvent("refresh", this);
52130 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
52131 var bt = this.getBodyTable();
52132 var tbody = bt.firstChild;
52133 var rows = bt.rows;
52134 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
52135 tbody.removeChild(rows[firstRow]);
52137 this.stripeRows(firstRow);
52138 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
52142 updateRows : function(dataSource, firstRow, lastRow){
52143 var s = this.getScrollState();
52145 this.restoreScroll(s);
52148 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
52152 this.updateHeaderSortState();
52155 getScrollState : function(){
52157 var sb = this.scroller.dom;
52158 return {left: sb.scrollLeft, top: sb.scrollTop};
52161 stripeRows : function(startRow){
52162 if(!this.grid.stripeRows || this.ds.getCount() < 1){
52165 startRow = startRow || 0;
52166 var rows = this.getBodyTable().rows;
52167 var lrows = this.getLockedTable().rows;
52168 var cls = ' x-grid-row-alt ';
52169 for(var i = startRow, len = rows.length; i < len; i++){
52170 var row = rows[i], lrow = lrows[i];
52171 var isAlt = ((i+1) % 2 == 0);
52172 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
52173 if(isAlt == hasAlt){
52177 row.className += " x-grid-row-alt";
52179 row.className = row.className.replace("x-grid-row-alt", "");
52182 lrow.className = row.className;
52187 restoreScroll : function(state){
52188 //Roo.log('GridView.restoreScroll');
52189 var sb = this.scroller.dom;
52190 sb.scrollLeft = state.left;
52191 sb.scrollTop = state.top;
52195 syncScroll : function(){
52196 //Roo.log('GridView.syncScroll');
52197 var sb = this.scroller.dom;
52198 var sh = this.mainHd.dom;
52199 var bs = this.mainBody.dom;
52200 var lv = this.lockedBody.dom;
52201 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
52202 lv.scrollTop = bs.scrollTop = sb.scrollTop;
52205 handleScroll : function(e){
52207 var sb = this.scroller.dom;
52208 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
52212 handleWheel : function(e){
52213 var d = e.getWheelDelta();
52214 this.scroller.dom.scrollTop -= d*22;
52215 // set this here to prevent jumpy scrolling on large tables
52216 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
52220 renderRows : function(startRow, endRow){
52221 // pull in all the crap needed to render rows
52222 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
52223 var colCount = cm.getColumnCount();
52225 if(ds.getCount() < 1){
52229 // build a map for all the columns
52231 for(var i = 0; i < colCount; i++){
52232 var name = cm.getDataIndex(i);
52234 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
52235 renderer : cm.getRenderer(i),
52236 id : cm.getColumnId(i),
52237 locked : cm.isLocked(i)
52241 startRow = startRow || 0;
52242 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
52244 // records to render
52245 var rs = ds.getRange(startRow, endRow);
52247 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
52250 // As much as I hate to duplicate code, this was branched because FireFox really hates
52251 // [].join("") on strings. The performance difference was substantial enough to
52252 // branch this function
52253 doRender : Roo.isGecko ?
52254 function(cs, rs, ds, startRow, colCount, stripe){
52255 var ts = this.templates, ct = ts.cell, rt = ts.row;
52257 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52259 var hasListener = this.grid.hasListener('rowclass');
52261 for(var j = 0, len = rs.length; j < len; j++){
52262 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
52263 for(var i = 0; i < colCount; i++){
52265 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52267 p.css = p.attr = "";
52268 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52269 if(p.value == undefined || p.value === "") p.value = " ";
52270 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52271 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52273 var markup = ct.apply(p);
52281 if(stripe && ((rowIndex+1) % 2 == 0)){
52282 alt.push("x-grid-row-alt")
52285 alt.push( " x-grid-dirty-row");
52288 if(this.getRowClass){
52289 alt.push(this.getRowClass(r, rowIndex));
52295 rowIndex : rowIndex,
52298 this.grid.fireEvent('rowclass', this, rowcfg);
52299 alt.push(rowcfg.rowClass);
52301 rp.alt = alt.join(" ");
52302 lbuf+= rt.apply(rp);
52304 buf+= rt.apply(rp);
52306 return [lbuf, buf];
52308 function(cs, rs, ds, startRow, colCount, stripe){
52309 var ts = this.templates, ct = ts.cell, rt = ts.row;
52311 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52312 var hasListener = this.grid.hasListener('rowclass');
52315 for(var j = 0, len = rs.length; j < len; j++){
52316 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
52317 for(var i = 0; i < colCount; i++){
52319 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52321 p.css = p.attr = "";
52322 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52323 if(p.value == undefined || p.value === "") p.value = " ";
52324 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52325 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52328 var markup = ct.apply(p);
52330 cb[cb.length] = markup;
52332 lcb[lcb.length] = markup;
52336 if(stripe && ((rowIndex+1) % 2 == 0)){
52337 alt.push( "x-grid-row-alt");
52340 alt.push(" x-grid-dirty-row");
52343 if(this.getRowClass){
52344 alt.push( this.getRowClass(r, rowIndex));
52350 rowIndex : rowIndex,
52353 this.grid.fireEvent('rowclass', this, rowcfg);
52354 alt.push(rowcfg.rowClass);
52356 rp.alt = alt.join(" ");
52357 rp.cells = lcb.join("");
52358 lbuf[lbuf.length] = rt.apply(rp);
52359 rp.cells = cb.join("");
52360 buf[buf.length] = rt.apply(rp);
52362 return [lbuf.join(""), buf.join("")];
52365 renderBody : function(){
52366 var markup = this.renderRows();
52367 var bt = this.templates.body;
52368 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
52372 * Refreshes the grid
52373 * @param {Boolean} headersToo
52375 refresh : function(headersToo){
52376 this.fireEvent("beforerefresh", this);
52377 this.grid.stopEditing();
52378 var result = this.renderBody();
52379 this.lockedBody.update(result[0]);
52380 this.mainBody.update(result[1]);
52381 if(headersToo === true){
52382 this.updateHeaders();
52383 this.updateColumns();
52384 this.updateSplitters();
52385 this.updateHeaderSortState();
52387 this.syncRowHeights();
52389 this.fireEvent("refresh", this);
52392 handleColumnMove : function(cm, oldIndex, newIndex){
52393 this.indexMap = null;
52394 var s = this.getScrollState();
52395 this.refresh(true);
52396 this.restoreScroll(s);
52397 this.afterMove(newIndex);
52400 afterMove : function(colIndex){
52401 if(this.enableMoveAnim && Roo.enableFx){
52402 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
52404 // if multisort - fix sortOrder, and reload..
52405 if (this.grid.dataSource.multiSort) {
52406 // the we can call sort again..
52407 var dm = this.grid.dataSource;
52408 var cm = this.grid.colModel;
52410 for(var i = 0; i < cm.config.length; i++ ) {
52412 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
52413 continue; // dont' bother, it's not in sort list or being set.
52416 so.push(cm.config[i].dataIndex);
52419 dm.load(dm.lastOptions);
52426 updateCell : function(dm, rowIndex, dataIndex){
52427 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
52428 if(typeof colIndex == "undefined"){ // not present in grid
52431 var cm = this.grid.colModel;
52432 var cell = this.getCell(rowIndex, colIndex);
52433 var cellText = this.getCellText(rowIndex, colIndex);
52436 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
52437 id : cm.getColumnId(colIndex),
52438 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
52440 var renderer = cm.getRenderer(colIndex);
52441 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
52442 if(typeof val == "undefined" || val === "") val = " ";
52443 cellText.innerHTML = val;
52444 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
52445 this.syncRowHeights(rowIndex, rowIndex);
52448 calcColumnWidth : function(colIndex, maxRowsToMeasure){
52450 if(this.grid.autoSizeHeaders){
52451 var h = this.getHeaderCellMeasure(colIndex);
52452 maxWidth = Math.max(maxWidth, h.scrollWidth);
52455 if(this.cm.isLocked(colIndex)){
52456 tb = this.getLockedTable();
52459 tb = this.getBodyTable();
52460 index = colIndex - this.cm.getLockedCount();
52463 var rows = tb.rows;
52464 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
52465 for(var i = 0; i < stopIndex; i++){
52466 var cell = rows[i].childNodes[index].firstChild;
52467 maxWidth = Math.max(maxWidth, cell.scrollWidth);
52470 return maxWidth + /*margin for error in IE*/ 5;
52473 * Autofit a column to its content.
52474 * @param {Number} colIndex
52475 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
52477 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
52478 if(this.cm.isHidden(colIndex)){
52479 return; // can't calc a hidden column
52482 var cid = this.cm.getColumnId(colIndex);
52483 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
52484 if(this.grid.autoSizeHeaders){
52485 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
52488 var newWidth = this.calcColumnWidth(colIndex);
52489 this.cm.setColumnWidth(colIndex,
52490 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
52491 if(!suppressEvent){
52492 this.grid.fireEvent("columnresize", colIndex, newWidth);
52497 * Autofits all columns to their content and then expands to fit any extra space in the grid
52499 autoSizeColumns : function(){
52500 var cm = this.grid.colModel;
52501 var colCount = cm.getColumnCount();
52502 for(var i = 0; i < colCount; i++){
52503 this.autoSizeColumn(i, true, true);
52505 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
52508 this.updateColumns();
52514 * Autofits all columns to the grid's width proportionate with their current size
52515 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
52517 fitColumns : function(reserveScrollSpace){
52518 var cm = this.grid.colModel;
52519 var colCount = cm.getColumnCount();
52523 for (i = 0; i < colCount; i++){
52524 if(!cm.isHidden(i) && !cm.isFixed(i)){
52525 w = cm.getColumnWidth(i);
52531 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
52532 if(reserveScrollSpace){
52535 var frac = (avail - cm.getTotalWidth())/width;
52536 while (cols.length){
52539 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
52541 this.updateColumns();
52545 onRowSelect : function(rowIndex){
52546 var row = this.getRowComposite(rowIndex);
52547 row.addClass("x-grid-row-selected");
52550 onRowDeselect : function(rowIndex){
52551 var row = this.getRowComposite(rowIndex);
52552 row.removeClass("x-grid-row-selected");
52555 onCellSelect : function(row, col){
52556 var cell = this.getCell(row, col);
52558 Roo.fly(cell).addClass("x-grid-cell-selected");
52562 onCellDeselect : function(row, col){
52563 var cell = this.getCell(row, col);
52565 Roo.fly(cell).removeClass("x-grid-cell-selected");
52569 updateHeaderSortState : function(){
52571 // sort state can be single { field: xxx, direction : yyy}
52572 // or { xxx=>ASC , yyy : DESC ..... }
52575 if (!this.ds.multiSort) {
52576 var state = this.ds.getSortState();
52580 mstate[state.field] = state.direction;
52581 // FIXME... - this is not used here.. but might be elsewhere..
52582 this.sortState = state;
52585 mstate = this.ds.sortToggle;
52587 //remove existing sort classes..
52589 var sc = this.sortClasses;
52590 var hds = this.el.select(this.headerSelector).removeClass(sc);
52592 for(var f in mstate) {
52594 var sortColumn = this.cm.findColumnIndex(f);
52596 if(sortColumn != -1){
52597 var sortDir = mstate[f];
52598 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
52607 handleHeaderClick : function(g, index){
52608 if(this.headersDisabled){
52611 var dm = g.dataSource, cm = g.colModel;
52612 if(!cm.isSortable(index)){
52617 if (dm.multiSort) {
52618 // update the sortOrder
52620 for(var i = 0; i < cm.config.length; i++ ) {
52622 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
52623 continue; // dont' bother, it's not in sort list or being set.
52626 so.push(cm.config[i].dataIndex);
52632 dm.sort(cm.getDataIndex(index));
52636 destroy : function(){
52638 this.colMenu.removeAll();
52639 Roo.menu.MenuMgr.unregister(this.colMenu);
52640 this.colMenu.getEl().remove();
52641 delete this.colMenu;
52644 this.hmenu.removeAll();
52645 Roo.menu.MenuMgr.unregister(this.hmenu);
52646 this.hmenu.getEl().remove();
52649 if(this.grid.enableColumnMove){
52650 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
52652 for(var dd in dds){
52653 if(!dds[dd].config.isTarget && dds[dd].dragElId){
52654 var elid = dds[dd].dragElId;
52656 Roo.get(elid).remove();
52657 } else if(dds[dd].config.isTarget){
52658 dds[dd].proxyTop.remove();
52659 dds[dd].proxyBottom.remove();
52662 if(Roo.dd.DDM.locationCache[dd]){
52663 delete Roo.dd.DDM.locationCache[dd];
52666 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
52669 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
52670 this.bind(null, null);
52671 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
52674 handleLockChange : function(){
52675 this.refresh(true);
52678 onDenyColumnLock : function(){
52682 onDenyColumnHide : function(){
52686 handleHdMenuClick : function(item){
52687 var index = this.hdCtxIndex;
52688 var cm = this.cm, ds = this.ds;
52691 ds.sort(cm.getDataIndex(index), "ASC");
52694 ds.sort(cm.getDataIndex(index), "DESC");
52697 var lc = cm.getLockedCount();
52698 if(cm.getColumnCount(true) <= lc+1){
52699 this.onDenyColumnLock();
52703 cm.setLocked(index, true, true);
52704 cm.moveColumn(index, lc);
52705 this.grid.fireEvent("columnmove", index, lc);
52707 cm.setLocked(index, true);
52711 var lc = cm.getLockedCount();
52712 if((lc-1) != index){
52713 cm.setLocked(index, false, true);
52714 cm.moveColumn(index, lc-1);
52715 this.grid.fireEvent("columnmove", index, lc-1);
52717 cm.setLocked(index, false);
52721 index = cm.getIndexById(item.id.substr(4));
52723 if(item.checked && cm.getColumnCount(true) <= 1){
52724 this.onDenyColumnHide();
52727 cm.setHidden(index, item.checked);
52733 beforeColMenuShow : function(){
52734 var cm = this.cm, colCount = cm.getColumnCount();
52735 this.colMenu.removeAll();
52736 for(var i = 0; i < colCount; i++){
52737 this.colMenu.add(new Roo.menu.CheckItem({
52738 id: "col-"+cm.getColumnId(i),
52739 text: cm.getColumnHeader(i),
52740 checked: !cm.isHidden(i),
52746 handleHdCtx : function(g, index, e){
52748 var hd = this.getHeaderCell(index);
52749 this.hdCtxIndex = index;
52750 var ms = this.hmenu.items, cm = this.cm;
52751 ms.get("asc").setDisabled(!cm.isSortable(index));
52752 ms.get("desc").setDisabled(!cm.isSortable(index));
52753 if(this.grid.enableColLock !== false){
52754 ms.get("lock").setDisabled(cm.isLocked(index));
52755 ms.get("unlock").setDisabled(!cm.isLocked(index));
52757 this.hmenu.show(hd, "tl-bl");
52760 handleHdOver : function(e){
52761 var hd = this.findHeaderCell(e.getTarget());
52762 if(hd && !this.headersDisabled){
52763 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
52764 this.fly(hd).addClass("x-grid-hd-over");
52769 handleHdOut : function(e){
52770 var hd = this.findHeaderCell(e.getTarget());
52772 this.fly(hd).removeClass("x-grid-hd-over");
52776 handleSplitDblClick : function(e, t){
52777 var i = this.getCellIndex(t);
52778 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
52779 this.autoSizeColumn(i, true);
52784 render : function(){
52787 var colCount = cm.getColumnCount();
52789 if(this.grid.monitorWindowResize === true){
52790 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52792 var header = this.renderHeaders();
52793 var body = this.templates.body.apply({rows:""});
52794 var html = this.templates.master.apply({
52797 lockedHeader: header[0],
52801 //this.updateColumns();
52803 this.grid.getGridEl().dom.innerHTML = html;
52805 this.initElements();
52807 // a kludge to fix the random scolling effect in webkit
52808 this.el.on("scroll", function() {
52809 this.el.dom.scrollTop=0; // hopefully not recursive..
52812 this.scroller.on("scroll", this.handleScroll, this);
52813 this.lockedBody.on("mousewheel", this.handleWheel, this);
52814 this.mainBody.on("mousewheel", this.handleWheel, this);
52816 this.mainHd.on("mouseover", this.handleHdOver, this);
52817 this.mainHd.on("mouseout", this.handleHdOut, this);
52818 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
52819 {delegate: "."+this.splitClass});
52821 this.lockedHd.on("mouseover", this.handleHdOver, this);
52822 this.lockedHd.on("mouseout", this.handleHdOut, this);
52823 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
52824 {delegate: "."+this.splitClass});
52826 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
52827 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52830 this.updateSplitters();
52832 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
52833 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52834 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52837 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
52838 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
52840 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
52841 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
52843 if(this.grid.enableColLock !== false){
52844 this.hmenu.add('-',
52845 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
52846 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
52849 if(this.grid.enableColumnHide !== false){
52851 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
52852 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
52853 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
52855 this.hmenu.add('-',
52856 {id:"columns", text: this.columnsText, menu: this.colMenu}
52859 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
52861 this.grid.on("headercontextmenu", this.handleHdCtx, this);
52864 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
52865 this.dd = new Roo.grid.GridDragZone(this.grid, {
52866 ddGroup : this.grid.ddGroup || 'GridDD'
52872 for(var i = 0; i < colCount; i++){
52873 if(cm.isHidden(i)){
52874 this.hideColumn(i);
52876 if(cm.config[i].align){
52877 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
52878 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
52882 this.updateHeaderSortState();
52884 this.beforeInitialResize();
52887 // two part rendering gives faster view to the user
52888 this.renderPhase2.defer(1, this);
52891 renderPhase2 : function(){
52892 // render the rows now
52894 if(this.grid.autoSizeColumns){
52895 this.autoSizeColumns();
52899 beforeInitialResize : function(){
52903 onColumnSplitterMoved : function(i, w){
52904 this.userResized = true;
52905 var cm = this.grid.colModel;
52906 cm.setColumnWidth(i, w, true);
52907 var cid = cm.getColumnId(i);
52908 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
52909 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
52910 this.updateSplitters();
52912 this.grid.fireEvent("columnresize", i, w);
52915 syncRowHeights : function(startIndex, endIndex){
52916 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
52917 startIndex = startIndex || 0;
52918 var mrows = this.getBodyTable().rows;
52919 var lrows = this.getLockedTable().rows;
52920 var len = mrows.length-1;
52921 endIndex = Math.min(endIndex || len, len);
52922 for(var i = startIndex; i <= endIndex; i++){
52923 var m = mrows[i], l = lrows[i];
52924 var h = Math.max(m.offsetHeight, l.offsetHeight);
52925 m.style.height = l.style.height = h + "px";
52930 layout : function(initialRender, is2ndPass){
52932 var auto = g.autoHeight;
52933 var scrollOffset = 16;
52934 var c = g.getGridEl(), cm = this.cm,
52935 expandCol = g.autoExpandColumn,
52937 //c.beginMeasure();
52939 if(!c.dom.offsetWidth){ // display:none?
52941 this.lockedWrap.show();
52942 this.mainWrap.show();
52947 var hasLock = this.cm.isLocked(0);
52949 var tbh = this.headerPanel.getHeight();
52950 var bbh = this.footerPanel.getHeight();
52953 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
52954 var newHeight = ch + c.getBorderWidth("tb");
52956 newHeight = Math.min(g.maxHeight, newHeight);
52958 c.setHeight(newHeight);
52962 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
52965 var s = this.scroller;
52967 var csize = c.getSize(true);
52969 this.el.setSize(csize.width, csize.height);
52971 this.headerPanel.setWidth(csize.width);
52972 this.footerPanel.setWidth(csize.width);
52974 var hdHeight = this.mainHd.getHeight();
52975 var vw = csize.width;
52976 var vh = csize.height - (tbh + bbh);
52980 var bt = this.getBodyTable();
52981 var ltWidth = hasLock ?
52982 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
52984 var scrollHeight = bt.offsetHeight;
52985 var scrollWidth = ltWidth + bt.offsetWidth;
52986 var vscroll = false, hscroll = false;
52988 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
52990 var lw = this.lockedWrap, mw = this.mainWrap;
52991 var lb = this.lockedBody, mb = this.mainBody;
52993 setTimeout(function(){
52994 var t = s.dom.offsetTop;
52995 var w = s.dom.clientWidth,
52996 h = s.dom.clientHeight;
52999 lw.setSize(ltWidth, h);
53001 mw.setLeftTop(ltWidth, t);
53002 mw.setSize(w-ltWidth, h);
53004 lb.setHeight(h-hdHeight);
53005 mb.setHeight(h-hdHeight);
53007 if(is2ndPass !== true && !gv.userResized && expandCol){
53008 // high speed resize without full column calculation
53010 var ci = cm.getIndexById(expandCol);
53012 ci = cm.findColumnIndex(expandCol);
53014 ci = Math.max(0, ci); // make sure it's got at least the first col.
53015 var expandId = cm.getColumnId(ci);
53016 var tw = cm.getTotalWidth(false);
53017 var currentWidth = cm.getColumnWidth(ci);
53018 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
53019 if(currentWidth != cw){
53020 cm.setColumnWidth(ci, cw, true);
53021 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53022 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53023 gv.updateSplitters();
53024 gv.layout(false, true);
53036 onWindowResize : function(){
53037 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
53043 appendFooter : function(parentEl){
53047 sortAscText : "Sort Ascending",
53048 sortDescText : "Sort Descending",
53049 lockText : "Lock Column",
53050 unlockText : "Unlock Column",
53051 columnsText : "Columns"
53055 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
53056 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
53057 this.proxy.el.addClass('x-grid3-col-dd');
53060 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
53061 handleMouseDown : function(e){
53065 callHandleMouseDown : function(e){
53066 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
53071 * Ext JS Library 1.1.1
53072 * Copyright(c) 2006-2007, Ext JS, LLC.
53074 * Originally Released Under LGPL - original licence link has changed is not relivant.
53077 * <script type="text/javascript">
53081 // This is a support class used internally by the Grid components
53082 Roo.grid.SplitDragZone = function(grid, hd, hd2){
53084 this.view = grid.getView();
53085 this.proxy = this.view.resizeProxy;
53086 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
53087 "gridSplitters" + this.grid.getGridEl().id, {
53088 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
53090 this.setHandleElId(Roo.id(hd));
53091 this.setOuterHandleElId(Roo.id(hd2));
53092 this.scroll = false;
53094 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
53095 fly: Roo.Element.fly,
53097 b4StartDrag : function(x, y){
53098 this.view.headersDisabled = true;
53099 this.proxy.setHeight(this.view.mainWrap.getHeight());
53100 var w = this.cm.getColumnWidth(this.cellIndex);
53101 var minw = Math.max(w-this.grid.minColumnWidth, 0);
53102 this.resetConstraints();
53103 this.setXConstraint(minw, 1000);
53104 this.setYConstraint(0, 0);
53105 this.minX = x - minw;
53106 this.maxX = x + 1000;
53108 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
53112 handleMouseDown : function(e){
53113 ev = Roo.EventObject.setEvent(e);
53114 var t = this.fly(ev.getTarget());
53115 if(t.hasClass("x-grid-split")){
53116 this.cellIndex = this.view.getCellIndex(t.dom);
53117 this.split = t.dom;
53118 this.cm = this.grid.colModel;
53119 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
53120 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
53125 endDrag : function(e){
53126 this.view.headersDisabled = false;
53127 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
53128 var diff = endX - this.startPos;
53129 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
53132 autoOffset : function(){
53133 this.setDelta(0,0);
53137 * Ext JS Library 1.1.1
53138 * Copyright(c) 2006-2007, Ext JS, LLC.
53140 * Originally Released Under LGPL - original licence link has changed is not relivant.
53143 * <script type="text/javascript">
53147 // This is a support class used internally by the Grid components
53148 Roo.grid.GridDragZone = function(grid, config){
53149 this.view = grid.getView();
53150 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
53151 if(this.view.lockedBody){
53152 this.setHandleElId(Roo.id(this.view.mainBody.dom));
53153 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
53155 this.scroll = false;
53157 this.ddel = document.createElement('div');
53158 this.ddel.className = 'x-grid-dd-wrap';
53161 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
53162 ddGroup : "GridDD",
53164 getDragData : function(e){
53165 var t = Roo.lib.Event.getTarget(e);
53166 var rowIndex = this.view.findRowIndex(t);
53167 var sm = this.grid.selModel;
53169 //Roo.log(rowIndex);
53171 if (sm.getSelectedCell) {
53172 // cell selection..
53173 if (!sm.getSelectedCell()) {
53176 if (rowIndex != sm.getSelectedCell()[0]) {
53182 if(rowIndex !== false){
53187 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
53189 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
53192 if (e.hasModifier()){
53193 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
53196 Roo.log("getDragData");
53201 rowIndex: rowIndex,
53202 selections:sm.getSelections ? sm.getSelections() : (
53203 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
53210 onInitDrag : function(e){
53211 var data = this.dragData;
53212 this.ddel.innerHTML = this.grid.getDragDropText();
53213 this.proxy.update(this.ddel);
53214 // fire start drag?
53217 afterRepair : function(){
53218 this.dragging = false;
53221 getRepairXY : function(e, data){
53225 onEndDrag : function(data, e){
53229 onValidDrop : function(dd, e, id){
53234 beforeInvalidDrop : function(e, id){
53239 * Ext JS Library 1.1.1
53240 * Copyright(c) 2006-2007, Ext JS, LLC.
53242 * Originally Released Under LGPL - original licence link has changed is not relivant.
53245 * <script type="text/javascript">
53250 * @class Roo.grid.ColumnModel
53251 * @extends Roo.util.Observable
53252 * This is the default implementation of a ColumnModel used by the Grid. It defines
53253 * the columns in the grid.
53256 var colModel = new Roo.grid.ColumnModel([
53257 {header: "Ticker", width: 60, sortable: true, locked: true},
53258 {header: "Company Name", width: 150, sortable: true},
53259 {header: "Market Cap.", width: 100, sortable: true},
53260 {header: "$ Sales", width: 100, sortable: true, renderer: money},
53261 {header: "Employees", width: 100, sortable: true, resizable: false}
53266 * The config options listed for this class are options which may appear in each
53267 * individual column definition.
53268 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
53270 * @param {Object} config An Array of column config objects. See this class's
53271 * config objects for details.
53273 Roo.grid.ColumnModel = function(config){
53275 * The config passed into the constructor
53277 this.config = config;
53280 // if no id, create one
53281 // if the column does not have a dataIndex mapping,
53282 // map it to the order it is in the config
53283 for(var i = 0, len = config.length; i < len; i++){
53285 if(typeof c.dataIndex == "undefined"){
53288 if(typeof c.renderer == "string"){
53289 c.renderer = Roo.util.Format[c.renderer];
53291 if(typeof c.id == "undefined"){
53294 if(c.editor && c.editor.xtype){
53295 c.editor = Roo.factory(c.editor, Roo.grid);
53297 if(c.editor && c.editor.isFormField){
53298 c.editor = new Roo.grid.GridEditor(c.editor);
53300 this.lookup[c.id] = c;
53304 * The width of columns which have no width specified (defaults to 100)
53307 this.defaultWidth = 100;
53310 * Default sortable of columns which have no sortable specified (defaults to false)
53313 this.defaultSortable = false;
53317 * @event widthchange
53318 * Fires when the width of a column changes.
53319 * @param {ColumnModel} this
53320 * @param {Number} columnIndex The column index
53321 * @param {Number} newWidth The new width
53323 "widthchange": true,
53325 * @event headerchange
53326 * Fires when the text of a header changes.
53327 * @param {ColumnModel} this
53328 * @param {Number} columnIndex The column index
53329 * @param {Number} newText The new header text
53331 "headerchange": true,
53333 * @event hiddenchange
53334 * Fires when a column is hidden or "unhidden".
53335 * @param {ColumnModel} this
53336 * @param {Number} columnIndex The column index
53337 * @param {Boolean} hidden true if hidden, false otherwise
53339 "hiddenchange": true,
53341 * @event columnmoved
53342 * Fires when a column is moved.
53343 * @param {ColumnModel} this
53344 * @param {Number} oldIndex
53345 * @param {Number} newIndex
53347 "columnmoved" : true,
53349 * @event columlockchange
53350 * Fires when a column's locked state is changed
53351 * @param {ColumnModel} this
53352 * @param {Number} colIndex
53353 * @param {Boolean} locked true if locked
53355 "columnlockchange" : true
53357 Roo.grid.ColumnModel.superclass.constructor.call(this);
53359 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
53361 * @cfg {String} header The header text to display in the Grid view.
53364 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
53365 * {@link Roo.data.Record} definition from which to draw the column's value. If not
53366 * specified, the column's index is used as an index into the Record's data Array.
53369 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
53370 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
53373 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
53374 * Defaults to the value of the {@link #defaultSortable} property.
53375 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
53378 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
53381 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
53384 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
53387 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
53390 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
53391 * given the cell's data value. See {@link #setRenderer}. If not specified, the
53392 * default renderer uses the raw data value.
53395 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
53398 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
53402 * Returns the id of the column at the specified index.
53403 * @param {Number} index The column index
53404 * @return {String} the id
53406 getColumnId : function(index){
53407 return this.config[index].id;
53411 * Returns the column for a specified id.
53412 * @param {String} id The column id
53413 * @return {Object} the column
53415 getColumnById : function(id){
53416 return this.lookup[id];
53421 * Returns the column for a specified dataIndex.
53422 * @param {String} dataIndex The column dataIndex
53423 * @return {Object|Boolean} the column or false if not found
53425 getColumnByDataIndex: function(dataIndex){
53426 var index = this.findColumnIndex(dataIndex);
53427 return index > -1 ? this.config[index] : false;
53431 * Returns the index for a specified column id.
53432 * @param {String} id The column id
53433 * @return {Number} the index, or -1 if not found
53435 getIndexById : function(id){
53436 for(var i = 0, len = this.config.length; i < len; i++){
53437 if(this.config[i].id == id){
53445 * Returns the index for a specified column dataIndex.
53446 * @param {String} dataIndex The column dataIndex
53447 * @return {Number} the index, or -1 if not found
53450 findColumnIndex : function(dataIndex){
53451 for(var i = 0, len = this.config.length; i < len; i++){
53452 if(this.config[i].dataIndex == dataIndex){
53460 moveColumn : function(oldIndex, newIndex){
53461 var c = this.config[oldIndex];
53462 this.config.splice(oldIndex, 1);
53463 this.config.splice(newIndex, 0, c);
53464 this.dataMap = null;
53465 this.fireEvent("columnmoved", this, oldIndex, newIndex);
53468 isLocked : function(colIndex){
53469 return this.config[colIndex].locked === true;
53472 setLocked : function(colIndex, value, suppressEvent){
53473 if(this.isLocked(colIndex) == value){
53476 this.config[colIndex].locked = value;
53477 if(!suppressEvent){
53478 this.fireEvent("columnlockchange", this, colIndex, value);
53482 getTotalLockedWidth : function(){
53483 var totalWidth = 0;
53484 for(var i = 0; i < this.config.length; i++){
53485 if(this.isLocked(i) && !this.isHidden(i)){
53486 this.totalWidth += this.getColumnWidth(i);
53492 getLockedCount : function(){
53493 for(var i = 0, len = this.config.length; i < len; i++){
53494 if(!this.isLocked(i)){
53501 * Returns the number of columns.
53504 getColumnCount : function(visibleOnly){
53505 if(visibleOnly === true){
53507 for(var i = 0, len = this.config.length; i < len; i++){
53508 if(!this.isHidden(i)){
53514 return this.config.length;
53518 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
53519 * @param {Function} fn
53520 * @param {Object} scope (optional)
53521 * @return {Array} result
53523 getColumnsBy : function(fn, scope){
53525 for(var i = 0, len = this.config.length; i < len; i++){
53526 var c = this.config[i];
53527 if(fn.call(scope||this, c, i) === true){
53535 * Returns true if the specified column is sortable.
53536 * @param {Number} col The column index
53537 * @return {Boolean}
53539 isSortable : function(col){
53540 if(typeof this.config[col].sortable == "undefined"){
53541 return this.defaultSortable;
53543 return this.config[col].sortable;
53547 * Returns the rendering (formatting) function defined for the column.
53548 * @param {Number} col The column index.
53549 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
53551 getRenderer : function(col){
53552 if(!this.config[col].renderer){
53553 return Roo.grid.ColumnModel.defaultRenderer;
53555 return this.config[col].renderer;
53559 * Sets the rendering (formatting) function for a column.
53560 * @param {Number} col The column index
53561 * @param {Function} fn The function to use to process the cell's raw data
53562 * to return HTML markup for the grid view. The render function is called with
53563 * the following parameters:<ul>
53564 * <li>Data value.</li>
53565 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
53566 * <li>css A CSS style string to apply to the table cell.</li>
53567 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
53568 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
53569 * <li>Row index</li>
53570 * <li>Column index</li>
53571 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
53573 setRenderer : function(col, fn){
53574 this.config[col].renderer = fn;
53578 * Returns the width for the specified column.
53579 * @param {Number} col The column index
53582 getColumnWidth : function(col){
53583 return this.config[col].width * 1 || this.defaultWidth;
53587 * Sets the width for a column.
53588 * @param {Number} col The column index
53589 * @param {Number} width The new width
53591 setColumnWidth : function(col, width, suppressEvent){
53592 this.config[col].width = width;
53593 this.totalWidth = null;
53594 if(!suppressEvent){
53595 this.fireEvent("widthchange", this, col, width);
53600 * Returns the total width of all columns.
53601 * @param {Boolean} includeHidden True to include hidden column widths
53604 getTotalWidth : function(includeHidden){
53605 if(!this.totalWidth){
53606 this.totalWidth = 0;
53607 for(var i = 0, len = this.config.length; i < len; i++){
53608 if(includeHidden || !this.isHidden(i)){
53609 this.totalWidth += this.getColumnWidth(i);
53613 return this.totalWidth;
53617 * Returns the header for the specified column.
53618 * @param {Number} col The column index
53621 getColumnHeader : function(col){
53622 return this.config[col].header;
53626 * Sets the header for a column.
53627 * @param {Number} col The column index
53628 * @param {String} header The new header
53630 setColumnHeader : function(col, header){
53631 this.config[col].header = header;
53632 this.fireEvent("headerchange", this, col, header);
53636 * Returns the tooltip for the specified column.
53637 * @param {Number} col The column index
53640 getColumnTooltip : function(col){
53641 return this.config[col].tooltip;
53644 * Sets the tooltip for a column.
53645 * @param {Number} col The column index
53646 * @param {String} tooltip The new tooltip
53648 setColumnTooltip : function(col, tooltip){
53649 this.config[col].tooltip = tooltip;
53653 * Returns the dataIndex for the specified column.
53654 * @param {Number} col The column index
53657 getDataIndex : function(col){
53658 return this.config[col].dataIndex;
53662 * Sets the dataIndex for a column.
53663 * @param {Number} col The column index
53664 * @param {Number} dataIndex The new dataIndex
53666 setDataIndex : function(col, dataIndex){
53667 this.config[col].dataIndex = dataIndex;
53673 * Returns true if the cell is editable.
53674 * @param {Number} colIndex The column index
53675 * @param {Number} rowIndex The row index
53676 * @return {Boolean}
53678 isCellEditable : function(colIndex, rowIndex){
53679 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
53683 * Returns the editor defined for the cell/column.
53684 * return false or null to disable editing.
53685 * @param {Number} colIndex The column index
53686 * @param {Number} rowIndex The row index
53689 getCellEditor : function(colIndex, rowIndex){
53690 return this.config[colIndex].editor;
53694 * Sets if a column is editable.
53695 * @param {Number} col The column index
53696 * @param {Boolean} editable True if the column is editable
53698 setEditable : function(col, editable){
53699 this.config[col].editable = editable;
53704 * Returns true if the column is hidden.
53705 * @param {Number} colIndex The column index
53706 * @return {Boolean}
53708 isHidden : function(colIndex){
53709 return this.config[colIndex].hidden;
53714 * Returns true if the column width cannot be changed
53716 isFixed : function(colIndex){
53717 return this.config[colIndex].fixed;
53721 * Returns true if the column can be resized
53722 * @return {Boolean}
53724 isResizable : function(colIndex){
53725 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
53728 * Sets if a column is hidden.
53729 * @param {Number} colIndex The column index
53730 * @param {Boolean} hidden True if the column is hidden
53732 setHidden : function(colIndex, hidden){
53733 this.config[colIndex].hidden = hidden;
53734 this.totalWidth = null;
53735 this.fireEvent("hiddenchange", this, colIndex, hidden);
53739 * Sets the editor for a column.
53740 * @param {Number} col The column index
53741 * @param {Object} editor The editor object
53743 setEditor : function(col, editor){
53744 this.config[col].editor = editor;
53748 Roo.grid.ColumnModel.defaultRenderer = function(value){
53749 if(typeof value == "string" && value.length < 1){
53755 // Alias for backwards compatibility
53756 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
53759 * Ext JS Library 1.1.1
53760 * Copyright(c) 2006-2007, Ext JS, LLC.
53762 * Originally Released Under LGPL - original licence link has changed is not relivant.
53765 * <script type="text/javascript">
53769 * @class Roo.grid.AbstractSelectionModel
53770 * @extends Roo.util.Observable
53771 * Abstract base class for grid SelectionModels. It provides the interface that should be
53772 * implemented by descendant classes. This class should not be directly instantiated.
53775 Roo.grid.AbstractSelectionModel = function(){
53776 this.locked = false;
53777 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
53780 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
53781 /** @ignore Called by the grid automatically. Do not call directly. */
53782 init : function(grid){
53788 * Locks the selections.
53791 this.locked = true;
53795 * Unlocks the selections.
53797 unlock : function(){
53798 this.locked = false;
53802 * Returns true if the selections are locked.
53803 * @return {Boolean}
53805 isLocked : function(){
53806 return this.locked;
53810 * Ext JS Library 1.1.1
53811 * Copyright(c) 2006-2007, Ext JS, LLC.
53813 * Originally Released Under LGPL - original licence link has changed is not relivant.
53816 * <script type="text/javascript">
53819 * @extends Roo.grid.AbstractSelectionModel
53820 * @class Roo.grid.RowSelectionModel
53821 * The default SelectionModel used by {@link Roo.grid.Grid}.
53822 * It supports multiple selections and keyboard selection/navigation.
53824 * @param {Object} config
53826 Roo.grid.RowSelectionModel = function(config){
53827 Roo.apply(this, config);
53828 this.selections = new Roo.util.MixedCollection(false, function(o){
53833 this.lastActive = false;
53837 * @event selectionchange
53838 * Fires when the selection changes
53839 * @param {SelectionModel} this
53841 "selectionchange" : true,
53843 * @event afterselectionchange
53844 * Fires after the selection changes (eg. by key press or clicking)
53845 * @param {SelectionModel} this
53847 "afterselectionchange" : true,
53849 * @event beforerowselect
53850 * Fires when a row is selected being selected, return false to cancel.
53851 * @param {SelectionModel} this
53852 * @param {Number} rowIndex The selected index
53853 * @param {Boolean} keepExisting False if other selections will be cleared
53855 "beforerowselect" : true,
53858 * Fires when a row is selected.
53859 * @param {SelectionModel} this
53860 * @param {Number} rowIndex The selected index
53861 * @param {Roo.data.Record} r The record
53863 "rowselect" : true,
53865 * @event rowdeselect
53866 * Fires when a row is deselected.
53867 * @param {SelectionModel} this
53868 * @param {Number} rowIndex The selected index
53870 "rowdeselect" : true
53872 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
53873 this.locked = false;
53876 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
53878 * @cfg {Boolean} singleSelect
53879 * True to allow selection of only one row at a time (defaults to false)
53881 singleSelect : false,
53884 initEvents : function(){
53886 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
53887 this.grid.on("mousedown", this.handleMouseDown, this);
53888 }else{ // allow click to work like normal
53889 this.grid.on("rowclick", this.handleDragableRowClick, this);
53892 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
53893 "up" : function(e){
53895 this.selectPrevious(e.shiftKey);
53896 }else if(this.last !== false && this.lastActive !== false){
53897 var last = this.last;
53898 this.selectRange(this.last, this.lastActive-1);
53899 this.grid.getView().focusRow(this.lastActive);
53900 if(last !== false){
53904 this.selectFirstRow();
53906 this.fireEvent("afterselectionchange", this);
53908 "down" : function(e){
53910 this.selectNext(e.shiftKey);
53911 }else if(this.last !== false && this.lastActive !== false){
53912 var last = this.last;
53913 this.selectRange(this.last, this.lastActive+1);
53914 this.grid.getView().focusRow(this.lastActive);
53915 if(last !== false){
53919 this.selectFirstRow();
53921 this.fireEvent("afterselectionchange", this);
53926 var view = this.grid.view;
53927 view.on("refresh", this.onRefresh, this);
53928 view.on("rowupdated", this.onRowUpdated, this);
53929 view.on("rowremoved", this.onRemove, this);
53933 onRefresh : function(){
53934 var ds = this.grid.dataSource, i, v = this.grid.view;
53935 var s = this.selections;
53936 s.each(function(r){
53937 if((i = ds.indexOfId(r.id)) != -1){
53946 onRemove : function(v, index, r){
53947 this.selections.remove(r);
53951 onRowUpdated : function(v, index, r){
53952 if(this.isSelected(r)){
53953 v.onRowSelect(index);
53959 * @param {Array} records The records to select
53960 * @param {Boolean} keepExisting (optional) True to keep existing selections
53962 selectRecords : function(records, keepExisting){
53964 this.clearSelections();
53966 var ds = this.grid.dataSource;
53967 for(var i = 0, len = records.length; i < len; i++){
53968 this.selectRow(ds.indexOf(records[i]), true);
53973 * Gets the number of selected rows.
53976 getCount : function(){
53977 return this.selections.length;
53981 * Selects the first row in the grid.
53983 selectFirstRow : function(){
53988 * Select the last row.
53989 * @param {Boolean} keepExisting (optional) True to keep existing selections
53991 selectLastRow : function(keepExisting){
53992 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
53996 * Selects the row immediately following the last selected row.
53997 * @param {Boolean} keepExisting (optional) True to keep existing selections
53999 selectNext : function(keepExisting){
54000 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
54001 this.selectRow(this.last+1, keepExisting);
54002 this.grid.getView().focusRow(this.last);
54007 * Selects the row that precedes the last selected row.
54008 * @param {Boolean} keepExisting (optional) True to keep existing selections
54010 selectPrevious : function(keepExisting){
54012 this.selectRow(this.last-1, keepExisting);
54013 this.grid.getView().focusRow(this.last);
54018 * Returns the selected records
54019 * @return {Array} Array of selected records
54021 getSelections : function(){
54022 return [].concat(this.selections.items);
54026 * Returns the first selected record.
54029 getSelected : function(){
54030 return this.selections.itemAt(0);
54035 * Clears all selections.
54037 clearSelections : function(fast){
54038 if(this.locked) return;
54040 var ds = this.grid.dataSource;
54041 var s = this.selections;
54042 s.each(function(r){
54043 this.deselectRow(ds.indexOfId(r.id));
54047 this.selections.clear();
54054 * Selects all rows.
54056 selectAll : function(){
54057 if(this.locked) return;
54058 this.selections.clear();
54059 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
54060 this.selectRow(i, true);
54065 * Returns True if there is a selection.
54066 * @return {Boolean}
54068 hasSelection : function(){
54069 return this.selections.length > 0;
54073 * Returns True if the specified row is selected.
54074 * @param {Number/Record} record The record or index of the record to check
54075 * @return {Boolean}
54077 isSelected : function(index){
54078 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
54079 return (r && this.selections.key(r.id) ? true : false);
54083 * Returns True if the specified record id is selected.
54084 * @param {String} id The id of record to check
54085 * @return {Boolean}
54087 isIdSelected : function(id){
54088 return (this.selections.key(id) ? true : false);
54092 handleMouseDown : function(e, t){
54093 var view = this.grid.getView(), rowIndex;
54094 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
54097 if(e.shiftKey && this.last !== false){
54098 var last = this.last;
54099 this.selectRange(last, rowIndex, e.ctrlKey);
54100 this.last = last; // reset the last
54101 view.focusRow(rowIndex);
54103 var isSelected = this.isSelected(rowIndex);
54104 if(e.button !== 0 && isSelected){
54105 view.focusRow(rowIndex);
54106 }else if(e.ctrlKey && isSelected){
54107 this.deselectRow(rowIndex);
54108 }else if(!isSelected){
54109 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
54110 view.focusRow(rowIndex);
54113 this.fireEvent("afterselectionchange", this);
54116 handleDragableRowClick : function(grid, rowIndex, e)
54118 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
54119 this.selectRow(rowIndex, false);
54120 grid.view.focusRow(rowIndex);
54121 this.fireEvent("afterselectionchange", this);
54126 * Selects multiple rows.
54127 * @param {Array} rows Array of the indexes of the row to select
54128 * @param {Boolean} keepExisting (optional) True to keep existing selections
54130 selectRows : function(rows, keepExisting){
54132 this.clearSelections();
54134 for(var i = 0, len = rows.length; i < len; i++){
54135 this.selectRow(rows[i], true);
54140 * Selects a range of rows. All rows in between startRow and endRow are also selected.
54141 * @param {Number} startRow The index of the first row in the range
54142 * @param {Number} endRow The index of the last row in the range
54143 * @param {Boolean} keepExisting (optional) True to retain existing selections
54145 selectRange : function(startRow, endRow, keepExisting){
54146 if(this.locked) return;
54148 this.clearSelections();
54150 if(startRow <= endRow){
54151 for(var i = startRow; i <= endRow; i++){
54152 this.selectRow(i, true);
54155 for(var i = startRow; i >= endRow; i--){
54156 this.selectRow(i, true);
54162 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
54163 * @param {Number} startRow The index of the first row in the range
54164 * @param {Number} endRow The index of the last row in the range
54166 deselectRange : function(startRow, endRow, preventViewNotify){
54167 if(this.locked) return;
54168 for(var i = startRow; i <= endRow; i++){
54169 this.deselectRow(i, preventViewNotify);
54175 * @param {Number} row The index of the row to select
54176 * @param {Boolean} keepExisting (optional) True to keep existing selections
54178 selectRow : function(index, keepExisting, preventViewNotify){
54179 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
54180 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
54181 if(!keepExisting || this.singleSelect){
54182 this.clearSelections();
54184 var r = this.grid.dataSource.getAt(index);
54185 this.selections.add(r);
54186 this.last = this.lastActive = index;
54187 if(!preventViewNotify){
54188 this.grid.getView().onRowSelect(index);
54190 this.fireEvent("rowselect", this, index, r);
54191 this.fireEvent("selectionchange", this);
54197 * @param {Number} row The index of the row to deselect
54199 deselectRow : function(index, preventViewNotify){
54200 if(this.locked) return;
54201 if(this.last == index){
54204 if(this.lastActive == index){
54205 this.lastActive = false;
54207 var r = this.grid.dataSource.getAt(index);
54208 this.selections.remove(r);
54209 if(!preventViewNotify){
54210 this.grid.getView().onRowDeselect(index);
54212 this.fireEvent("rowdeselect", this, index);
54213 this.fireEvent("selectionchange", this);
54217 restoreLast : function(){
54219 this.last = this._last;
54224 acceptsNav : function(row, col, cm){
54225 return !cm.isHidden(col) && cm.isCellEditable(col, row);
54229 onEditorKey : function(field, e){
54230 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
54235 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
54237 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54239 }else if(k == e.ENTER && !e.ctrlKey){
54243 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
54245 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
54247 }else if(k == e.ESC){
54251 g.startEditing(newCell[0], newCell[1]);
54256 * Ext JS Library 1.1.1
54257 * Copyright(c) 2006-2007, Ext JS, LLC.
54259 * Originally Released Under LGPL - original licence link has changed is not relivant.
54262 * <script type="text/javascript">
54265 * @class Roo.grid.CellSelectionModel
54266 * @extends Roo.grid.AbstractSelectionModel
54267 * This class provides the basic implementation for cell selection in a grid.
54269 * @param {Object} config The object containing the configuration of this model.
54270 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
54272 Roo.grid.CellSelectionModel = function(config){
54273 Roo.apply(this, config);
54275 this.selection = null;
54279 * @event beforerowselect
54280 * Fires before a cell is selected.
54281 * @param {SelectionModel} this
54282 * @param {Number} rowIndex The selected row index
54283 * @param {Number} colIndex The selected cell index
54285 "beforecellselect" : true,
54287 * @event cellselect
54288 * Fires when a cell is selected.
54289 * @param {SelectionModel} this
54290 * @param {Number} rowIndex The selected row index
54291 * @param {Number} colIndex The selected cell index
54293 "cellselect" : true,
54295 * @event selectionchange
54296 * Fires when the active selection changes.
54297 * @param {SelectionModel} this
54298 * @param {Object} selection null for no selection or an object (o) with two properties
54300 <li>o.record: the record object for the row the selection is in</li>
54301 <li>o.cell: An array of [rowIndex, columnIndex]</li>
54304 "selectionchange" : true,
54307 * Fires when the tab (or enter) was pressed on the last editable cell
54308 * You can use this to trigger add new row.
54309 * @param {SelectionModel} this
54313 * @event beforeeditnext
54314 * Fires before the next editable sell is made active
54315 * You can use this to skip to another cell or fire the tabend
54316 * if you set cell to false
54317 * @param {Object} eventdata object : { cell : [ row, col ] }
54319 "beforeeditnext" : true
54321 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
54324 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
54326 enter_is_tab: false,
54329 initEvents : function(){
54330 this.grid.on("mousedown", this.handleMouseDown, this);
54331 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
54332 var view = this.grid.view;
54333 view.on("refresh", this.onViewChange, this);
54334 view.on("rowupdated", this.onRowUpdated, this);
54335 view.on("beforerowremoved", this.clearSelections, this);
54336 view.on("beforerowsinserted", this.clearSelections, this);
54337 if(this.grid.isEditor){
54338 this.grid.on("beforeedit", this.beforeEdit, this);
54343 beforeEdit : function(e){
54344 this.select(e.row, e.column, false, true, e.record);
54348 onRowUpdated : function(v, index, r){
54349 if(this.selection && this.selection.record == r){
54350 v.onCellSelect(index, this.selection.cell[1]);
54355 onViewChange : function(){
54356 this.clearSelections(true);
54360 * Returns the currently selected cell,.
54361 * @return {Array} The selected cell (row, column) or null if none selected.
54363 getSelectedCell : function(){
54364 return this.selection ? this.selection.cell : null;
54368 * Clears all selections.
54369 * @param {Boolean} true to prevent the gridview from being notified about the change.
54371 clearSelections : function(preventNotify){
54372 var s = this.selection;
54374 if(preventNotify !== true){
54375 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
54377 this.selection = null;
54378 this.fireEvent("selectionchange", this, null);
54383 * Returns true if there is a selection.
54384 * @return {Boolean}
54386 hasSelection : function(){
54387 return this.selection ? true : false;
54391 handleMouseDown : function(e, t){
54392 var v = this.grid.getView();
54393 if(this.isLocked()){
54396 var row = v.findRowIndex(t);
54397 var cell = v.findCellIndex(t);
54398 if(row !== false && cell !== false){
54399 this.select(row, cell);
54405 * @param {Number} rowIndex
54406 * @param {Number} collIndex
54408 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
54409 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
54410 this.clearSelections();
54411 r = r || this.grid.dataSource.getAt(rowIndex);
54414 cell : [rowIndex, colIndex]
54416 if(!preventViewNotify){
54417 var v = this.grid.getView();
54418 v.onCellSelect(rowIndex, colIndex);
54419 if(preventFocus !== true){
54420 v.focusCell(rowIndex, colIndex);
54423 this.fireEvent("cellselect", this, rowIndex, colIndex);
54424 this.fireEvent("selectionchange", this, this.selection);
54429 isSelectable : function(rowIndex, colIndex, cm){
54430 return !cm.isHidden(colIndex);
54434 handleKeyDown : function(e){
54435 //Roo.log('Cell Sel Model handleKeyDown');
54436 if(!e.isNavKeyPress()){
54439 var g = this.grid, s = this.selection;
54442 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
54444 this.select(cell[0], cell[1]);
54449 var walk = function(row, col, step){
54450 return g.walkCells(row, col, step, sm.isSelectable, sm);
54452 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
54459 // handled by onEditorKey
54460 if (g.isEditor && g.editing) {
54464 newCell = walk(r, c-1, -1);
54466 newCell = walk(r, c+1, 1);
54471 newCell = walk(r+1, c, 1);
54475 newCell = walk(r-1, c, -1);
54479 newCell = walk(r, c+1, 1);
54483 newCell = walk(r, c-1, -1);
54488 if(g.isEditor && !g.editing){
54489 g.startEditing(r, c);
54498 this.select(newCell[0], newCell[1]);
54504 acceptsNav : function(row, col, cm){
54505 return !cm.isHidden(col) && cm.isCellEditable(col, row);
54509 * @param {Number} field (not used) - as it's normally used as a listener
54510 * @param {Number} e - event - fake it by using
54512 * var e = Roo.EventObjectImpl.prototype;
54513 * e.keyCode = e.TAB
54517 onEditorKey : function(field, e){
54519 var k = e.getKey(),
54522 ed = g.activeEditor,
54524 ///Roo.log('onEditorKey' + k);
54527 if (this.enter_is_tab && k == e.ENTER) {
54533 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
54535 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54541 } else if(k == e.ENTER && !e.ctrlKey){
54544 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54546 } else if(k == e.ESC){
54551 var ecall = { cell : newCell, forward : forward };
54552 this.fireEvent('beforeeditnext', ecall );
54553 newCell = ecall.cell;
54554 forward = ecall.forward;
54558 //Roo.log('next cell after edit');
54559 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
54560 } else if (forward) {
54561 // tabbed past last
54562 this.fireEvent.defer(100, this, ['tabend',this]);
54567 * Ext JS Library 1.1.1
54568 * Copyright(c) 2006-2007, Ext JS, LLC.
54570 * Originally Released Under LGPL - original licence link has changed is not relivant.
54573 * <script type="text/javascript">
54577 * @class Roo.grid.EditorGrid
54578 * @extends Roo.grid.Grid
54579 * Class for creating and editable grid.
54580 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54581 * The container MUST have some type of size defined for the grid to fill. The container will be
54582 * automatically set to position relative if it isn't already.
54583 * @param {Object} dataSource The data model to bind to
54584 * @param {Object} colModel The column model with info about this grid's columns
54586 Roo.grid.EditorGrid = function(container, config){
54587 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
54588 this.getGridEl().addClass("xedit-grid");
54590 if(!this.selModel){
54591 this.selModel = new Roo.grid.CellSelectionModel();
54594 this.activeEditor = null;
54598 * @event beforeedit
54599 * Fires before cell editing is triggered. The edit event object has the following properties <br />
54600 * <ul style="padding:5px;padding-left:16px;">
54601 * <li>grid - This grid</li>
54602 * <li>record - The record being edited</li>
54603 * <li>field - The field name being edited</li>
54604 * <li>value - The value for the field being edited.</li>
54605 * <li>row - The grid row index</li>
54606 * <li>column - The grid column index</li>
54607 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
54609 * @param {Object} e An edit event (see above for description)
54611 "beforeedit" : true,
54614 * Fires after a cell is edited. <br />
54615 * <ul style="padding:5px;padding-left:16px;">
54616 * <li>grid - This grid</li>
54617 * <li>record - The record being edited</li>
54618 * <li>field - The field name being edited</li>
54619 * <li>value - The value being set</li>
54620 * <li>originalValue - The original value for the field, before the edit.</li>
54621 * <li>row - The grid row index</li>
54622 * <li>column - The grid column index</li>
54624 * @param {Object} e An edit event (see above for description)
54626 "afteredit" : true,
54628 * @event validateedit
54629 * Fires after a cell is edited, but before the value is set in the record.
54630 * You can use this to modify the value being set in the field, Return false
54631 * to cancel the change. The edit event object has the following properties <br />
54632 * <ul style="padding:5px;padding-left:16px;">
54633 * <li>editor - This editor</li>
54634 * <li>grid - This grid</li>
54635 * <li>record - The record being edited</li>
54636 * <li>field - The field name being edited</li>
54637 * <li>value - The value being set</li>
54638 * <li>originalValue - The original value for the field, before the edit.</li>
54639 * <li>row - The grid row index</li>
54640 * <li>column - The grid column index</li>
54641 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
54643 * @param {Object} e An edit event (see above for description)
54645 "validateedit" : true
54647 this.on("bodyscroll", this.stopEditing, this);
54648 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
54651 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
54653 * @cfg {Number} clicksToEdit
54654 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
54661 trackMouseOver: false, // causes very odd FF errors
54663 onCellDblClick : function(g, row, col){
54664 this.startEditing(row, col);
54667 onEditComplete : function(ed, value, startValue){
54668 this.editing = false;
54669 this.activeEditor = null;
54670 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
54672 var field = this.colModel.getDataIndex(ed.col);
54677 originalValue: startValue,
54684 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
54687 if(String(value) !== String(startValue)){
54689 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
54690 r.set(field, e.value);
54691 // if we are dealing with a combo box..
54692 // then we also set the 'name' colum to be the displayField
54693 if (ed.field.displayField && ed.field.name) {
54694 r.set(ed.field.name, ed.field.el.dom.value);
54697 delete e.cancel; //?? why!!!
54698 this.fireEvent("afteredit", e);
54701 this.fireEvent("afteredit", e); // always fire it!
54703 this.view.focusCell(ed.row, ed.col);
54707 * Starts editing the specified for the specified row/column
54708 * @param {Number} rowIndex
54709 * @param {Number} colIndex
54711 startEditing : function(row, col){
54712 this.stopEditing();
54713 if(this.colModel.isCellEditable(col, row)){
54714 this.view.ensureVisible(row, col, true);
54716 var r = this.dataSource.getAt(row);
54717 var field = this.colModel.getDataIndex(col);
54718 var cell = Roo.get(this.view.getCell(row,col));
54723 value: r.data[field],
54728 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
54729 this.editing = true;
54730 var ed = this.colModel.getCellEditor(col, row);
54736 ed.render(ed.parentEl || document.body);
54742 (function(){ // complex but required for focus issues in safari, ie and opera
54746 ed.on("complete", this.onEditComplete, this, {single: true});
54747 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
54748 this.activeEditor = ed;
54749 var v = r.data[field];
54750 ed.startEdit(this.view.getCell(row, col), v);
54751 // combo's with 'displayField and name set
54752 if (ed.field.displayField && ed.field.name) {
54753 ed.field.el.dom.value = r.data[ed.field.name];
54757 }).defer(50, this);
54763 * Stops any active editing
54765 stopEditing : function(){
54766 if(this.activeEditor){
54767 this.activeEditor.completeEdit();
54769 this.activeEditor = null;
54773 * Called to get grid's drag proxy text, by default returns this.ddText.
54776 getDragDropText : function(){
54777 var count = this.selModel.getSelectedCell() ? 1 : 0;
54778 return String.format(this.ddText, count, count == 1 ? '' : 's');
54783 * Ext JS Library 1.1.1
54784 * Copyright(c) 2006-2007, Ext JS, LLC.
54786 * Originally Released Under LGPL - original licence link has changed is not relivant.
54789 * <script type="text/javascript">
54792 // private - not really -- you end up using it !
54793 // This is a support class used internally by the Grid components
54796 * @class Roo.grid.GridEditor
54797 * @extends Roo.Editor
54798 * Class for creating and editable grid elements.
54799 * @param {Object} config any settings (must include field)
54801 Roo.grid.GridEditor = function(field, config){
54802 if (!config && field.field) {
54804 field = Roo.factory(config.field, Roo.form);
54806 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
54807 field.monitorTab = false;
54810 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
54813 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
54816 alignment: "tl-tl",
54819 cls: "x-small-editor x-grid-editor",
54824 * Ext JS Library 1.1.1
54825 * Copyright(c) 2006-2007, Ext JS, LLC.
54827 * Originally Released Under LGPL - original licence link has changed is not relivant.
54830 * <script type="text/javascript">
54835 Roo.grid.PropertyRecord = Roo.data.Record.create([
54836 {name:'name',type:'string'}, 'value'
54840 Roo.grid.PropertyStore = function(grid, source){
54842 this.store = new Roo.data.Store({
54843 recordType : Roo.grid.PropertyRecord
54845 this.store.on('update', this.onUpdate, this);
54847 this.setSource(source);
54849 Roo.grid.PropertyStore.superclass.constructor.call(this);
54854 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
54855 setSource : function(o){
54857 this.store.removeAll();
54860 if(this.isEditableValue(o[k])){
54861 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
54864 this.store.loadRecords({records: data}, {}, true);
54867 onUpdate : function(ds, record, type){
54868 if(type == Roo.data.Record.EDIT){
54869 var v = record.data['value'];
54870 var oldValue = record.modified['value'];
54871 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
54872 this.source[record.id] = v;
54874 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
54881 getProperty : function(row){
54882 return this.store.getAt(row);
54885 isEditableValue: function(val){
54886 if(val && val instanceof Date){
54888 }else if(typeof val == 'object' || typeof val == 'function'){
54894 setValue : function(prop, value){
54895 this.source[prop] = value;
54896 this.store.getById(prop).set('value', value);
54899 getSource : function(){
54900 return this.source;
54904 Roo.grid.PropertyColumnModel = function(grid, store){
54907 g.PropertyColumnModel.superclass.constructor.call(this, [
54908 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
54909 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
54911 this.store = store;
54912 this.bselect = Roo.DomHelper.append(document.body, {
54913 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
54914 {tag: 'option', value: 'true', html: 'true'},
54915 {tag: 'option', value: 'false', html: 'false'}
54918 Roo.id(this.bselect);
54921 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
54922 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
54923 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
54924 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
54925 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
54927 this.renderCellDelegate = this.renderCell.createDelegate(this);
54928 this.renderPropDelegate = this.renderProp.createDelegate(this);
54931 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
54935 valueText : 'Value',
54937 dateFormat : 'm/j/Y',
54940 renderDate : function(dateVal){
54941 return dateVal.dateFormat(this.dateFormat);
54944 renderBool : function(bVal){
54945 return bVal ? 'true' : 'false';
54948 isCellEditable : function(colIndex, rowIndex){
54949 return colIndex == 1;
54952 getRenderer : function(col){
54954 this.renderCellDelegate : this.renderPropDelegate;
54957 renderProp : function(v){
54958 return this.getPropertyName(v);
54961 renderCell : function(val){
54963 if(val instanceof Date){
54964 rv = this.renderDate(val);
54965 }else if(typeof val == 'boolean'){
54966 rv = this.renderBool(val);
54968 return Roo.util.Format.htmlEncode(rv);
54971 getPropertyName : function(name){
54972 var pn = this.grid.propertyNames;
54973 return pn && pn[name] ? pn[name] : name;
54976 getCellEditor : function(colIndex, rowIndex){
54977 var p = this.store.getProperty(rowIndex);
54978 var n = p.data['name'], val = p.data['value'];
54980 if(typeof(this.grid.customEditors[n]) == 'string'){
54981 return this.editors[this.grid.customEditors[n]];
54983 if(typeof(this.grid.customEditors[n]) != 'undefined'){
54984 return this.grid.customEditors[n];
54986 if(val instanceof Date){
54987 return this.editors['date'];
54988 }else if(typeof val == 'number'){
54989 return this.editors['number'];
54990 }else if(typeof val == 'boolean'){
54991 return this.editors['boolean'];
54993 return this.editors['string'];
54999 * @class Roo.grid.PropertyGrid
55000 * @extends Roo.grid.EditorGrid
55001 * This class represents the interface of a component based property grid control.
55002 * <br><br>Usage:<pre><code>
55003 var grid = new Roo.grid.PropertyGrid("my-container-id", {
55011 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55012 * The container MUST have some type of size defined for the grid to fill. The container will be
55013 * automatically set to position relative if it isn't already.
55014 * @param {Object} config A config object that sets properties on this grid.
55016 Roo.grid.PropertyGrid = function(container, config){
55017 config = config || {};
55018 var store = new Roo.grid.PropertyStore(this);
55019 this.store = store;
55020 var cm = new Roo.grid.PropertyColumnModel(this, store);
55021 store.store.sort('name', 'ASC');
55022 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
55025 enableColLock:false,
55026 enableColumnMove:false,
55028 trackMouseOver: false,
55031 this.getGridEl().addClass('x-props-grid');
55032 this.lastEditRow = null;
55033 this.on('columnresize', this.onColumnResize, this);
55036 * @event beforepropertychange
55037 * Fires before a property changes (return false to stop?)
55038 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55039 * @param {String} id Record Id
55040 * @param {String} newval New Value
55041 * @param {String} oldval Old Value
55043 "beforepropertychange": true,
55045 * @event propertychange
55046 * Fires after a property changes
55047 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55048 * @param {String} id Record Id
55049 * @param {String} newval New Value
55050 * @param {String} oldval Old Value
55052 "propertychange": true
55054 this.customEditors = this.customEditors || {};
55056 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
55059 * @cfg {Object} customEditors map of colnames=> custom editors.
55060 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
55061 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
55062 * false disables editing of the field.
55066 * @cfg {Object} propertyNames map of property Names to their displayed value
55069 render : function(){
55070 Roo.grid.PropertyGrid.superclass.render.call(this);
55071 this.autoSize.defer(100, this);
55074 autoSize : function(){
55075 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
55077 this.view.fitColumns();
55081 onColumnResize : function(){
55082 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
55086 * Sets the data for the Grid
55087 * accepts a Key => Value object of all the elements avaiable.
55088 * @param {Object} data to appear in grid.
55090 setSource : function(source){
55091 this.store.setSource(source);
55095 * Gets all the data from the grid.
55096 * @return {Object} data data stored in grid
55098 getSource : function(){
55099 return this.store.getSource();
55103 * Ext JS Library 1.1.1
55104 * Copyright(c) 2006-2007, Ext JS, LLC.
55106 * Originally Released Under LGPL - original licence link has changed is not relivant.
55109 * <script type="text/javascript">
55113 * @class Roo.LoadMask
55114 * A simple utility class for generically masking elements while loading data. If the element being masked has
55115 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
55116 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
55117 * element's UpdateManager load indicator and will be destroyed after the initial load.
55119 * Create a new LoadMask
55120 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
55121 * @param {Object} config The config object
55123 Roo.LoadMask = function(el, config){
55124 this.el = Roo.get(el);
55125 Roo.apply(this, config);
55127 this.store.on('beforeload', this.onBeforeLoad, this);
55128 this.store.on('load', this.onLoad, this);
55129 this.store.on('loadexception', this.onLoadException, this);
55130 this.removeMask = false;
55132 var um = this.el.getUpdateManager();
55133 um.showLoadIndicator = false; // disable the default indicator
55134 um.on('beforeupdate', this.onBeforeLoad, this);
55135 um.on('update', this.onLoad, this);
55136 um.on('failure', this.onLoad, this);
55137 this.removeMask = true;
55141 Roo.LoadMask.prototype = {
55143 * @cfg {Boolean} removeMask
55144 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
55145 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
55148 * @cfg {String} msg
55149 * The text to display in a centered loading message box (defaults to 'Loading...')
55151 msg : 'Loading...',
55153 * @cfg {String} msgCls
55154 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
55156 msgCls : 'x-mask-loading',
55159 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
55165 * Disables the mask to prevent it from being displayed
55167 disable : function(){
55168 this.disabled = true;
55172 * Enables the mask so that it can be displayed
55174 enable : function(){
55175 this.disabled = false;
55178 onLoadException : function()
55180 Roo.log(arguments);
55182 if (typeof(arguments[3]) != 'undefined') {
55183 Roo.MessageBox.alert("Error loading",arguments[3]);
55187 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
55188 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
55197 this.el.unmask(this.removeMask);
55200 onLoad : function()
55202 this.el.unmask(this.removeMask);
55206 onBeforeLoad : function(){
55207 if(!this.disabled){
55208 this.el.mask(this.msg, this.msgCls);
55213 destroy : function(){
55215 this.store.un('beforeload', this.onBeforeLoad, this);
55216 this.store.un('load', this.onLoad, this);
55217 this.store.un('loadexception', this.onLoadException, this);
55219 var um = this.el.getUpdateManager();
55220 um.un('beforeupdate', this.onBeforeLoad, this);
55221 um.un('update', this.onLoad, this);
55222 um.un('failure', this.onLoad, this);
55227 * Ext JS Library 1.1.1
55228 * Copyright(c) 2006-2007, Ext JS, LLC.
55230 * Originally Released Under LGPL - original licence link has changed is not relivant.
55233 * <script type="text/javascript">
55238 * @class Roo.XTemplate
55239 * @extends Roo.Template
55240 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
55242 var t = new Roo.XTemplate(
55243 '<select name="{name}">',
55244 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
55248 // then append, applying the master template values
55251 * Supported features:
55256 {a_variable} - output encoded.
55257 {a_variable.format:("Y-m-d")} - call a method on the variable
55258 {a_variable:raw} - unencoded output
55259 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
55260 {a_variable:this.method_on_template(...)} - call a method on the template object.
55265 <tpl for="a_variable or condition.."></tpl>
55266 <tpl if="a_variable or condition"></tpl>
55267 <tpl exec="some javascript"></tpl>
55268 <tpl name="named_template"></tpl> (experimental)
55270 <tpl for="."></tpl> - just iterate the property..
55271 <tpl for=".."></tpl> - iterates with the parent (probably the template)
55275 Roo.XTemplate = function()
55277 Roo.XTemplate.superclass.constructor.apply(this, arguments);
55284 Roo.extend(Roo.XTemplate, Roo.Template, {
55287 * The various sub templates
55292 * basic tag replacing syntax
55295 * // you can fake an object call by doing this
55299 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
55302 * compile the template
55304 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
55307 compile: function()
55311 s = ['<tpl>', s, '</tpl>'].join('');
55313 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
55314 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
55315 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
55316 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
55317 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
55322 while(true == !!(m = s.match(re))){
55323 var forMatch = m[0].match(nameRe),
55324 ifMatch = m[0].match(ifRe),
55325 execMatch = m[0].match(execRe),
55326 namedMatch = m[0].match(namedRe),
55331 name = forMatch && forMatch[1] ? forMatch[1] : '';
55334 // if - puts fn into test..
55335 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
55337 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
55342 // exec - calls a function... returns empty if true is returned.
55343 exp = execMatch && execMatch[1] ? execMatch[1] : null;
55345 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
55353 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
55354 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
55355 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
55358 var uid = namedMatch ? namedMatch[1] : id;
55362 id: namedMatch ? namedMatch[1] : id,
55369 s = s.replace(m[0], '');
55371 s = s.replace(m[0], '{xtpl'+ id + '}');
55376 for(var i = tpls.length-1; i >= 0; --i){
55377 this.compileTpl(tpls[i]);
55378 this.tpls[tpls[i].id] = tpls[i];
55380 this.master = tpls[tpls.length-1];
55384 * same as applyTemplate, except it's done to one of the subTemplates
55385 * when using named templates, you can do:
55387 * var str = pl.applySubTemplate('your-name', values);
55390 * @param {Number} id of the template
55391 * @param {Object} values to apply to template
55392 * @param {Object} parent (normaly the instance of this object)
55394 applySubTemplate : function(id, values, parent)
55398 var t = this.tpls[id];
55402 if(t.test && !t.test.call(this, values, parent)){
55406 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
55407 Roo.log(e.toString());
55413 if(t.exec && t.exec.call(this, values, parent)){
55417 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
55418 Roo.log(e.toString());
55423 var vs = t.target ? t.target.call(this, values, parent) : values;
55424 parent = t.target ? values : parent;
55425 if(t.target && vs instanceof Array){
55427 for(var i = 0, len = vs.length; i < len; i++){
55428 buf[buf.length] = t.compiled.call(this, vs[i], parent);
55430 return buf.join('');
55432 return t.compiled.call(this, vs, parent);
55434 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
55435 Roo.log(e.toString());
55436 Roo.log(t.compiled);
55441 compileTpl : function(tpl)
55443 var fm = Roo.util.Format;
55444 var useF = this.disableFormats !== true;
55445 var sep = Roo.isGecko ? "+" : ",";
55446 var undef = function(str) {
55447 Roo.log("Property not found :" + str);
55451 var fn = function(m, name, format, args)
55453 //Roo.log(arguments);
55454 args = args ? args.replace(/\\'/g,"'") : args;
55455 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
55456 if (typeof(format) == 'undefined') {
55457 format= 'htmlEncode';
55459 if (format == 'raw' ) {
55463 if(name.substr(0, 4) == 'xtpl'){
55464 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
55467 // build an array of options to determine if value is undefined..
55469 // basically get 'xxxx.yyyy' then do
55470 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
55471 // (function () { Roo.log("Property not found"); return ''; })() :
55476 Roo.each(name.split('.'), function(st) {
55477 lookfor += (lookfor.length ? '.': '') + st;
55478 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
55481 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
55484 if(format && useF){
55486 args = args ? ',' + args : "";
55488 if(format.substr(0, 5) != "this."){
55489 format = "fm." + format + '(';
55491 format = 'this.call("'+ format.substr(5) + '", ';
55495 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
55499 // called with xxyx.yuu:(test,test)
55501 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
55503 // raw.. - :raw modifier..
55504 return "'"+ sep + udef_st + name + ")"+sep+"'";
55508 // branched to use + in gecko and [].join() in others
55510 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
55511 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
55514 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
55515 body.push(tpl.body.replace(/(\r\n|\n)/g,
55516 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
55517 body.push("'].join('');};};");
55518 body = body.join('');
55521 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
55523 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
55529 applyTemplate : function(values){
55530 return this.master.compiled.call(this, values, {});
55531 //var s = this.subs;
55534 apply : function(){
55535 return this.applyTemplate.apply(this, arguments);
55540 Roo.XTemplate.from = function(el){
55541 el = Roo.getDom(el);
55542 return new Roo.XTemplate(el.value || el.innerHTML);
55544 * Original code for Roojs - LGPL
55545 * <script type="text/javascript">
55549 * @class Roo.XComponent
55550 * A delayed Element creator...
55551 * Or a way to group chunks of interface together.
55553 * Mypart.xyx = new Roo.XComponent({
55555 parent : 'Mypart.xyz', // empty == document.element.!!
55559 disabled : function() {}
55561 tree : function() { // return an tree of xtype declared components
55565 xtype : 'NestedLayoutPanel',
55572 * It can be used to build a big heiracy, with parent etc.
55573 * or you can just use this to render a single compoent to a dom element
55574 * MYPART.render(Roo.Element | String(id) | dom_element )
55576 * @extends Roo.util.Observable
55578 * @param cfg {Object} configuration of component
55581 Roo.XComponent = function(cfg) {
55582 Roo.apply(this, cfg);
55586 * Fires when this the componnt is built
55587 * @param {Roo.XComponent} c the component
55592 this.region = this.region || 'center'; // default..
55593 Roo.XComponent.register(this);
55594 this.modules = false;
55595 this.el = false; // where the layout goes..
55599 Roo.extend(Roo.XComponent, Roo.util.Observable, {
55602 * The created element (with Roo.factory())
55603 * @type {Roo.Layout}
55609 * for BC - use el in new code
55610 * @type {Roo.Layout}
55616 * for BC - use el in new code
55617 * @type {Roo.Layout}
55622 * @cfg {Function|boolean} disabled
55623 * If this module is disabled by some rule, return true from the funtion
55628 * @cfg {String} parent
55629 * Name of parent element which it get xtype added to..
55634 * @cfg {String} order
55635 * Used to set the order in which elements are created (usefull for multiple tabs)
55640 * @cfg {String} name
55641 * String to display while loading.
55645 * @cfg {String} region
55646 * Region to render component to (defaults to center)
55651 * @cfg {Array} items
55652 * A single item array - the first element is the root of the tree..
55653 * It's done this way to stay compatible with the Xtype system...
55659 * The method that retuns the tree of parts that make up this compoennt
55666 * render element to dom or tree
55667 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
55670 render : function(el)
55674 var hp = this.parent ? 1 : 0;
55676 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
55677 // if parent is a '#.....' string, then let's use that..
55678 var ename = this.parent.substr(1)
55679 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
55680 el = Roo.get(ename);
55681 if (!el && !this.parent) {
55682 Roo.log("Warning - element can not be found :#" + ename );
55688 if (!this.parent) {
55690 el = el ? Roo.get(el) : false;
55692 // it's a top level one..
55694 el : new Roo.BorderLayout(el || document.body, {
55700 tabPosition: 'top',
55701 //resizeTabs: true,
55702 alwaysShowTabs: el && hp? false : true,
55703 hideTabs: el || !hp ? true : false,
55710 if (!this.parent.el) {
55711 // probably an old style ctor, which has been disabled.
55715 // The 'tree' method is '_tree now'
55717 var tree = this._tree ? this._tree() : this.tree();
55718 tree.region = tree.region || this.region;
55719 this.el = this.parent.el.addxtype(tree);
55720 this.fireEvent('built', this);
55722 this.panel = this.el;
55723 this.layout = this.panel.layout;
55724 this.parentLayout = this.parent.layout || false;
55730 Roo.apply(Roo.XComponent, {
55732 * @property hideProgress
55733 * true to disable the building progress bar.. usefull on single page renders.
55736 hideProgress : false,
55738 * @property buildCompleted
55739 * True when the builder has completed building the interface.
55742 buildCompleted : false,
55745 * @property topModule
55746 * the upper most module - uses document.element as it's constructor.
55753 * @property modules
55754 * array of modules to be created by registration system.
55755 * @type {Array} of Roo.XComponent
55760 * @property elmodules
55761 * array of modules to be created by which use #ID
55762 * @type {Array} of Roo.XComponent
55769 * Register components to be built later.
55771 * This solves the following issues
55772 * - Building is not done on page load, but after an authentication process has occured.
55773 * - Interface elements are registered on page load
55774 * - Parent Interface elements may not be loaded before child, so this handles that..
55781 module : 'Pman.Tab.projectMgr',
55783 parent : 'Pman.layout',
55784 disabled : false, // or use a function..
55787 * * @param {Object} details about module
55789 register : function(obj) {
55791 Roo.XComponent.event.fireEvent('register', obj);
55792 switch(typeof(obj.disabled) ) {
55798 if ( obj.disabled() ) {
55804 if (obj.disabled) {
55810 this.modules.push(obj);
55814 * convert a string to an object..
55815 * eg. 'AAA.BBB' -> finds AAA.BBB
55819 toObject : function(str)
55821 if (!str || typeof(str) == 'object') {
55824 if (str.substring(0,1) == '#') {
55828 var ar = str.split('.');
55833 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
55835 throw "Module not found : " + str;
55839 throw "Module not found : " + str;
55841 Roo.each(ar, function(e) {
55842 if (typeof(o[e]) == 'undefined') {
55843 throw "Module not found : " + str;
55854 * move modules into their correct place in the tree..
55857 preBuild : function ()
55860 Roo.each(this.modules , function (obj)
55862 Roo.XComponent.event.fireEvent('beforebuild', obj);
55864 var opar = obj.parent;
55866 obj.parent = this.toObject(opar);
55868 Roo.log("parent:toObject failed: " + e.toString());
55873 Roo.debug && Roo.log("GOT top level module");
55874 Roo.debug && Roo.log(obj);
55875 obj.modules = new Roo.util.MixedCollection(false,
55876 function(o) { return o.order + '' }
55878 this.topModule = obj;
55881 // parent is a string (usually a dom element name..)
55882 if (typeof(obj.parent) == 'string') {
55883 this.elmodules.push(obj);
55886 if (obj.parent.constructor != Roo.XComponent) {
55887 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
55889 if (!obj.parent.modules) {
55890 obj.parent.modules = new Roo.util.MixedCollection(false,
55891 function(o) { return o.order + '' }
55894 if (obj.parent.disabled) {
55895 obj.disabled = true;
55897 obj.parent.modules.add(obj);
55902 * make a list of modules to build.
55903 * @return {Array} list of modules.
55906 buildOrder : function()
55909 var cmp = function(a,b) {
55910 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
55912 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
55913 throw "No top level modules to build";
55916 // make a flat list in order of modules to build.
55917 var mods = this.topModule ? [ this.topModule ] : [];
55920 // elmodules (is a list of DOM based modules )
55921 Roo.each(this.elmodules, function(e) {
55923 if (!this.topModule &&
55924 typeof(e.parent) == 'string' &&
55925 e.parent.substring(0,1) == '#' &&
55926 Roo.get(e.parent.substr(1))
55929 _this.topModule = e;
55935 // add modules to their parents..
55936 var addMod = function(m) {
55937 Roo.debug && Roo.log("build Order: add: " + m.name);
55940 if (m.modules && !m.disabled) {
55941 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
55942 m.modules.keySort('ASC', cmp );
55943 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
55945 m.modules.each(addMod);
55947 Roo.debug && Roo.log("build Order: no child modules");
55949 // not sure if this is used any more..
55951 m.finalize.name = m.name + " (clean up) ";
55952 mods.push(m.finalize);
55956 if (this.topModule && this.topModule.modules) {
55957 this.topModule.modules.keySort('ASC', cmp );
55958 this.topModule.modules.each(addMod);
55964 * Build the registered modules.
55965 * @param {Object} parent element.
55966 * @param {Function} optional method to call after module has been added.
55974 var mods = this.buildOrder();
55976 //this.allmods = mods;
55977 //Roo.debug && Roo.log(mods);
55979 if (!mods.length) { // should not happen
55980 throw "NO modules!!!";
55984 var msg = "Building Interface...";
55985 // flash it up as modal - so we store the mask!?
55986 if (!this.hideProgress) {
55987 Roo.MessageBox.show({ title: 'loading' });
55988 Roo.MessageBox.show({
55989 title: "Please wait...",
55998 var total = mods.length;
56001 var progressRun = function() {
56002 if (!mods.length) {
56003 Roo.debug && Roo.log('hide?');
56004 if (!this.hideProgress) {
56005 Roo.MessageBox.hide();
56007 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
56013 var m = mods.shift();
56016 Roo.debug && Roo.log(m);
56017 // not sure if this is supported any more.. - modules that are are just function
56018 if (typeof(m) == 'function') {
56020 return progressRun.defer(10, _this);
56024 msg = "Building Interface " + (total - mods.length) +
56026 (m.name ? (' - ' + m.name) : '');
56027 Roo.debug && Roo.log(msg);
56028 if (!this.hideProgress) {
56029 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
56033 // is the module disabled?
56034 var disabled = (typeof(m.disabled) == 'function') ?
56035 m.disabled.call(m.module.disabled) : m.disabled;
56039 return progressRun(); // we do not update the display!
56047 // it's 10 on top level, and 1 on others??? why...
56048 return progressRun.defer(10, _this);
56051 progressRun.defer(1, _this);
56065 * wrapper for event.on - aliased later..
56066 * Typically use to register a event handler for register:
56068 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
56077 Roo.XComponent.event = new Roo.util.Observable({
56081 * Fires when an Component is registered,
56082 * set the disable property on the Component to stop registration.
56083 * @param {Roo.XComponent} c the component being registerd.
56088 * @event beforebuild
56089 * Fires before each Component is built
56090 * can be used to apply permissions.
56091 * @param {Roo.XComponent} c the component being registerd.
56094 'beforebuild' : true,
56096 * @event buildcomplete
56097 * Fires on the top level element when all elements have been built
56098 * @param {Roo.XComponent} the top level component.
56100 'buildcomplete' : true
56105 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);