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 (e.browserEvent.touches && e.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"],
41695 * @cfg {String} defaultFont default font to use.
41697 defaultFont: 'tahoma',
41699 fontSelect : false,
41702 formatCombo : false,
41704 init : function(editor)
41706 this.editor = editor;
41709 var fid = editor.frameId;
41711 function btn(id, toggle, handler){
41712 var xid = fid + '-'+ id ;
41716 cls : 'x-btn-icon x-edit-'+id,
41717 enableToggle:toggle !== false,
41718 scope: editor, // was editor...
41719 handler:handler||editor.relayBtnCmd,
41720 clickEvent:'mousedown',
41721 tooltip: etb.buttonTips[id] || undefined, ///tips ???
41728 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
41730 // stop form submits
41731 tb.el.on('click', function(e){
41732 e.preventDefault(); // what does this do?
41735 if(!this.disable.font) { // && !Roo.isSafari){
41736 /* why no safari for fonts
41737 editor.fontSelect = tb.el.createChild({
41740 cls:'x-font-select',
41741 html: this.createFontOptions()
41744 editor.fontSelect.on('change', function(){
41745 var font = editor.fontSelect.dom.value;
41746 editor.relayCmd('fontname', font);
41747 editor.deferFocus();
41751 editor.fontSelect.dom,
41757 if(!this.disable.formats){
41758 this.formatCombo = new Roo.form.ComboBox({
41759 store: new Roo.data.SimpleStore({
41762 data : this.formats // from states.js
41766 //autoCreate : {tag: "div", size: "20"},
41767 displayField:'tag',
41771 triggerAction: 'all',
41772 emptyText:'Add tag',
41773 selectOnFocus:true,
41776 'select': function(c, r, i) {
41777 editor.insertTag(r.get('tag'));
41783 tb.addField(this.formatCombo);
41787 if(!this.disable.format){
41794 if(!this.disable.fontSize){
41799 btn('increasefontsize', false, editor.adjustFont),
41800 btn('decreasefontsize', false, editor.adjustFont)
41805 if(!this.disable.colors){
41808 id:editor.frameId +'-forecolor',
41809 cls:'x-btn-icon x-edit-forecolor',
41810 clickEvent:'mousedown',
41811 tooltip: this.buttonTips['forecolor'] || undefined,
41813 menu : new Roo.menu.ColorMenu({
41814 allowReselect: true,
41815 focus: Roo.emptyFn,
41818 selectHandler: function(cp, color){
41819 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
41820 editor.deferFocus();
41823 clickEvent:'mousedown'
41826 id:editor.frameId +'backcolor',
41827 cls:'x-btn-icon x-edit-backcolor',
41828 clickEvent:'mousedown',
41829 tooltip: this.buttonTips['backcolor'] || undefined,
41831 menu : new Roo.menu.ColorMenu({
41832 focus: Roo.emptyFn,
41835 allowReselect: true,
41836 selectHandler: function(cp, color){
41838 editor.execCmd('useCSS', false);
41839 editor.execCmd('hilitecolor', color);
41840 editor.execCmd('useCSS', true);
41841 editor.deferFocus();
41843 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
41844 Roo.isSafari || Roo.isIE ? '#'+color : color);
41845 editor.deferFocus();
41849 clickEvent:'mousedown'
41854 // now add all the items...
41857 if(!this.disable.alignments){
41860 btn('justifyleft'),
41861 btn('justifycenter'),
41862 btn('justifyright')
41866 //if(!Roo.isSafari){
41867 if(!this.disable.links){
41870 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
41874 if(!this.disable.lists){
41877 btn('insertorderedlist'),
41878 btn('insertunorderedlist')
41881 if(!this.disable.sourceEdit){
41884 btn('sourceedit', true, function(btn){
41885 this.toggleSourceEdit(btn.pressed);
41892 // special menu.. - needs to be tidied up..
41893 if (!this.disable.special) {
41896 cls: 'x-edit-none',
41902 for (var i =0; i < this.specialChars.length; i++) {
41903 smenu.menu.items.push({
41905 html: this.specialChars[i],
41906 handler: function(a,b) {
41907 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
41908 //editor.insertAtCursor(a.html);
41921 if (!this.disable.specialElements) {
41924 cls: 'x-edit-none',
41929 for (var i =0; i < this.specialElements.length; i++) {
41930 semenu.menu.items.push(
41932 handler: function(a,b) {
41933 editor.insertAtCursor(this.ihtml);
41935 }, this.specialElements[i])
41947 for(var i =0; i< this.btns.length;i++) {
41948 var b = Roo.factory(this.btns[i],Roo.form);
41949 b.cls = 'x-edit-none';
41958 // disable everything...
41960 this.tb.items.each(function(item){
41961 if(item.id != editor.frameId+ '-sourceedit'){
41965 this.rendered = true;
41967 // the all the btns;
41968 editor.on('editorevent', this.updateToolbar, this);
41969 // other toolbars need to implement this..
41970 //editor.on('editmodechange', this.updateToolbar, this);
41976 * Protected method that will not generally be called directly. It triggers
41977 * a toolbar update by reading the markup state of the current selection in the editor.
41979 updateToolbar: function(){
41981 if(!this.editor.activated){
41982 this.editor.onFirstFocus();
41986 var btns = this.tb.items.map,
41987 doc = this.editor.doc,
41988 frameId = this.editor.frameId;
41990 if(!this.disable.font && !Roo.isSafari){
41992 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
41993 if(name != this.fontSelect.dom.value){
41994 this.fontSelect.dom.value = name;
41998 if(!this.disable.format){
41999 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
42000 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
42001 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
42003 if(!this.disable.alignments){
42004 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
42005 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
42006 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
42008 if(!Roo.isSafari && !this.disable.lists){
42009 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
42010 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
42013 var ans = this.editor.getAllAncestors();
42014 if (this.formatCombo) {
42017 var store = this.formatCombo.store;
42018 this.formatCombo.setValue("");
42019 for (var i =0; i < ans.length;i++) {
42020 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
42022 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
42030 // hides menus... - so this cant be on a menu...
42031 Roo.menu.MenuMgr.hideAll();
42033 //this.editorsyncValue();
42037 createFontOptions : function(){
42038 var buf = [], fs = this.fontFamilies, ff, lc;
42042 for(var i = 0, len = fs.length; i< len; i++){
42044 lc = ff.toLowerCase();
42046 '<option value="',lc,'" style="font-family:',ff,';"',
42047 (this.defaultFont == lc ? ' selected="true">' : '>'),
42052 return buf.join('');
42055 toggleSourceEdit : function(sourceEditMode){
42056 if(sourceEditMode === undefined){
42057 sourceEditMode = !this.sourceEditMode;
42059 this.sourceEditMode = sourceEditMode === true;
42060 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
42061 // just toggle the button?
42062 if(btn.pressed !== this.editor.sourceEditMode){
42063 btn.toggle(this.editor.sourceEditMode);
42067 if(this.sourceEditMode){
42068 this.tb.items.each(function(item){
42069 if(item.cmd != 'sourceedit'){
42075 if(this.initialized){
42076 this.tb.items.each(function(item){
42082 // tell the editor that it's been pressed..
42083 this.editor.toggleSourceEdit(sourceEditMode);
42087 * Object collection of toolbar tooltips for the buttons in the editor. The key
42088 * is the command id associated with that button and the value is a valid QuickTips object.
42093 title: 'Bold (Ctrl+B)',
42094 text: 'Make the selected text bold.',
42095 cls: 'x-html-editor-tip'
42098 title: 'Italic (Ctrl+I)',
42099 text: 'Make the selected text italic.',
42100 cls: 'x-html-editor-tip'
42108 title: 'Bold (Ctrl+B)',
42109 text: 'Make the selected text bold.',
42110 cls: 'x-html-editor-tip'
42113 title: 'Italic (Ctrl+I)',
42114 text: 'Make the selected text italic.',
42115 cls: 'x-html-editor-tip'
42118 title: 'Underline (Ctrl+U)',
42119 text: 'Underline the selected text.',
42120 cls: 'x-html-editor-tip'
42122 increasefontsize : {
42123 title: 'Grow Text',
42124 text: 'Increase the font size.',
42125 cls: 'x-html-editor-tip'
42127 decreasefontsize : {
42128 title: 'Shrink Text',
42129 text: 'Decrease the font size.',
42130 cls: 'x-html-editor-tip'
42133 title: 'Text Highlight Color',
42134 text: 'Change the background color of the selected text.',
42135 cls: 'x-html-editor-tip'
42138 title: 'Font Color',
42139 text: 'Change the color of the selected text.',
42140 cls: 'x-html-editor-tip'
42143 title: 'Align Text Left',
42144 text: 'Align text to the left.',
42145 cls: 'x-html-editor-tip'
42148 title: 'Center Text',
42149 text: 'Center text in the editor.',
42150 cls: 'x-html-editor-tip'
42153 title: 'Align Text Right',
42154 text: 'Align text to the right.',
42155 cls: 'x-html-editor-tip'
42157 insertunorderedlist : {
42158 title: 'Bullet List',
42159 text: 'Start a bulleted list.',
42160 cls: 'x-html-editor-tip'
42162 insertorderedlist : {
42163 title: 'Numbered List',
42164 text: 'Start a numbered list.',
42165 cls: 'x-html-editor-tip'
42168 title: 'Hyperlink',
42169 text: 'Make the selected text a hyperlink.',
42170 cls: 'x-html-editor-tip'
42173 title: 'Source Edit',
42174 text: 'Switch to source editing mode.',
42175 cls: 'x-html-editor-tip'
42179 onDestroy : function(){
42182 this.tb.items.each(function(item){
42184 item.menu.removeAll();
42186 item.menu.el.destroy();
42194 onFirstFocus: function() {
42195 this.tb.items.each(function(item){
42204 // <script type="text/javascript">
42207 * Ext JS Library 1.1.1
42208 * Copyright(c) 2006-2007, Ext JS, LLC.
42215 * @class Roo.form.HtmlEditor.ToolbarContext
42220 new Roo.form.HtmlEditor({
42223 { xtype: 'ToolbarStandard', styles : {} }
42224 { xtype: 'ToolbarContext', disable : {} }
42230 * @config : {Object} disable List of elements to disable.. (not done yet.)
42231 * @config : {Object} styles Map of styles available.
42235 Roo.form.HtmlEditor.ToolbarContext = function(config)
42238 Roo.apply(this, config);
42239 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42240 // dont call parent... till later.
42241 this.styles = this.styles || {};
42246 Roo.form.HtmlEditor.ToolbarContext.types = {
42258 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42320 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
42325 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
42335 style : 'fontFamily',
42336 displayField: 'display',
42337 optname : 'font-family',
42386 // should we really allow this??
42387 // should this just be
42398 style : 'fontFamily',
42399 displayField: 'display',
42400 optname : 'font-family',
42407 style : 'fontFamily',
42408 displayField: 'display',
42409 optname : 'font-family',
42416 style : 'fontFamily',
42417 displayField: 'display',
42418 optname : 'font-family',
42429 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
42430 Roo.form.HtmlEditor.ToolbarContext.stores = false;
42432 Roo.form.HtmlEditor.ToolbarContext.options = {
42434 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
42435 [ 'Courier New', 'Courier New'],
42436 [ 'Tahoma', 'Tahoma'],
42437 [ 'Times New Roman,serif', 'Times'],
42438 [ 'Verdana','Verdana' ]
42442 // fixme - these need to be configurable..
42445 Roo.form.HtmlEditor.ToolbarContext.types
42448 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
42456 * @cfg {Object} disable List of toolbar elements to disable
42461 * @cfg {Object} styles List of styles
42462 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
42464 * These must be defined in the page, so they get rendered correctly..
42475 init : function(editor)
42477 this.editor = editor;
42480 var fid = editor.frameId;
42482 function btn(id, toggle, handler){
42483 var xid = fid + '-'+ id ;
42487 cls : 'x-btn-icon x-edit-'+id,
42488 enableToggle:toggle !== false,
42489 scope: editor, // was editor...
42490 handler:handler||editor.relayBtnCmd,
42491 clickEvent:'mousedown',
42492 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42496 // create a new element.
42497 var wdiv = editor.wrap.createChild({
42499 }, editor.wrap.dom.firstChild.nextSibling, true);
42501 // can we do this more than once??
42503 // stop form submits
42506 // disable everything...
42507 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42508 this.toolbars = {};
42510 for (var i in ty) {
42512 this.toolbars[i] = this.buildToolbar(ty[i],i);
42514 this.tb = this.toolbars.BODY;
42516 this.buildFooter();
42517 this.footer.show();
42518 editor.on('hide', function( ) { this.footer.hide() }, this);
42519 editor.on('show', function( ) { this.footer.show() }, this);
42522 this.rendered = true;
42524 // the all the btns;
42525 editor.on('editorevent', this.updateToolbar, this);
42526 // other toolbars need to implement this..
42527 //editor.on('editmodechange', this.updateToolbar, this);
42533 * Protected method that will not generally be called directly. It triggers
42534 * a toolbar update by reading the markup state of the current selection in the editor.
42536 updateToolbar: function(editor,ev,sel){
42539 // capture mouse up - this is handy for selecting images..
42540 // perhaps should go somewhere else...
42541 if(!this.editor.activated){
42542 this.editor.onFirstFocus();
42546 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
42547 // selectNode - might want to handle IE?
42549 (ev.type == 'mouseup' || ev.type == 'click' ) &&
42550 ev.target && ev.target.tagName == 'IMG') {
42551 // they have click on an image...
42552 // let's see if we can change the selection...
42555 var nodeRange = sel.ownerDocument.createRange();
42557 nodeRange.selectNode(sel);
42559 nodeRange.selectNodeContents(sel);
42561 //nodeRange.collapse(true);
42562 var s = editor.win.getSelection();
42563 s.removeAllRanges();
42564 s.addRange(nodeRange);
42568 var updateFooter = sel ? false : true;
42571 var ans = this.editor.getAllAncestors();
42574 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42577 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
42578 sel = sel ? sel : this.editor.doc.body;
42579 sel = sel.tagName.length ? sel : this.editor.doc.body;
42582 // pick a menu that exists..
42583 var tn = sel.tagName.toUpperCase();
42584 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
42586 tn = sel.tagName.toUpperCase();
42588 var lastSel = this.tb.selectedNode
42590 this.tb.selectedNode = sel;
42592 // if current menu does not match..
42593 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
42596 ///console.log("show: " + tn);
42597 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
42600 this.tb.items.first().el.innerHTML = tn + ': ';
42603 // update attributes
42604 if (this.tb.fields) {
42605 this.tb.fields.each(function(e) {
42607 e.setValue(sel.style[e.stylename]);
42610 e.setValue(sel.getAttribute(e.attrname));
42614 var hasStyles = false;
42615 for(var i in this.styles) {
42622 var st = this.tb.fields.item(0);
42624 st.store.removeAll();
42627 var cn = sel.className.split(/\s+/);
42630 if (this.styles['*']) {
42632 Roo.each(this.styles['*'], function(v) {
42633 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42636 if (this.styles[tn]) {
42637 Roo.each(this.styles[tn], function(v) {
42638 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42642 st.store.loadData(avs);
42646 // flag our selected Node.
42647 this.tb.selectedNode = sel;
42650 Roo.menu.MenuMgr.hideAll();
42654 if (!updateFooter) {
42655 //this.footDisp.dom.innerHTML = '';
42658 // update the footer
42662 this.footerEls = ans.reverse();
42663 Roo.each(this.footerEls, function(a,i) {
42664 if (!a) { return; }
42665 html += html.length ? ' > ' : '';
42667 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
42672 var sz = this.footDisp.up('td').getSize();
42673 this.footDisp.dom.style.width = (sz.width -10) + 'px';
42674 this.footDisp.dom.style.marginLeft = '5px';
42676 this.footDisp.dom.style.overflow = 'hidden';
42678 this.footDisp.dom.innerHTML = html;
42680 //this.editorsyncValue();
42687 onDestroy : function(){
42690 this.tb.items.each(function(item){
42692 item.menu.removeAll();
42694 item.menu.el.destroy();
42702 onFirstFocus: function() {
42703 // need to do this for all the toolbars..
42704 this.tb.items.each(function(item){
42708 buildToolbar: function(tlist, nm)
42710 var editor = this.editor;
42711 // create a new element.
42712 var wdiv = editor.wrap.createChild({
42714 }, editor.wrap.dom.firstChild.nextSibling, true);
42717 var tb = new Roo.Toolbar(wdiv);
42720 tb.add(nm+ ": ");
42723 for(var i in this.styles) {
42728 if (styles && styles.length) {
42730 // this needs a multi-select checkbox...
42731 tb.addField( new Roo.form.ComboBox({
42732 store: new Roo.data.SimpleStore({
42734 fields: ['val', 'selected'],
42737 name : '-roo-edit-className',
42738 attrname : 'className',
42739 displayField: 'val',
42743 triggerAction: 'all',
42744 emptyText:'Select Style',
42745 selectOnFocus:true,
42748 'select': function(c, r, i) {
42749 // initial support only for on class per el..
42750 tb.selectedNode.className = r ? r.get('val') : '';
42751 editor.syncValue();
42758 var tbc = Roo.form.HtmlEditor.ToolbarContext;
42759 var tbops = tbc.options;
42761 for (var i in tlist) {
42763 var item = tlist[i];
42764 tb.add(item.title + ": ");
42767 //optname == used so you can configure the options available..
42768 var opts = item.opts ? item.opts : false;
42769 if (item.optname) {
42770 opts = tbops[item.optname];
42775 // opts == pulldown..
42776 tb.addField( new Roo.form.ComboBox({
42777 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
42779 fields: ['val', 'display'],
42782 name : '-roo-edit-' + i,
42784 stylename : item.style ? item.style : false,
42785 displayField: item.displayField ? item.displayField : 'val',
42786 valueField : 'val',
42788 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
42790 triggerAction: 'all',
42791 emptyText:'Select',
42792 selectOnFocus:true,
42793 width: item.width ? item.width : 130,
42795 'select': function(c, r, i) {
42797 tb.selectedNode.style[c.stylename] = r.get('val');
42800 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
42809 tb.addField( new Roo.form.TextField({
42812 //allowBlank:false,
42817 tb.addField( new Roo.form.TextField({
42818 name: '-roo-edit-' + i,
42825 'change' : function(f, nv, ov) {
42826 tb.selectedNode.setAttribute(f.attrname, nv);
42835 text: 'Remove Tag',
42838 click : function ()
42841 // undo does not work.
42843 var sn = tb.selectedNode;
42845 var pn = sn.parentNode;
42847 var stn = sn.childNodes[0];
42848 var en = sn.childNodes[sn.childNodes.length - 1 ];
42849 while (sn.childNodes.length) {
42850 var node = sn.childNodes[0];
42851 sn.removeChild(node);
42853 pn.insertBefore(node, sn);
42856 pn.removeChild(sn);
42857 var range = editor.createRange();
42859 range.setStart(stn,0);
42860 range.setEnd(en,0); //????
42861 //range.selectNode(sel);
42864 var selection = editor.getSelection();
42865 selection.removeAllRanges();
42866 selection.addRange(range);
42870 //_this.updateToolbar(null, null, pn);
42871 _this.updateToolbar(null, null, null);
42872 _this.footDisp.dom.innerHTML = '';
42882 tb.el.on('click', function(e){
42883 e.preventDefault(); // what does this do?
42885 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
42888 // dont need to disable them... as they will get hidden
42893 buildFooter : function()
42896 var fel = this.editor.wrap.createChild();
42897 this.footer = new Roo.Toolbar(fel);
42898 // toolbar has scrolly on left / right?
42899 var footDisp= new Roo.Toolbar.Fill();
42905 handler : function() {
42906 _t.footDisp.scrollTo('left',0,true)
42910 this.footer.add( footDisp );
42915 handler : function() {
42917 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
42921 var fel = Roo.get(footDisp.el);
42922 fel.addClass('x-editor-context');
42923 this.footDispWrap = fel;
42924 this.footDispWrap.overflow = 'hidden';
42926 this.footDisp = fel.createChild();
42927 this.footDispWrap.on('click', this.onContextClick, this)
42931 onContextClick : function (ev,dom)
42933 ev.preventDefault();
42934 var cn = dom.className;
42936 if (!cn.match(/x-ed-loc-/)) {
42939 var n = cn.split('-').pop();
42940 var ans = this.footerEls;
42944 var range = this.editor.createRange();
42946 range.selectNodeContents(sel);
42947 //range.selectNode(sel);
42950 var selection = this.editor.getSelection();
42951 selection.removeAllRanges();
42952 selection.addRange(range);
42956 this.updateToolbar(null, null, sel);
42973 * Ext JS Library 1.1.1
42974 * Copyright(c) 2006-2007, Ext JS, LLC.
42976 * Originally Released Under LGPL - original licence link has changed is not relivant.
42979 * <script type="text/javascript">
42983 * @class Roo.form.BasicForm
42984 * @extends Roo.util.Observable
42985 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
42987 * @param {String/HTMLElement/Roo.Element} el The form element or its id
42988 * @param {Object} config Configuration options
42990 Roo.form.BasicForm = function(el, config){
42991 this.allItems = [];
42992 this.childForms = [];
42993 Roo.apply(this, config);
42995 * The Roo.form.Field items in this form.
42996 * @type MixedCollection
43000 this.items = new Roo.util.MixedCollection(false, function(o){
43001 return o.id || (o.id = Roo.id());
43005 * @event beforeaction
43006 * Fires before any action is performed. Return false to cancel the action.
43007 * @param {Form} this
43008 * @param {Action} action The action to be performed
43010 beforeaction: true,
43012 * @event actionfailed
43013 * Fires when an action fails.
43014 * @param {Form} this
43015 * @param {Action} action The action that failed
43017 actionfailed : true,
43019 * @event actioncomplete
43020 * Fires when an action is completed.
43021 * @param {Form} this
43022 * @param {Action} action The action that completed
43024 actioncomplete : true
43029 Roo.form.BasicForm.superclass.constructor.call(this);
43032 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
43034 * @cfg {String} method
43035 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
43038 * @cfg {DataReader} reader
43039 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
43040 * This is optional as there is built-in support for processing JSON.
43043 * @cfg {DataReader} errorReader
43044 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
43045 * This is completely optional as there is built-in support for processing JSON.
43048 * @cfg {String} url
43049 * The URL to use for form actions if one isn't supplied in the action options.
43052 * @cfg {Boolean} fileUpload
43053 * Set to true if this form is a file upload.
43057 * @cfg {Object} baseParams
43058 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
43063 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
43068 activeAction : null,
43071 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
43072 * or setValues() data instead of when the form was first created.
43074 trackResetOnLoad : false,
43078 * childForms - used for multi-tab forms
43081 childForms : false,
43084 * allItems - full list of fields.
43090 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
43091 * element by passing it or its id or mask the form itself by passing in true.
43094 waitMsgTarget : false,
43097 initEl : function(el){
43098 this.el = Roo.get(el);
43099 this.id = this.el.id || Roo.id();
43100 this.el.on('submit', this.onSubmit, this);
43101 this.el.addClass('x-form');
43105 onSubmit : function(e){
43110 * Returns true if client-side validation on the form is successful.
43113 isValid : function(){
43115 this.items.each(function(f){
43124 * Returns true if any fields in this form have changed since their original load.
43127 isDirty : function(){
43129 this.items.each(function(f){
43139 * Performs a predefined action (submit or load) or custom actions you define on this form.
43140 * @param {String} actionName The name of the action type
43141 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
43142 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
43143 * accept other config options):
43145 Property Type Description
43146 ---------------- --------------- ----------------------------------------------------------------------------------
43147 url String The url for the action (defaults to the form's url)
43148 method String The form method to use (defaults to the form's method, or POST if not defined)
43149 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
43150 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
43151 validate the form on the client (defaults to false)
43153 * @return {BasicForm} this
43155 doAction : function(action, options){
43156 if(typeof action == 'string'){
43157 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
43159 if(this.fireEvent('beforeaction', this, action) !== false){
43160 this.beforeAction(action);
43161 action.run.defer(100, action);
43167 * Shortcut to do a submit action.
43168 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43169 * @return {BasicForm} this
43171 submit : function(options){
43172 this.doAction('submit', options);
43177 * Shortcut to do a load action.
43178 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43179 * @return {BasicForm} this
43181 load : function(options){
43182 this.doAction('load', options);
43187 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
43188 * @param {Record} record The record to edit
43189 * @return {BasicForm} this
43191 updateRecord : function(record){
43192 record.beginEdit();
43193 var fs = record.fields;
43194 fs.each(function(f){
43195 var field = this.findField(f.name);
43197 record.set(f.name, field.getValue());
43205 * Loads an Roo.data.Record into this form.
43206 * @param {Record} record The record to load
43207 * @return {BasicForm} this
43209 loadRecord : function(record){
43210 this.setValues(record.data);
43215 beforeAction : function(action){
43216 var o = action.options;
43219 if(this.waitMsgTarget === true){
43220 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
43221 }else if(this.waitMsgTarget){
43222 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
43223 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
43225 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
43231 afterAction : function(action, success){
43232 this.activeAction = null;
43233 var o = action.options;
43235 if(this.waitMsgTarget === true){
43237 }else if(this.waitMsgTarget){
43238 this.waitMsgTarget.unmask();
43240 Roo.MessageBox.updateProgress(1);
43241 Roo.MessageBox.hide();
43248 Roo.callback(o.success, o.scope, [this, action]);
43249 this.fireEvent('actioncomplete', this, action);
43253 // failure condition..
43254 // we have a scenario where updates need confirming.
43255 // eg. if a locking scenario exists..
43256 // we look for { errors : { needs_confirm : true }} in the response.
43258 (typeof(action.result) != 'undefined') &&
43259 (typeof(action.result.errors) != 'undefined') &&
43260 (typeof(action.result.errors.needs_confirm) != 'undefined')
43263 Roo.MessageBox.confirm(
43264 "Change requires confirmation",
43265 action.result.errorMsg,
43270 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
43280 Roo.callback(o.failure, o.scope, [this, action]);
43281 // show an error message if no failed handler is set..
43282 if (!this.hasListener('actionfailed')) {
43283 Roo.MessageBox.alert("Error",
43284 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
43285 action.result.errorMsg :
43286 "Saving Failed, please check your entries or try again"
43290 this.fireEvent('actionfailed', this, action);
43296 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
43297 * @param {String} id The value to search for
43300 findField : function(id){
43301 var field = this.items.get(id);
43303 this.items.each(function(f){
43304 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
43310 return field || null;
43314 * Add a secondary form to this one,
43315 * Used to provide tabbed forms. One form is primary, with hidden values
43316 * which mirror the elements from the other forms.
43318 * @param {Roo.form.Form} form to add.
43321 addForm : function(form)
43324 if (this.childForms.indexOf(form) > -1) {
43328 this.childForms.push(form);
43330 Roo.each(form.allItems, function (fe) {
43332 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
43333 if (this.findField(n)) { // already added..
43336 var add = new Roo.form.Hidden({
43339 add.render(this.el);
43346 * Mark fields in this form invalid in bulk.
43347 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
43348 * @return {BasicForm} this
43350 markInvalid : function(errors){
43351 if(errors instanceof Array){
43352 for(var i = 0, len = errors.length; i < len; i++){
43353 var fieldError = errors[i];
43354 var f = this.findField(fieldError.id);
43356 f.markInvalid(fieldError.msg);
43362 if(typeof errors[id] != 'function' && (field = this.findField(id))){
43363 field.markInvalid(errors[id]);
43367 Roo.each(this.childForms || [], function (f) {
43368 f.markInvalid(errors);
43375 * Set values for fields in this form in bulk.
43376 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
43377 * @return {BasicForm} this
43379 setValues : function(values){
43380 if(values instanceof Array){ // array of objects
43381 for(var i = 0, len = values.length; i < len; i++){
43383 var f = this.findField(v.id);
43385 f.setValue(v.value);
43386 if(this.trackResetOnLoad){
43387 f.originalValue = f.getValue();
43391 }else{ // object hash
43394 if(typeof values[id] != 'function' && (field = this.findField(id))){
43396 if (field.setFromData &&
43397 field.valueField &&
43398 field.displayField &&
43399 // combos' with local stores can
43400 // be queried via setValue()
43401 // to set their value..
43402 (field.store && !field.store.isLocal)
43406 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
43407 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
43408 field.setFromData(sd);
43411 field.setValue(values[id]);
43415 if(this.trackResetOnLoad){
43416 field.originalValue = field.getValue();
43422 Roo.each(this.childForms || [], function (f) {
43423 f.setValues(values);
43430 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
43431 * they are returned as an array.
43432 * @param {Boolean} asString
43435 getValues : function(asString){
43436 if (this.childForms) {
43437 // copy values from the child forms
43438 Roo.each(this.childForms, function (f) {
43439 this.setValues(f.getValues());
43445 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
43446 if(asString === true){
43449 return Roo.urlDecode(fs);
43453 * Returns the fields in this form as an object with key/value pairs.
43454 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
43457 getFieldValues : function(with_hidden)
43459 if (this.childForms) {
43460 // copy values from the child forms
43461 // should this call getFieldValues - probably not as we do not currently copy
43462 // hidden fields when we generate..
43463 Roo.each(this.childForms, function (f) {
43464 this.setValues(f.getValues());
43469 this.items.each(function(f){
43470 if (!f.getName()) {
43473 var v = f.getValue();
43474 if (f.inputType =='radio') {
43475 if (typeof(ret[f.getName()]) == 'undefined') {
43476 ret[f.getName()] = ''; // empty..
43479 if (!f.el.dom.checked) {
43483 v = f.el.dom.value;
43487 // not sure if this supported any more..
43488 if ((typeof(v) == 'object') && f.getRawValue) {
43489 v = f.getRawValue() ; // dates..
43491 // combo boxes where name != hiddenName...
43492 if (f.name != f.getName()) {
43493 ret[f.name] = f.getRawValue();
43495 ret[f.getName()] = v;
43502 * Clears all invalid messages in this form.
43503 * @return {BasicForm} this
43505 clearInvalid : function(){
43506 this.items.each(function(f){
43510 Roo.each(this.childForms || [], function (f) {
43519 * Resets this form.
43520 * @return {BasicForm} this
43522 reset : function(){
43523 this.items.each(function(f){
43527 Roo.each(this.childForms || [], function (f) {
43536 * Add Roo.form components to this form.
43537 * @param {Field} field1
43538 * @param {Field} field2 (optional)
43539 * @param {Field} etc (optional)
43540 * @return {BasicForm} this
43543 this.items.addAll(Array.prototype.slice.call(arguments, 0));
43549 * Removes a field from the items collection (does NOT remove its markup).
43550 * @param {Field} field
43551 * @return {BasicForm} this
43553 remove : function(field){
43554 this.items.remove(field);
43559 * Looks at the fields in this form, checks them for an id attribute,
43560 * and calls applyTo on the existing dom element with that id.
43561 * @return {BasicForm} this
43563 render : function(){
43564 this.items.each(function(f){
43565 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
43573 * Calls {@link Ext#apply} for all fields in this form with the passed object.
43574 * @param {Object} values
43575 * @return {BasicForm} this
43577 applyToFields : function(o){
43578 this.items.each(function(f){
43585 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
43586 * @param {Object} values
43587 * @return {BasicForm} this
43589 applyIfToFields : function(o){
43590 this.items.each(function(f){
43598 Roo.BasicForm = Roo.form.BasicForm;/*
43600 * Ext JS Library 1.1.1
43601 * Copyright(c) 2006-2007, Ext JS, LLC.
43603 * Originally Released Under LGPL - original licence link has changed is not relivant.
43606 * <script type="text/javascript">
43610 * @class Roo.form.Form
43611 * @extends Roo.form.BasicForm
43612 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
43614 * @param {Object} config Configuration options
43616 Roo.form.Form = function(config){
43618 if (config.items) {
43619 xitems = config.items;
43620 delete config.items;
43624 Roo.form.Form.superclass.constructor.call(this, null, config);
43625 this.url = this.url || this.action;
43627 this.root = new Roo.form.Layout(Roo.applyIf({
43631 this.active = this.root;
43633 * Array of all the buttons that have been added to this form via {@link addButton}
43637 this.allItems = [];
43640 * @event clientvalidation
43641 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
43642 * @param {Form} this
43643 * @param {Boolean} valid true if the form has passed client-side validation
43645 clientvalidation: true,
43648 * Fires when the form is rendered
43649 * @param {Roo.form.Form} form
43654 if (this.progressUrl) {
43655 // push a hidden field onto the list of fields..
43659 name : 'UPLOAD_IDENTIFIER'
43664 Roo.each(xitems, this.addxtype, this);
43670 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
43672 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
43675 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
43678 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
43680 buttonAlign:'center',
43683 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
43688 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
43689 * This property cascades to child containers if not set.
43694 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
43695 * fires a looping event with that state. This is required to bind buttons to the valid
43696 * state using the config value formBind:true on the button.
43698 monitorValid : false,
43701 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
43706 * @cfg {String} progressUrl - Url to return progress data
43709 progressUrl : false,
43712 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
43713 * fields are added and the column is closed. If no fields are passed the column remains open
43714 * until end() is called.
43715 * @param {Object} config The config to pass to the column
43716 * @param {Field} field1 (optional)
43717 * @param {Field} field2 (optional)
43718 * @param {Field} etc (optional)
43719 * @return Column The column container object
43721 column : function(c){
43722 var col = new Roo.form.Column(c);
43724 if(arguments.length > 1){ // duplicate code required because of Opera
43725 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43732 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
43733 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
43734 * until end() is called.
43735 * @param {Object} config The config to pass to the fieldset
43736 * @param {Field} field1 (optional)
43737 * @param {Field} field2 (optional)
43738 * @param {Field} etc (optional)
43739 * @return FieldSet The fieldset container object
43741 fieldset : function(c){
43742 var fs = new Roo.form.FieldSet(c);
43744 if(arguments.length > 1){ // duplicate code required because of Opera
43745 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43752 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
43753 * fields are added and the container is closed. If no fields are passed the container remains open
43754 * until end() is called.
43755 * @param {Object} config The config to pass to the Layout
43756 * @param {Field} field1 (optional)
43757 * @param {Field} field2 (optional)
43758 * @param {Field} etc (optional)
43759 * @return Layout The container object
43761 container : function(c){
43762 var l = new Roo.form.Layout(c);
43764 if(arguments.length > 1){ // duplicate code required because of Opera
43765 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43772 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
43773 * @param {Object} container A Roo.form.Layout or subclass of Layout
43774 * @return {Form} this
43776 start : function(c){
43777 // cascade label info
43778 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
43779 this.active.stack.push(c);
43780 c.ownerCt = this.active;
43786 * Closes the current open container
43787 * @return {Form} this
43790 if(this.active == this.root){
43793 this.active = this.active.ownerCt;
43798 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
43799 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
43800 * as the label of the field.
43801 * @param {Field} field1
43802 * @param {Field} field2 (optional)
43803 * @param {Field} etc. (optional)
43804 * @return {Form} this
43807 this.active.stack.push.apply(this.active.stack, arguments);
43808 this.allItems.push.apply(this.allItems,arguments);
43810 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
43811 if(a[i].isFormField){
43816 Roo.form.Form.superclass.add.apply(this, r);
43826 * Find any element that has been added to a form, using it's ID or name
43827 * This can include framesets, columns etc. along with regular fields..
43828 * @param {String} id - id or name to find.
43830 * @return {Element} e - or false if nothing found.
43832 findbyId : function(id)
43838 Roo.each(this.allItems, function(f){
43839 if (f.id == id || f.name == id ){
43850 * Render this form into the passed container. This should only be called once!
43851 * @param {String/HTMLElement/Element} container The element this component should be rendered into
43852 * @return {Form} this
43854 render : function(ct)
43860 var o = this.autoCreate || {
43862 method : this.method || 'POST',
43863 id : this.id || Roo.id()
43865 this.initEl(ct.createChild(o));
43867 this.root.render(this.el);
43871 this.items.each(function(f){
43872 f.render('x-form-el-'+f.id);
43875 if(this.buttons.length > 0){
43876 // tables are required to maintain order and for correct IE layout
43877 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
43878 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
43879 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
43881 var tr = tb.getElementsByTagName('tr')[0];
43882 for(var i = 0, len = this.buttons.length; i < len; i++) {
43883 var b = this.buttons[i];
43884 var td = document.createElement('td');
43885 td.className = 'x-form-btn-td';
43886 b.render(tr.appendChild(td));
43889 if(this.monitorValid){ // initialize after render
43890 this.startMonitoring();
43892 this.fireEvent('rendered', this);
43897 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
43898 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
43899 * object or a valid Roo.DomHelper element config
43900 * @param {Function} handler The function called when the button is clicked
43901 * @param {Object} scope (optional) The scope of the handler function
43902 * @return {Roo.Button}
43904 addButton : function(config, handler, scope){
43908 minWidth: this.minButtonWidth,
43911 if(typeof config == "string"){
43914 Roo.apply(bc, config);
43916 var btn = new Roo.Button(null, bc);
43917 this.buttons.push(btn);
43922 * Adds a series of form elements (using the xtype property as the factory method.
43923 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
43924 * @param {Object} config
43927 addxtype : function()
43929 var ar = Array.prototype.slice.call(arguments, 0);
43931 for(var i = 0; i < ar.length; i++) {
43933 continue; // skip -- if this happends something invalid got sent, we
43934 // should ignore it, as basically that interface element will not show up
43935 // and that should be pretty obvious!!
43938 if (Roo.form[ar[i].xtype]) {
43940 var fe = Roo.factory(ar[i], Roo.form);
43946 fe.store.form = this;
43951 this.allItems.push(fe);
43952 if (fe.items && fe.addxtype) {
43953 fe.addxtype.apply(fe, fe.items);
43963 // console.log('adding ' + ar[i].xtype);
43965 if (ar[i].xtype == 'Button') {
43966 //console.log('adding button');
43967 //console.log(ar[i]);
43968 this.addButton(ar[i]);
43969 this.allItems.push(fe);
43973 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
43974 alert('end is not supported on xtype any more, use items');
43976 // //console.log('adding end');
43984 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
43985 * option "monitorValid"
43987 startMonitoring : function(){
43990 Roo.TaskMgr.start({
43991 run : this.bindHandler,
43992 interval : this.monitorPoll || 200,
43999 * Stops monitoring of the valid state of this form
44001 stopMonitoring : function(){
44002 this.bound = false;
44006 bindHandler : function(){
44008 return false; // stops binding
44011 this.items.each(function(f){
44012 if(!f.isValid(true)){
44017 for(var i = 0, len = this.buttons.length; i < len; i++){
44018 var btn = this.buttons[i];
44019 if(btn.formBind === true && btn.disabled === valid){
44020 btn.setDisabled(!valid);
44023 this.fireEvent('clientvalidation', this, valid);
44037 Roo.Form = Roo.form.Form;
44040 * Ext JS Library 1.1.1
44041 * Copyright(c) 2006-2007, Ext JS, LLC.
44043 * Originally Released Under LGPL - original licence link has changed is not relivant.
44046 * <script type="text/javascript">
44050 * @class Roo.form.Action
44051 * Internal Class used to handle form actions
44053 * @param {Roo.form.BasicForm} el The form element or its id
44054 * @param {Object} config Configuration options
44058 // define the action interface
44059 Roo.form.Action = function(form, options){
44061 this.options = options || {};
44064 * Client Validation Failed
44067 Roo.form.Action.CLIENT_INVALID = 'client';
44069 * Server Validation Failed
44072 Roo.form.Action.SERVER_INVALID = 'server';
44074 * Connect to Server Failed
44077 Roo.form.Action.CONNECT_FAILURE = 'connect';
44079 * Reading Data from Server Failed
44082 Roo.form.Action.LOAD_FAILURE = 'load';
44084 Roo.form.Action.prototype = {
44086 failureType : undefined,
44087 response : undefined,
44088 result : undefined,
44090 // interface method
44091 run : function(options){
44095 // interface method
44096 success : function(response){
44100 // interface method
44101 handleResponse : function(response){
44105 // default connection failure
44106 failure : function(response){
44108 this.response = response;
44109 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44110 this.form.afterAction(this, false);
44113 processResponse : function(response){
44114 this.response = response;
44115 if(!response.responseText){
44118 this.result = this.handleResponse(response);
44119 return this.result;
44122 // utility functions used internally
44123 getUrl : function(appendParams){
44124 var url = this.options.url || this.form.url || this.form.el.dom.action;
44126 var p = this.getParams();
44128 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
44134 getMethod : function(){
44135 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
44138 getParams : function(){
44139 var bp = this.form.baseParams;
44140 var p = this.options.params;
44142 if(typeof p == "object"){
44143 p = Roo.urlEncode(Roo.applyIf(p, bp));
44144 }else if(typeof p == 'string' && bp){
44145 p += '&' + Roo.urlEncode(bp);
44148 p = Roo.urlEncode(bp);
44153 createCallback : function(){
44155 success: this.success,
44156 failure: this.failure,
44158 timeout: (this.form.timeout*1000),
44159 upload: this.form.fileUpload ? this.success : undefined
44164 Roo.form.Action.Submit = function(form, options){
44165 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
44168 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
44171 haveProgress : false,
44172 uploadComplete : false,
44174 // uploadProgress indicator.
44175 uploadProgress : function()
44177 if (!this.form.progressUrl) {
44181 if (!this.haveProgress) {
44182 Roo.MessageBox.progress("Uploading", "Uploading");
44184 if (this.uploadComplete) {
44185 Roo.MessageBox.hide();
44189 this.haveProgress = true;
44191 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
44193 var c = new Roo.data.Connection();
44195 url : this.form.progressUrl,
44200 success : function(req){
44201 //console.log(data);
44205 rdata = Roo.decode(req.responseText)
44207 Roo.log("Invalid data from server..");
44211 if (!rdata || !rdata.success) {
44213 Roo.MessageBox.alert(Roo.encode(rdata));
44216 var data = rdata.data;
44218 if (this.uploadComplete) {
44219 Roo.MessageBox.hide();
44224 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
44225 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
44228 this.uploadProgress.defer(2000,this);
44231 failure: function(data) {
44232 Roo.log('progress url failed ');
44243 // run get Values on the form, so it syncs any secondary forms.
44244 this.form.getValues();
44246 var o = this.options;
44247 var method = this.getMethod();
44248 var isPost = method == 'POST';
44249 if(o.clientValidation === false || this.form.isValid()){
44251 if (this.form.progressUrl) {
44252 this.form.findField('UPLOAD_IDENTIFIER').setValue(
44253 (new Date() * 1) + '' + Math.random());
44258 Roo.Ajax.request(Roo.apply(this.createCallback(), {
44259 form:this.form.el.dom,
44260 url:this.getUrl(!isPost),
44262 params:isPost ? this.getParams() : null,
44263 isUpload: this.form.fileUpload
44266 this.uploadProgress();
44268 }else if (o.clientValidation !== false){ // client validation failed
44269 this.failureType = Roo.form.Action.CLIENT_INVALID;
44270 this.form.afterAction(this, false);
44274 success : function(response)
44276 this.uploadComplete= true;
44277 if (this.haveProgress) {
44278 Roo.MessageBox.hide();
44282 var result = this.processResponse(response);
44283 if(result === true || result.success){
44284 this.form.afterAction(this, true);
44288 this.form.markInvalid(result.errors);
44289 this.failureType = Roo.form.Action.SERVER_INVALID;
44291 this.form.afterAction(this, false);
44293 failure : function(response)
44295 this.uploadComplete= true;
44296 if (this.haveProgress) {
44297 Roo.MessageBox.hide();
44300 this.response = response;
44301 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44302 this.form.afterAction(this, false);
44305 handleResponse : function(response){
44306 if(this.form.errorReader){
44307 var rs = this.form.errorReader.read(response);
44310 for(var i = 0, len = rs.records.length; i < len; i++) {
44311 var r = rs.records[i];
44312 errors[i] = r.data;
44315 if(errors.length < 1){
44319 success : rs.success,
44325 ret = Roo.decode(response.responseText);
44329 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
44339 Roo.form.Action.Load = function(form, options){
44340 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
44341 this.reader = this.form.reader;
44344 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
44349 Roo.Ajax.request(Roo.apply(
44350 this.createCallback(), {
44351 method:this.getMethod(),
44352 url:this.getUrl(false),
44353 params:this.getParams()
44357 success : function(response){
44359 var result = this.processResponse(response);
44360 if(result === true || !result.success || !result.data){
44361 this.failureType = Roo.form.Action.LOAD_FAILURE;
44362 this.form.afterAction(this, false);
44365 this.form.clearInvalid();
44366 this.form.setValues(result.data);
44367 this.form.afterAction(this, true);
44370 handleResponse : function(response){
44371 if(this.form.reader){
44372 var rs = this.form.reader.read(response);
44373 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
44375 success : rs.success,
44379 return Roo.decode(response.responseText);
44383 Roo.form.Action.ACTION_TYPES = {
44384 'load' : Roo.form.Action.Load,
44385 'submit' : Roo.form.Action.Submit
44388 * Ext JS Library 1.1.1
44389 * Copyright(c) 2006-2007, Ext JS, LLC.
44391 * Originally Released Under LGPL - original licence link has changed is not relivant.
44394 * <script type="text/javascript">
44398 * @class Roo.form.Layout
44399 * @extends Roo.Component
44400 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
44402 * @param {Object} config Configuration options
44404 Roo.form.Layout = function(config){
44406 if (config.items) {
44407 xitems = config.items;
44408 delete config.items;
44410 Roo.form.Layout.superclass.constructor.call(this, config);
44412 Roo.each(xitems, this.addxtype, this);
44416 Roo.extend(Roo.form.Layout, Roo.Component, {
44418 * @cfg {String/Object} autoCreate
44419 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
44422 * @cfg {String/Object/Function} style
44423 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
44424 * a function which returns such a specification.
44427 * @cfg {String} labelAlign
44428 * Valid values are "left," "top" and "right" (defaults to "left")
44431 * @cfg {Number} labelWidth
44432 * Fixed width in pixels of all field labels (defaults to undefined)
44435 * @cfg {Boolean} clear
44436 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
44440 * @cfg {String} labelSeparator
44441 * The separator to use after field labels (defaults to ':')
44443 labelSeparator : ':',
44445 * @cfg {Boolean} hideLabels
44446 * True to suppress the display of field labels in this layout (defaults to false)
44448 hideLabels : false,
44451 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
44456 onRender : function(ct, position){
44457 if(this.el){ // from markup
44458 this.el = Roo.get(this.el);
44459 }else { // generate
44460 var cfg = this.getAutoCreate();
44461 this.el = ct.createChild(cfg, position);
44464 this.el.applyStyles(this.style);
44466 if(this.labelAlign){
44467 this.el.addClass('x-form-label-'+this.labelAlign);
44469 if(this.hideLabels){
44470 this.labelStyle = "display:none";
44471 this.elementStyle = "padding-left:0;";
44473 if(typeof this.labelWidth == 'number'){
44474 this.labelStyle = "width:"+this.labelWidth+"px;";
44475 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
44477 if(this.labelAlign == 'top'){
44478 this.labelStyle = "width:auto;";
44479 this.elementStyle = "padding-left:0;";
44482 var stack = this.stack;
44483 var slen = stack.length;
44485 if(!this.fieldTpl){
44486 var t = new Roo.Template(
44487 '<div class="x-form-item {5}">',
44488 '<label for="{0}" style="{2}">{1}{4}</label>',
44489 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44491 '</div><div class="x-form-clear-left"></div>'
44493 t.disableFormats = true;
44495 Roo.form.Layout.prototype.fieldTpl = t;
44497 for(var i = 0; i < slen; i++) {
44498 if(stack[i].isFormField){
44499 this.renderField(stack[i]);
44501 this.renderComponent(stack[i]);
44506 this.el.createChild({cls:'x-form-clear'});
44511 renderField : function(f){
44512 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
44515 f.labelStyle||this.labelStyle||'', //2
44516 this.elementStyle||'', //3
44517 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
44518 f.itemCls||this.itemCls||'' //5
44519 ], true).getPrevSibling());
44523 renderComponent : function(c){
44524 c.render(c.isLayout ? this.el : this.el.createChild());
44527 * Adds a object form elements (using the xtype property as the factory method.)
44528 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
44529 * @param {Object} config
44531 addxtype : function(o)
44533 // create the lement.
44534 o.form = this.form;
44535 var fe = Roo.factory(o, Roo.form);
44536 this.form.allItems.push(fe);
44537 this.stack.push(fe);
44539 if (fe.isFormField) {
44540 this.form.items.add(fe);
44548 * @class Roo.form.Column
44549 * @extends Roo.form.Layout
44550 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
44552 * @param {Object} config Configuration options
44554 Roo.form.Column = function(config){
44555 Roo.form.Column.superclass.constructor.call(this, config);
44558 Roo.extend(Roo.form.Column, Roo.form.Layout, {
44560 * @cfg {Number/String} width
44561 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44564 * @cfg {String/Object} autoCreate
44565 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
44569 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
44572 onRender : function(ct, position){
44573 Roo.form.Column.superclass.onRender.call(this, ct, position);
44575 this.el.setWidth(this.width);
44582 * @class Roo.form.Row
44583 * @extends Roo.form.Layout
44584 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
44586 * @param {Object} config Configuration options
44590 Roo.form.Row = function(config){
44591 Roo.form.Row.superclass.constructor.call(this, config);
44594 Roo.extend(Roo.form.Row, Roo.form.Layout, {
44596 * @cfg {Number/String} width
44597 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44600 * @cfg {Number/String} height
44601 * The fixed height of the column in pixels or CSS value (defaults to "auto")
44603 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
44607 onRender : function(ct, position){
44608 //console.log('row render');
44610 var t = new Roo.Template(
44611 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
44612 '<label for="{0}" style="{2}">{1}{4}</label>',
44613 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44617 t.disableFormats = true;
44619 Roo.form.Layout.prototype.rowTpl = t;
44621 this.fieldTpl = this.rowTpl;
44623 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
44624 var labelWidth = 100;
44626 if ((this.labelAlign != 'top')) {
44627 if (typeof this.labelWidth == 'number') {
44628 labelWidth = this.labelWidth
44630 this.padWidth = 20 + labelWidth;
44634 Roo.form.Column.superclass.onRender.call(this, ct, position);
44636 this.el.setWidth(this.width);
44639 this.el.setHeight(this.height);
44644 renderField : function(f){
44645 f.fieldEl = this.fieldTpl.append(this.el, [
44646 f.id, f.fieldLabel,
44647 f.labelStyle||this.labelStyle||'',
44648 this.elementStyle||'',
44649 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
44650 f.itemCls||this.itemCls||'',
44651 f.width ? f.width + this.padWidth : 160 + this.padWidth
44658 * @class Roo.form.FieldSet
44659 * @extends Roo.form.Layout
44660 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
44662 * @param {Object} config Configuration options
44664 Roo.form.FieldSet = function(config){
44665 Roo.form.FieldSet.superclass.constructor.call(this, config);
44668 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
44670 * @cfg {String} legend
44671 * The text to display as the legend for the FieldSet (defaults to '')
44674 * @cfg {String/Object} autoCreate
44675 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
44679 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
44682 onRender : function(ct, position){
44683 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
44685 this.setLegend(this.legend);
44690 setLegend : function(text){
44692 this.el.child('legend').update(text);
44697 * Ext JS Library 1.1.1
44698 * Copyright(c) 2006-2007, Ext JS, LLC.
44700 * Originally Released Under LGPL - original licence link has changed is not relivant.
44703 * <script type="text/javascript">
44706 * @class Roo.form.VTypes
44707 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
44710 Roo.form.VTypes = function(){
44711 // closure these in so they are only created once.
44712 var alpha = /^[a-zA-Z_]+$/;
44713 var alphanum = /^[a-zA-Z0-9_]+$/;
44714 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
44715 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
44717 // All these messages and functions are configurable
44720 * The function used to validate email addresses
44721 * @param {String} value The email address
44723 'email' : function(v){
44724 return email.test(v);
44727 * The error text to display when the email validation function returns false
44730 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
44732 * The keystroke filter mask to be applied on email input
44735 'emailMask' : /[a-z0-9_\.\-@]/i,
44738 * The function used to validate URLs
44739 * @param {String} value The URL
44741 'url' : function(v){
44742 return url.test(v);
44745 * The error text to display when the url validation function returns false
44748 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
44751 * The function used to validate alpha values
44752 * @param {String} value The value
44754 'alpha' : function(v){
44755 return alpha.test(v);
44758 * The error text to display when the alpha validation function returns false
44761 'alphaText' : 'This field should only contain letters and _',
44763 * The keystroke filter mask to be applied on alpha input
44766 'alphaMask' : /[a-z_]/i,
44769 * The function used to validate alphanumeric values
44770 * @param {String} value The value
44772 'alphanum' : function(v){
44773 return alphanum.test(v);
44776 * The error text to display when the alphanumeric validation function returns false
44779 'alphanumText' : 'This field should only contain letters, numbers and _',
44781 * The keystroke filter mask to be applied on alphanumeric input
44784 'alphanumMask' : /[a-z0-9_]/i
44786 }();//<script type="text/javascript">
44789 * @class Roo.form.FCKeditor
44790 * @extends Roo.form.TextArea
44791 * Wrapper around the FCKEditor http://www.fckeditor.net
44793 * Creates a new FCKeditor
44794 * @param {Object} config Configuration options
44796 Roo.form.FCKeditor = function(config){
44797 Roo.form.FCKeditor.superclass.constructor.call(this, config);
44800 * @event editorinit
44801 * Fired when the editor is initialized - you can add extra handlers here..
44802 * @param {FCKeditor} this
44803 * @param {Object} the FCK object.
44810 Roo.form.FCKeditor.editors = { };
44811 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
44813 //defaultAutoCreate : {
44814 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
44818 * @cfg {Object} fck options - see fck manual for details.
44823 * @cfg {Object} fck toolbar set (Basic or Default)
44825 toolbarSet : 'Basic',
44827 * @cfg {Object} fck BasePath
44829 basePath : '/fckeditor/',
44837 onRender : function(ct, position)
44840 this.defaultAutoCreate = {
44842 style:"width:300px;height:60px;",
44843 autocomplete: "off"
44846 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
44849 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
44850 if(this.preventScrollbars){
44851 this.el.setStyle("overflow", "hidden");
44853 this.el.setHeight(this.growMin);
44856 //console.log('onrender' + this.getId() );
44857 Roo.form.FCKeditor.editors[this.getId()] = this;
44860 this.replaceTextarea() ;
44864 getEditor : function() {
44865 return this.fckEditor;
44868 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
44869 * @param {Mixed} value The value to set
44873 setValue : function(value)
44875 //console.log('setValue: ' + value);
44877 if(typeof(value) == 'undefined') { // not sure why this is happending...
44880 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44882 //if(!this.el || !this.getEditor()) {
44883 // this.value = value;
44884 //this.setValue.defer(100,this,[value]);
44888 if(!this.getEditor()) {
44892 this.getEditor().SetData(value);
44899 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
44900 * @return {Mixed} value The field value
44902 getValue : function()
44905 if (this.frame && this.frame.dom.style.display == 'none') {
44906 return Roo.form.FCKeditor.superclass.getValue.call(this);
44909 if(!this.el || !this.getEditor()) {
44911 // this.getValue.defer(100,this);
44916 var value=this.getEditor().GetData();
44917 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44918 return Roo.form.FCKeditor.superclass.getValue.call(this);
44924 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
44925 * @return {Mixed} value The field value
44927 getRawValue : function()
44929 if (this.frame && this.frame.dom.style.display == 'none') {
44930 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44933 if(!this.el || !this.getEditor()) {
44934 //this.getRawValue.defer(100,this);
44941 var value=this.getEditor().GetData();
44942 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
44943 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44947 setSize : function(w,h) {
44951 //if (this.frame && this.frame.dom.style.display == 'none') {
44952 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44955 //if(!this.el || !this.getEditor()) {
44956 // this.setSize.defer(100,this, [w,h]);
44962 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44964 this.frame.dom.setAttribute('width', w);
44965 this.frame.dom.setAttribute('height', h);
44966 this.frame.setSize(w,h);
44970 toggleSourceEdit : function(value) {
44974 this.el.dom.style.display = value ? '' : 'none';
44975 this.frame.dom.style.display = value ? 'none' : '';
44980 focus: function(tag)
44982 if (this.frame.dom.style.display == 'none') {
44983 return Roo.form.FCKeditor.superclass.focus.call(this);
44985 if(!this.el || !this.getEditor()) {
44986 this.focus.defer(100,this, [tag]);
44993 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
44994 this.getEditor().Focus();
44996 if (!this.getEditor().Selection.GetSelection()) {
44997 this.focus.defer(100,this, [tag]);
45002 var r = this.getEditor().EditorDocument.createRange();
45003 r.setStart(tgs[0],0);
45004 r.setEnd(tgs[0],0);
45005 this.getEditor().Selection.GetSelection().removeAllRanges();
45006 this.getEditor().Selection.GetSelection().addRange(r);
45007 this.getEditor().Focus();
45014 replaceTextarea : function()
45016 if ( document.getElementById( this.getId() + '___Frame' ) )
45018 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
45020 // We must check the elements firstly using the Id and then the name.
45021 var oTextarea = document.getElementById( this.getId() );
45023 var colElementsByName = document.getElementsByName( this.getId() ) ;
45025 oTextarea.style.display = 'none' ;
45027 if ( oTextarea.tabIndex ) {
45028 this.TabIndex = oTextarea.tabIndex ;
45031 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
45032 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
45033 this.frame = Roo.get(this.getId() + '___Frame')
45036 _getConfigHtml : function()
45040 for ( var o in this.fckconfig ) {
45041 sConfig += sConfig.length > 0 ? '&' : '';
45042 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
45045 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
45049 _getIFrameHtml : function()
45051 var sFile = 'fckeditor.html' ;
45052 /* no idea what this is about..
45055 if ( (/fcksource=true/i).test( window.top.location.search ) )
45056 sFile = 'fckeditor.original.html' ;
45061 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
45062 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
45065 var html = '<iframe id="' + this.getId() +
45066 '___Frame" src="' + sLink +
45067 '" width="' + this.width +
45068 '" height="' + this.height + '"' +
45069 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
45070 ' frameborder="0" scrolling="no"></iframe>' ;
45075 _insertHtmlBefore : function( html, element )
45077 if ( element.insertAdjacentHTML ) {
45079 element.insertAdjacentHTML( 'beforeBegin', html ) ;
45081 var oRange = document.createRange() ;
45082 oRange.setStartBefore( element ) ;
45083 var oFragment = oRange.createContextualFragment( html );
45084 element.parentNode.insertBefore( oFragment, element ) ;
45097 //Roo.reg('fckeditor', Roo.form.FCKeditor);
45099 function FCKeditor_OnComplete(editorInstance){
45100 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
45101 f.fckEditor = editorInstance;
45102 //console.log("loaded");
45103 f.fireEvent('editorinit', f, editorInstance);
45123 //<script type="text/javascript">
45125 * @class Roo.form.GridField
45126 * @extends Roo.form.Field
45127 * Embed a grid (or editable grid into a form)
45130 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
45132 * xgrid.store = Roo.data.Store
45133 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
45134 * xgrid.store.reader = Roo.data.JsonReader
45138 * Creates a new GridField
45139 * @param {Object} config Configuration options
45141 Roo.form.GridField = function(config){
45142 Roo.form.GridField.superclass.constructor.call(this, config);
45146 Roo.extend(Roo.form.GridField, Roo.form.Field, {
45148 * @cfg {Number} width - used to restrict width of grid..
45152 * @cfg {Number} height - used to restrict height of grid..
45156 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
45162 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45163 * {tag: "input", type: "checkbox", autocomplete: "off"})
45165 // defaultAutoCreate : { tag: 'div' },
45166 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45168 * @cfg {String} addTitle Text to include for adding a title.
45172 onResize : function(){
45173 Roo.form.Field.superclass.onResize.apply(this, arguments);
45176 initEvents : function(){
45177 // Roo.form.Checkbox.superclass.initEvents.call(this);
45178 // has no events...
45183 getResizeEl : function(){
45187 getPositionEl : function(){
45192 onRender : function(ct, position){
45194 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
45195 var style = this.style;
45198 Roo.form.GridField.superclass.onRender.call(this, ct, position);
45199 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
45200 this.viewEl = this.wrap.createChild({ tag: 'div' });
45202 this.viewEl.applyStyles(style);
45205 this.viewEl.setWidth(this.width);
45208 this.viewEl.setHeight(this.height);
45210 //if(this.inputValue !== undefined){
45211 //this.setValue(this.value);
45214 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
45217 this.grid.render();
45218 this.grid.getDataSource().on('remove', this.refreshValue, this);
45219 this.grid.getDataSource().on('update', this.refreshValue, this);
45220 this.grid.on('afteredit', this.refreshValue, this);
45226 * Sets the value of the item.
45227 * @param {String} either an object or a string..
45229 setValue : function(v){
45231 v = v || []; // empty set..
45232 // this does not seem smart - it really only affects memoryproxy grids..
45233 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
45234 var ds = this.grid.getDataSource();
45235 // assumes a json reader..
45237 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
45238 ds.loadData( data);
45240 // clear selection so it does not get stale.
45241 if (this.grid.sm) {
45242 this.grid.sm.clearSelections();
45245 Roo.form.GridField.superclass.setValue.call(this, v);
45246 this.refreshValue();
45247 // should load data in the grid really....
45251 refreshValue: function() {
45253 this.grid.getDataSource().each(function(r) {
45256 this.el.dom.value = Roo.encode(val);
45264 * Ext JS Library 1.1.1
45265 * Copyright(c) 2006-2007, Ext JS, LLC.
45267 * Originally Released Under LGPL - original licence link has changed is not relivant.
45270 * <script type="text/javascript">
45273 * @class Roo.form.DisplayField
45274 * @extends Roo.form.Field
45275 * A generic Field to display non-editable data.
45277 * Creates a new Display Field item.
45278 * @param {Object} config Configuration options
45280 Roo.form.DisplayField = function(config){
45281 Roo.form.DisplayField.superclass.constructor.call(this, config);
45285 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
45286 inputType: 'hidden',
45292 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45294 focusClass : undefined,
45296 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45298 fieldClass: 'x-form-field',
45301 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
45303 valueRenderer: undefined,
45307 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45308 * {tag: "input", type: "checkbox", autocomplete: "off"})
45311 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45313 onResize : function(){
45314 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
45318 initEvents : function(){
45319 // Roo.form.Checkbox.superclass.initEvents.call(this);
45320 // has no events...
45325 getResizeEl : function(){
45329 getPositionEl : function(){
45334 onRender : function(ct, position){
45336 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
45337 //if(this.inputValue !== undefined){
45338 this.wrap = this.el.wrap();
45340 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
45342 if (this.bodyStyle) {
45343 this.viewEl.applyStyles(this.bodyStyle);
45345 //this.viewEl.setStyle('padding', '2px');
45347 this.setValue(this.value);
45352 initValue : Roo.emptyFn,
45357 onClick : function(){
45362 * Sets the checked state of the checkbox.
45363 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
45365 setValue : function(v){
45367 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
45368 // this might be called before we have a dom element..
45369 if (!this.viewEl) {
45372 this.viewEl.dom.innerHTML = html;
45373 Roo.form.DisplayField.superclass.setValue.call(this, v);
45383 * @class Roo.form.DayPicker
45384 * @extends Roo.form.Field
45385 * A Day picker show [M] [T] [W] ....
45387 * Creates a new Day Picker
45388 * @param {Object} config Configuration options
45390 Roo.form.DayPicker= function(config){
45391 Roo.form.DayPicker.superclass.constructor.call(this, config);
45395 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
45397 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45399 focusClass : undefined,
45401 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45403 fieldClass: "x-form-field",
45406 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45407 * {tag: "input", type: "checkbox", autocomplete: "off"})
45409 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
45412 actionMode : 'viewEl',
45416 inputType : 'hidden',
45419 inputElement: false, // real input element?
45420 basedOn: false, // ????
45422 isFormField: true, // not sure where this is needed!!!!
45424 onResize : function(){
45425 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
45426 if(!this.boxLabel){
45427 this.el.alignTo(this.wrap, 'c-c');
45431 initEvents : function(){
45432 Roo.form.Checkbox.superclass.initEvents.call(this);
45433 this.el.on("click", this.onClick, this);
45434 this.el.on("change", this.onClick, this);
45438 getResizeEl : function(){
45442 getPositionEl : function(){
45448 onRender : function(ct, position){
45449 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
45451 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
45453 var r1 = '<table><tr>';
45454 var r2 = '<tr class="x-form-daypick-icons">';
45455 for (var i=0; i < 7; i++) {
45456 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
45457 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
45460 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
45461 viewEl.select('img').on('click', this.onClick, this);
45462 this.viewEl = viewEl;
45465 // this will not work on Chrome!!!
45466 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
45467 this.el.on('propertychange', this.setFromHidden, this); //ie
45475 initValue : Roo.emptyFn,
45478 * Returns the checked state of the checkbox.
45479 * @return {Boolean} True if checked, else false
45481 getValue : function(){
45482 return this.el.dom.value;
45487 onClick : function(e){
45488 //this.setChecked(!this.checked);
45489 Roo.get(e.target).toggleClass('x-menu-item-checked');
45490 this.refreshValue();
45491 //if(this.el.dom.checked != this.checked){
45492 // this.setValue(this.el.dom.checked);
45497 refreshValue : function()
45500 this.viewEl.select('img',true).each(function(e,i,n) {
45501 val += e.is(".x-menu-item-checked") ? String(n) : '';
45503 this.setValue(val, true);
45507 * Sets the checked state of the checkbox.
45508 * On is always based on a string comparison between inputValue and the param.
45509 * @param {Boolean/String} value - the value to set
45510 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
45512 setValue : function(v,suppressEvent){
45513 if (!this.el.dom) {
45516 var old = this.el.dom.value ;
45517 this.el.dom.value = v;
45518 if (suppressEvent) {
45522 // update display..
45523 this.viewEl.select('img',true).each(function(e,i,n) {
45525 var on = e.is(".x-menu-item-checked");
45526 var newv = v.indexOf(String(n)) > -1;
45528 e.toggleClass('x-menu-item-checked');
45534 this.fireEvent('change', this, v, old);
45539 // handle setting of hidden value by some other method!!?!?
45540 setFromHidden: function()
45545 //console.log("SET FROM HIDDEN");
45546 //alert('setFrom hidden');
45547 this.setValue(this.el.dom.value);
45550 onDestroy : function()
45553 Roo.get(this.viewEl).remove();
45556 Roo.form.DayPicker.superclass.onDestroy.call(this);
45560 * RooJS Library 1.1.1
45561 * Copyright(c) 2008-2011 Alan Knowles
45568 * @class Roo.form.ComboCheck
45569 * @extends Roo.form.ComboBox
45570 * A combobox for multiple select items.
45572 * FIXME - could do with a reset button..
45575 * Create a new ComboCheck
45576 * @param {Object} config Configuration options
45578 Roo.form.ComboCheck = function(config){
45579 Roo.form.ComboCheck.superclass.constructor.call(this, config);
45580 // should verify some data...
45582 // hiddenName = required..
45583 // displayField = required
45584 // valudField == required
45585 var req= [ 'hiddenName', 'displayField', 'valueField' ];
45587 Roo.each(req, function(e) {
45588 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
45589 throw "Roo.form.ComboCheck : missing value for: " + e;
45596 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
45601 selectedClass: 'x-menu-item-checked',
45604 onRender : function(ct, position){
45610 var cls = 'x-combo-list';
45613 this.tpl = new Roo.Template({
45614 html : '<div class="'+cls+'-item x-menu-check-item">' +
45615 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
45616 '<span>{' + this.displayField + '}</span>' +
45623 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
45624 this.view.singleSelect = false;
45625 this.view.multiSelect = true;
45626 this.view.toggleSelect = true;
45627 this.pageTb.add(new Roo.Toolbar.Fill(), {
45630 handler: function()
45637 onViewOver : function(e, t){
45643 onViewClick : function(doFocus,index){
45647 select: function () {
45648 //Roo.log("SELECT CALLED");
45651 selectByValue : function(xv, scrollIntoView){
45652 var ar = this.getValueArray();
45655 Roo.each(ar, function(v) {
45656 if(v === undefined || v === null){
45659 var r = this.findRecord(this.valueField, v);
45661 sels.push(this.store.indexOf(r))
45665 this.view.select(sels);
45671 onSelect : function(record, index){
45672 // Roo.log("onselect Called");
45673 // this is only called by the clear button now..
45674 this.view.clearSelections();
45675 this.setValue('[]');
45676 if (this.value != this.valueBefore) {
45677 this.fireEvent('change', this, this.value, this.valueBefore);
45678 this.valueBefore = this.value;
45681 getValueArray : function()
45686 //Roo.log(this.value);
45687 if (typeof(this.value) == 'undefined') {
45690 var ar = Roo.decode(this.value);
45691 return ar instanceof Array ? ar : []; //?? valid?
45694 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
45699 expand : function ()
45702 Roo.form.ComboCheck.superclass.expand.call(this);
45703 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
45704 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
45709 collapse : function(){
45710 Roo.form.ComboCheck.superclass.collapse.call(this);
45711 var sl = this.view.getSelectedIndexes();
45712 var st = this.store;
45716 Roo.each(sl, function(i) {
45718 nv.push(r.get(this.valueField));
45720 this.setValue(Roo.encode(nv));
45721 if (this.value != this.valueBefore) {
45723 this.fireEvent('change', this, this.value, this.valueBefore);
45724 this.valueBefore = this.value;
45729 setValue : function(v){
45733 var vals = this.getValueArray();
45735 Roo.each(vals, function(k) {
45736 var r = this.findRecord(this.valueField, k);
45738 tv.push(r.data[this.displayField]);
45739 }else if(this.valueNotFoundText !== undefined){
45740 tv.push( this.valueNotFoundText );
45745 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
45746 this.hiddenField.value = v;
45752 * Ext JS Library 1.1.1
45753 * Copyright(c) 2006-2007, Ext JS, LLC.
45755 * Originally Released Under LGPL - original licence link has changed is not relivant.
45758 * <script type="text/javascript">
45762 * @class Roo.form.Signature
45763 * @extends Roo.form.Field
45767 * @param {Object} config Configuration options
45770 Roo.form.Signature = function(config){
45771 Roo.form.Signature.superclass.constructor.call(this, config);
45773 this.addEvents({// not in used??
45776 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
45777 * @param {Roo.form.Signature} combo This combo box
45782 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
45783 * @param {Roo.form.ComboBox} combo This combo box
45784 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
45790 Roo.extend(Roo.form.Signature, Roo.form.Field, {
45792 * @cfg {Object} labels Label to use when rendering a form.
45796 * confirm : "Confirm"
45801 confirm : "Confirm"
45804 * @cfg {Number} width The signature panel width (defaults to 300)
45808 * @cfg {Number} height The signature panel height (defaults to 100)
45812 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
45814 allowBlank : false,
45817 // {Object} signPanel The signature SVG panel element (defaults to {})
45819 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
45820 isMouseDown : false,
45821 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
45822 isConfirmed : false,
45823 // {String} signatureTmp SVG mapping string (defaults to empty string)
45827 defaultAutoCreate : { // modified by initCompnoent..
45833 onRender : function(ct, position){
45835 Roo.form.Signature.superclass.onRender.call(this, ct, position);
45837 this.wrap = this.el.wrap({
45838 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
45841 this.createToolbar(this);
45842 this.signPanel = this.wrap.createChild({
45844 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
45848 this.svgID = Roo.id();
45849 this.svgEl = this.signPanel.createChild({
45850 xmlns : 'http://www.w3.org/2000/svg',
45852 id : this.svgID + "-svg",
45854 height: this.height,
45855 viewBox: '0 0 '+this.width+' '+this.height,
45859 id: this.svgID + "-svg-r",
45861 height: this.height,
45866 id: this.svgID + "-svg-l",
45868 y1: (this.height*0.8), // start set the line in 80% of height
45869 x2: this.width, // end
45870 y2: (this.height*0.8), // end set the line in 80% of height
45872 'stroke-width': "1",
45873 'stroke-dasharray': "3",
45874 'shape-rendering': "crispEdges",
45875 'pointer-events': "none"
45879 id: this.svgID + "-svg-p",
45881 'stroke-width': "3",
45883 'pointer-events': 'none'
45888 this.svgBox = this.svgEl.dom.getScreenCTM();
45890 createSVG : function(){
45891 var svg = this.signPanel;
45892 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
45895 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
45896 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
45897 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
45898 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
45899 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
45900 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
45901 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
45904 isTouchEvent : function(e){
45905 return e.type.match(/^touch/);
45907 getCoords : function (e) {
45908 var pt = this.svgEl.dom.createSVGPoint();
45911 if (this.isTouchEvent(e)) {
45912 pt.x = e.targetTouches[0].clientX
45913 pt.y = e.targetTouches[0].clientY;
45915 var a = this.svgEl.dom.getScreenCTM();
45916 var b = a.inverse();
45917 var mx = pt.matrixTransform(b);
45918 return mx.x + ',' + mx.y;
45920 //mouse event headler
45921 down : function (e) {
45922 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
45923 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
45925 this.isMouseDown = true;
45927 e.preventDefault();
45929 move : function (e) {
45930 if (this.isMouseDown) {
45931 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
45932 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
45935 e.preventDefault();
45937 up : function (e) {
45938 this.isMouseDown = false;
45939 var sp = this.signatureTmp.split(' ');
45942 if(!sp[sp.length-2].match(/^L/)){
45946 this.signatureTmp = sp.join(" ");
45949 if(this.getValue() != this.signatureTmp){
45950 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
45951 this.isConfirmed = false;
45953 e.preventDefault();
45957 * Protected method that will not generally be called directly. It
45958 * is called when the editor creates its toolbar. Override this method if you need to
45959 * add custom toolbar buttons.
45960 * @param {HtmlEditor} editor
45962 createToolbar : function(editor){
45963 function btn(id, toggle, handler){
45964 var xid = fid + '-'+ id ;
45968 cls : 'x-btn-icon x-edit-'+id,
45969 enableToggle:toggle !== false,
45970 scope: editor, // was editor...
45971 handler:handler||editor.relayBtnCmd,
45972 clickEvent:'mousedown',
45973 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45979 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45983 cls : ' x-signature-btn x-signature-'+id,
45984 scope: editor, // was editor...
45985 handler: this.reset,
45986 clickEvent:'mousedown',
45987 text: this.labels.clear
45994 cls : ' x-signature-btn x-signature-'+id,
45995 scope: editor, // was editor...
45996 handler: this.confirmHandler,
45997 clickEvent:'mousedown',
45998 text: this.labels.confirm
46005 * when user is clicked confirm then show this image.....
46007 * @return {String} Image Data URI
46009 getImageDataURI : function(){
46010 var svg = this.svgEl.dom.parentNode.innerHTML;
46011 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
46016 * @return {Boolean} this.isConfirmed
46018 getConfirmed : function(){
46019 return this.isConfirmed;
46023 * @return {Number} this.width
46025 getWidth : function(){
46030 * @return {Number} this.height
46032 getHeight : function(){
46033 return this.height;
46036 getSignature : function(){
46037 return this.signatureTmp;
46040 reset : function(){
46041 this.signatureTmp = '';
46042 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46043 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
46044 this.isConfirmed = false;
46045 Roo.form.Signature.superclass.reset.call(this);
46047 setSignature : function(s){
46048 this.signatureTmp = s;
46049 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46050 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
46052 this.isConfirmed = false;
46053 Roo.form.Signature.superclass.reset.call(this);
46056 // Roo.log(this.signPanel.dom.contentWindow.up())
46059 setConfirmed : function(){
46063 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
46066 confirmHandler : function(){
46067 if(!this.getSignature()){
46071 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
46072 this.setValue(this.getSignature());
46073 this.isConfirmed = true;
46075 this.fireEvent('confirm', this);
46078 // Subclasses should provide the validation implementation by overriding this
46079 validateValue : function(value){
46080 if(this.allowBlank){
46084 if(this.isConfirmed){
46091 * Ext JS Library 1.1.1
46092 * Copyright(c) 2006-2007, Ext JS, LLC.
46094 * Originally Released Under LGPL - original licence link has changed is not relivant.
46097 * <script type="text/javascript">
46102 * @class Roo.form.ComboBox
46103 * @extends Roo.form.TriggerField
46104 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
46106 * Create a new ComboBox.
46107 * @param {Object} config Configuration options
46109 Roo.form.Select = function(config){
46110 Roo.form.Select.superclass.constructor.call(this, config);
46114 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
46116 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
46119 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
46120 * rendering into an Roo.Editor, defaults to false)
46123 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
46124 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
46127 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
46130 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
46131 * the dropdown list (defaults to undefined, with no header element)
46135 * @cfg {String/Roo.Template} tpl The template to use to render the output
46139 defaultAutoCreate : {tag: "select" },
46141 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
46143 listWidth: undefined,
46145 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
46146 * mode = 'remote' or 'text' if mode = 'local')
46148 displayField: undefined,
46150 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
46151 * mode = 'remote' or 'value' if mode = 'local').
46152 * Note: use of a valueField requires the user make a selection
46153 * in order for a value to be mapped.
46155 valueField: undefined,
46159 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
46160 * field's data value (defaults to the underlying DOM element's name)
46162 hiddenName: undefined,
46164 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
46168 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
46170 selectedClass: 'x-combo-selected',
46172 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
46173 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
46174 * which displays a downward arrow icon).
46176 triggerClass : 'x-form-arrow-trigger',
46178 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
46182 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
46183 * anchor positions (defaults to 'tl-bl')
46185 listAlign: 'tl-bl?',
46187 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
46191 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
46192 * query specified by the allQuery config option (defaults to 'query')
46194 triggerAction: 'query',
46196 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
46197 * (defaults to 4, does not apply if editable = false)
46201 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
46202 * delay (typeAheadDelay) if it matches a known value (defaults to false)
46206 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
46207 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
46211 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
46212 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
46216 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
46217 * when editable = true (defaults to false)
46219 selectOnFocus:false,
46221 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
46223 queryParam: 'query',
46225 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
46226 * when mode = 'remote' (defaults to 'Loading...')
46228 loadingText: 'Loading...',
46230 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
46234 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
46238 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
46239 * traditional select (defaults to true)
46243 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
46247 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
46251 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
46252 * listWidth has a higher value)
46256 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
46257 * allow the user to set arbitrary text into the field (defaults to false)
46259 forceSelection:false,
46261 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
46262 * if typeAhead = true (defaults to 250)
46264 typeAheadDelay : 250,
46266 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
46267 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
46269 valueNotFoundText : undefined,
46272 * @cfg {String} defaultValue The value displayed after loading the store.
46277 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
46279 blockFocus : false,
46282 * @cfg {Boolean} disableClear Disable showing of clear button.
46284 disableClear : false,
46286 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
46288 alwaysQuery : false,
46294 // element that contains real text value.. (when hidden is used..)
46297 onRender : function(ct, position){
46298 Roo.form.Field.prototype.onRender.call(this, ct, position);
46301 this.store.on('beforeload', this.onBeforeLoad, this);
46302 this.store.on('load', this.onLoad, this);
46303 this.store.on('loadexception', this.onLoadException, this);
46304 this.store.load({});
46312 initEvents : function(){
46313 //Roo.form.ComboBox.superclass.initEvents.call(this);
46317 onDestroy : function(){
46320 this.store.un('beforeload', this.onBeforeLoad, this);
46321 this.store.un('load', this.onLoad, this);
46322 this.store.un('loadexception', this.onLoadException, this);
46324 //Roo.form.ComboBox.superclass.onDestroy.call(this);
46328 fireKey : function(e){
46329 if(e.isNavKeyPress() && !this.list.isVisible()){
46330 this.fireEvent("specialkey", this, e);
46335 onResize: function(w, h){
46343 * Allow or prevent the user from directly editing the field text. If false is passed,
46344 * the user will only be able to select from the items defined in the dropdown list. This method
46345 * is the runtime equivalent of setting the 'editable' config option at config time.
46346 * @param {Boolean} value True to allow the user to directly edit the field text
46348 setEditable : function(value){
46353 onBeforeLoad : function(){
46355 Roo.log("Select before load");
46358 this.innerList.update(this.loadingText ?
46359 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
46360 //this.restrictHeight();
46361 this.selectedIndex = -1;
46365 onLoad : function(){
46368 var dom = this.el.dom;
46369 dom.innerHTML = '';
46370 var od = dom.ownerDocument;
46372 if (this.emptyText) {
46373 var op = od.createElement('option');
46374 op.setAttribute('value', '');
46375 op.innerHTML = String.format('{0}', this.emptyText);
46376 dom.appendChild(op);
46378 if(this.store.getCount() > 0){
46380 var vf = this.valueField;
46381 var df = this.displayField;
46382 this.store.data.each(function(r) {
46383 // which colmsn to use... testing - cdoe / title..
46384 var op = od.createElement('option');
46385 op.setAttribute('value', r.data[vf]);
46386 op.innerHTML = String.format('{0}', r.data[df]);
46387 dom.appendChild(op);
46389 if (typeof(this.defaultValue != 'undefined')) {
46390 this.setValue(this.defaultValue);
46395 //this.onEmptyResults();
46400 onLoadException : function()
46402 dom.innerHTML = '';
46404 Roo.log("Select on load exception");
46408 Roo.log(this.store.reader.jsonData);
46409 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
46410 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
46416 onTypeAhead : function(){
46421 onSelect : function(record, index){
46422 Roo.log('on select?');
46424 if(this.fireEvent('beforeselect', this, record, index) !== false){
46425 this.setFromData(index > -1 ? record.data : false);
46427 this.fireEvent('select', this, record, index);
46432 * Returns the currently selected field value or empty string if no value is set.
46433 * @return {String} value The selected value
46435 getValue : function(){
46436 var dom = this.el.dom;
46437 this.value = dom.options[dom.selectedIndex].value;
46443 * Clears any text/value currently set in the field
46445 clearValue : function(){
46447 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
46452 * Sets the specified value into the field. If the value finds a match, the corresponding record text
46453 * will be displayed in the field. If the value does not match the data value of an existing item,
46454 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
46455 * Otherwise the field will be blank (although the value will still be set).
46456 * @param {String} value The value to match
46458 setValue : function(v){
46459 var d = this.el.dom;
46460 for (var i =0; i < d.options.length;i++) {
46461 if (v == d.options[i].value) {
46462 d.selectedIndex = i;
46470 * @property {Object} the last set data for the element
46475 * Sets the value of the field based on a object which is related to the record format for the store.
46476 * @param {Object} value the value to set as. or false on reset?
46478 setFromData : function(o){
46479 Roo.log('setfrom data?');
46485 reset : function(){
46489 findRecord : function(prop, value){
46494 if(this.store.getCount() > 0){
46495 this.store.each(function(r){
46496 if(r.data[prop] == value){
46506 getName: function()
46508 // returns hidden if it's set..
46509 if (!this.rendered) {return ''};
46510 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
46518 onEmptyResults : function(){
46519 Roo.log('empty results');
46524 * Returns true if the dropdown list is expanded, else false.
46526 isExpanded : function(){
46531 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
46532 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
46533 * @param {String} value The data value of the item to select
46534 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
46535 * selected item if it is not currently in view (defaults to true)
46536 * @return {Boolean} True if the value matched an item in the list, else false
46538 selectByValue : function(v, scrollIntoView){
46539 Roo.log('select By Value');
46542 if(v !== undefined && v !== null){
46543 var r = this.findRecord(this.valueField || this.displayField, v);
46545 this.select(this.store.indexOf(r), scrollIntoView);
46553 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
46554 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
46555 * @param {Number} index The zero-based index of the list item to select
46556 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
46557 * selected item if it is not currently in view (defaults to true)
46559 select : function(index, scrollIntoView){
46560 Roo.log('select ');
46563 this.selectedIndex = index;
46564 this.view.select(index);
46565 if(scrollIntoView !== false){
46566 var el = this.view.getNode(index);
46568 this.innerList.scrollChildIntoView(el, false);
46576 validateBlur : function(){
46583 initQuery : function(){
46584 this.doQuery(this.getRawValue());
46588 doForce : function(){
46589 if(this.el.dom.value.length > 0){
46590 this.el.dom.value =
46591 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
46597 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
46598 * query allowing the query action to be canceled if needed.
46599 * @param {String} query The SQL query to execute
46600 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
46601 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
46602 * saved in the current store (defaults to false)
46604 doQuery : function(q, forceAll){
46606 Roo.log('doQuery?');
46607 if(q === undefined || q === null){
46612 forceAll: forceAll,
46616 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
46620 forceAll = qe.forceAll;
46621 if(forceAll === true || (q.length >= this.minChars)){
46622 if(this.lastQuery != q || this.alwaysQuery){
46623 this.lastQuery = q;
46624 if(this.mode == 'local'){
46625 this.selectedIndex = -1;
46627 this.store.clearFilter();
46629 this.store.filter(this.displayField, q);
46633 this.store.baseParams[this.queryParam] = q;
46635 params: this.getParams(q)
46640 this.selectedIndex = -1;
46647 getParams : function(q){
46649 //p[this.queryParam] = q;
46652 p.limit = this.pageSize;
46658 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
46660 collapse : function(){
46665 collapseIf : function(e){
46670 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
46672 expand : function(){
46680 * @cfg {Boolean} grow
46684 * @cfg {Number} growMin
46688 * @cfg {Number} growMax
46696 setWidth : function()
46700 getResizeEl : function(){
46703 });//<script type="text/javasscript">
46707 * @class Roo.DDView
46708 * A DnD enabled version of Roo.View.
46709 * @param {Element/String} container The Element in which to create the View.
46710 * @param {String} tpl The template string used to create the markup for each element of the View
46711 * @param {Object} config The configuration properties. These include all the config options of
46712 * {@link Roo.View} plus some specific to this class.<br>
46714 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
46715 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
46717 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
46718 .x-view-drag-insert-above {
46719 border-top:1px dotted #3366cc;
46721 .x-view-drag-insert-below {
46722 border-bottom:1px dotted #3366cc;
46728 Roo.DDView = function(container, tpl, config) {
46729 Roo.DDView.superclass.constructor.apply(this, arguments);
46730 this.getEl().setStyle("outline", "0px none");
46731 this.getEl().unselectable();
46732 if (this.dragGroup) {
46733 this.setDraggable(this.dragGroup.split(","));
46735 if (this.dropGroup) {
46736 this.setDroppable(this.dropGroup.split(","));
46738 if (this.deletable) {
46739 this.setDeletable();
46741 this.isDirtyFlag = false;
46747 Roo.extend(Roo.DDView, Roo.View, {
46748 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
46749 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
46750 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
46751 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
46755 reset: Roo.emptyFn,
46757 clearInvalid: Roo.form.Field.prototype.clearInvalid,
46759 validate: function() {
46763 destroy: function() {
46764 this.purgeListeners();
46765 this.getEl.removeAllListeners();
46766 this.getEl().remove();
46767 if (this.dragZone) {
46768 if (this.dragZone.destroy) {
46769 this.dragZone.destroy();
46772 if (this.dropZone) {
46773 if (this.dropZone.destroy) {
46774 this.dropZone.destroy();
46779 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
46780 getName: function() {
46784 /** Loads the View from a JSON string representing the Records to put into the Store. */
46785 setValue: function(v) {
46787 throw "DDView.setValue(). DDView must be constructed with a valid Store";
46790 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
46791 this.store.proxy = new Roo.data.MemoryProxy(data);
46795 /** @return {String} a parenthesised list of the ids of the Records in the View. */
46796 getValue: function() {
46798 this.store.each(function(rec) {
46799 result += rec.id + ',';
46801 return result.substr(0, result.length - 1) + ')';
46804 getIds: function() {
46805 var i = 0, result = new Array(this.store.getCount());
46806 this.store.each(function(rec) {
46807 result[i++] = rec.id;
46812 isDirty: function() {
46813 return this.isDirtyFlag;
46817 * Part of the Roo.dd.DropZone interface. If no target node is found, the
46818 * whole Element becomes the target, and this causes the drop gesture to append.
46820 getTargetFromEvent : function(e) {
46821 var target = e.getTarget();
46822 while ((target !== null) && (target.parentNode != this.el.dom)) {
46823 target = target.parentNode;
46826 target = this.el.dom.lastChild || this.el.dom;
46832 * Create the drag data which consists of an object which has the property "ddel" as
46833 * the drag proxy element.
46835 getDragData : function(e) {
46836 var target = this.findItemFromChild(e.getTarget());
46838 this.handleSelection(e);
46839 var selNodes = this.getSelectedNodes();
46842 copy: this.copy || (this.allowCopy && e.ctrlKey),
46846 var selectedIndices = this.getSelectedIndexes();
46847 for (var i = 0; i < selectedIndices.length; i++) {
46848 dragData.records.push(this.store.getAt(selectedIndices[i]));
46850 if (selNodes.length == 1) {
46851 dragData.ddel = target.cloneNode(true); // the div element
46853 var div = document.createElement('div'); // create the multi element drag "ghost"
46854 div.className = 'multi-proxy';
46855 for (var i = 0, len = selNodes.length; i < len; i++) {
46856 div.appendChild(selNodes[i].cloneNode(true));
46858 dragData.ddel = div;
46860 //console.log(dragData)
46861 //console.log(dragData.ddel.innerHTML)
46864 //console.log('nodragData')
46868 /** Specify to which ddGroup items in this DDView may be dragged. */
46869 setDraggable: function(ddGroup) {
46870 if (ddGroup instanceof Array) {
46871 Roo.each(ddGroup, this.setDraggable, this);
46874 if (this.dragZone) {
46875 this.dragZone.addToGroup(ddGroup);
46877 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
46878 containerScroll: true,
46882 // Draggability implies selection. DragZone's mousedown selects the element.
46883 if (!this.multiSelect) { this.singleSelect = true; }
46885 // Wire the DragZone's handlers up to methods in *this*
46886 this.dragZone.getDragData = this.getDragData.createDelegate(this);
46890 /** Specify from which ddGroup this DDView accepts drops. */
46891 setDroppable: function(ddGroup) {
46892 if (ddGroup instanceof Array) {
46893 Roo.each(ddGroup, this.setDroppable, this);
46896 if (this.dropZone) {
46897 this.dropZone.addToGroup(ddGroup);
46899 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
46900 containerScroll: true,
46904 // Wire the DropZone's handlers up to methods in *this*
46905 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
46906 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
46907 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
46908 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
46909 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
46913 /** Decide whether to drop above or below a View node. */
46914 getDropPoint : function(e, n, dd){
46915 if (n == this.el.dom) { return "above"; }
46916 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
46917 var c = t + (b - t) / 2;
46918 var y = Roo.lib.Event.getPageY(e);
46926 onNodeEnter : function(n, dd, e, data){
46930 onNodeOver : function(n, dd, e, data){
46931 var pt = this.getDropPoint(e, n, dd);
46932 // set the insert point style on the target node
46933 var dragElClass = this.dropNotAllowed;
46936 if (pt == "above"){
46937 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
46938 targetElClass = "x-view-drag-insert-above";
46940 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
46941 targetElClass = "x-view-drag-insert-below";
46943 if (this.lastInsertClass != targetElClass){
46944 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
46945 this.lastInsertClass = targetElClass;
46948 return dragElClass;
46951 onNodeOut : function(n, dd, e, data){
46952 this.removeDropIndicators(n);
46955 onNodeDrop : function(n, dd, e, data){
46956 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
46959 var pt = this.getDropPoint(e, n, dd);
46960 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
46961 if (pt == "below") { insertAt++; }
46962 for (var i = 0; i < data.records.length; i++) {
46963 var r = data.records[i];
46964 var dup = this.store.getById(r.id);
46965 if (dup && (dd != this.dragZone)) {
46966 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
46969 this.store.insert(insertAt++, r.copy());
46971 data.source.isDirtyFlag = true;
46973 this.store.insert(insertAt++, r);
46975 this.isDirtyFlag = true;
46978 this.dragZone.cachedTarget = null;
46982 removeDropIndicators : function(n){
46984 Roo.fly(n).removeClass([
46985 "x-view-drag-insert-above",
46986 "x-view-drag-insert-below"]);
46987 this.lastInsertClass = "_noclass";
46992 * Utility method. Add a delete option to the DDView's context menu.
46993 * @param {String} imageUrl The URL of the "delete" icon image.
46995 setDeletable: function(imageUrl) {
46996 if (!this.singleSelect && !this.multiSelect) {
46997 this.singleSelect = true;
46999 var c = this.getContextMenu();
47000 this.contextMenu.on("itemclick", function(item) {
47003 this.remove(this.getSelectedIndexes());
47007 this.contextMenu.add({
47014 /** Return the context menu for this DDView. */
47015 getContextMenu: function() {
47016 if (!this.contextMenu) {
47017 // Create the View's context menu
47018 this.contextMenu = new Roo.menu.Menu({
47019 id: this.id + "-contextmenu"
47021 this.el.on("contextmenu", this.showContextMenu, this);
47023 return this.contextMenu;
47026 disableContextMenu: function() {
47027 if (this.contextMenu) {
47028 this.el.un("contextmenu", this.showContextMenu, this);
47032 showContextMenu: function(e, item) {
47033 item = this.findItemFromChild(e.getTarget());
47036 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
47037 this.contextMenu.showAt(e.getXY());
47042 * Remove {@link Roo.data.Record}s at the specified indices.
47043 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
47045 remove: function(selectedIndices) {
47046 selectedIndices = [].concat(selectedIndices);
47047 for (var i = 0; i < selectedIndices.length; i++) {
47048 var rec = this.store.getAt(selectedIndices[i]);
47049 this.store.remove(rec);
47054 * Double click fires the event, but also, if this is draggable, and there is only one other
47055 * related DropZone, it transfers the selected node.
47057 onDblClick : function(e){
47058 var item = this.findItemFromChild(e.getTarget());
47060 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
47063 if (this.dragGroup) {
47064 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
47065 while (targets.indexOf(this.dropZone) > -1) {
47066 targets.remove(this.dropZone);
47068 if (targets.length == 1) {
47069 this.dragZone.cachedTarget = null;
47070 var el = Roo.get(targets[0].getEl());
47071 var box = el.getBox(true);
47072 targets[0].onNodeDrop(el.dom, {
47074 xy: [box.x, box.y + box.height - 1]
47075 }, null, this.getDragData(e));
47081 handleSelection: function(e) {
47082 this.dragZone.cachedTarget = null;
47083 var item = this.findItemFromChild(e.getTarget());
47085 this.clearSelections(true);
47088 if (item && (this.multiSelect || this.singleSelect)){
47089 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
47090 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
47091 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
47092 this.unselect(item);
47094 this.select(item, this.multiSelect && e.ctrlKey);
47095 this.lastSelection = item;
47100 onItemClick : function(item, index, e){
47101 if(this.fireEvent("beforeclick", this, index, item, e) === false){
47107 unselect : function(nodeInfo, suppressEvent){
47108 var node = this.getNode(nodeInfo);
47109 if(node && this.isSelected(node)){
47110 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
47111 Roo.fly(node).removeClass(this.selectedClass);
47112 this.selections.remove(node);
47113 if(!suppressEvent){
47114 this.fireEvent("selectionchange", this, this.selections);
47122 * Ext JS Library 1.1.1
47123 * Copyright(c) 2006-2007, Ext JS, LLC.
47125 * Originally Released Under LGPL - original licence link has changed is not relivant.
47128 * <script type="text/javascript">
47132 * @class Roo.LayoutManager
47133 * @extends Roo.util.Observable
47134 * Base class for layout managers.
47136 Roo.LayoutManager = function(container, config){
47137 Roo.LayoutManager.superclass.constructor.call(this);
47138 this.el = Roo.get(container);
47139 // ie scrollbar fix
47140 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
47141 document.body.scroll = "no";
47142 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
47143 this.el.position('relative');
47145 this.id = this.el.id;
47146 this.el.addClass("x-layout-container");
47147 /** false to disable window resize monitoring @type Boolean */
47148 this.monitorWindowResize = true;
47153 * Fires when a layout is performed.
47154 * @param {Roo.LayoutManager} this
47158 * @event regionresized
47159 * Fires when the user resizes a region.
47160 * @param {Roo.LayoutRegion} region The resized region
47161 * @param {Number} newSize The new size (width for east/west, height for north/south)
47163 "regionresized" : true,
47165 * @event regioncollapsed
47166 * Fires when a region is collapsed.
47167 * @param {Roo.LayoutRegion} region The collapsed region
47169 "regioncollapsed" : true,
47171 * @event regionexpanded
47172 * Fires when a region is expanded.
47173 * @param {Roo.LayoutRegion} region The expanded region
47175 "regionexpanded" : true
47177 this.updating = false;
47178 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47181 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
47183 * Returns true if this layout is currently being updated
47184 * @return {Boolean}
47186 isUpdating : function(){
47187 return this.updating;
47191 * Suspend the LayoutManager from doing auto-layouts while
47192 * making multiple add or remove calls
47194 beginUpdate : function(){
47195 this.updating = true;
47199 * Restore auto-layouts and optionally disable the manager from performing a layout
47200 * @param {Boolean} noLayout true to disable a layout update
47202 endUpdate : function(noLayout){
47203 this.updating = false;
47209 layout: function(){
47213 onRegionResized : function(region, newSize){
47214 this.fireEvent("regionresized", region, newSize);
47218 onRegionCollapsed : function(region){
47219 this.fireEvent("regioncollapsed", region);
47222 onRegionExpanded : function(region){
47223 this.fireEvent("regionexpanded", region);
47227 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
47228 * performs box-model adjustments.
47229 * @return {Object} The size as an object {width: (the width), height: (the height)}
47231 getViewSize : function(){
47233 if(this.el.dom != document.body){
47234 size = this.el.getSize();
47236 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
47238 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
47239 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
47244 * Returns the Element this layout is bound to.
47245 * @return {Roo.Element}
47247 getEl : function(){
47252 * Returns the specified region.
47253 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
47254 * @return {Roo.LayoutRegion}
47256 getRegion : function(target){
47257 return this.regions[target.toLowerCase()];
47260 onWindowResize : function(){
47261 if(this.monitorWindowResize){
47267 * Ext JS Library 1.1.1
47268 * Copyright(c) 2006-2007, Ext JS, LLC.
47270 * Originally Released Under LGPL - original licence link has changed is not relivant.
47273 * <script type="text/javascript">
47276 * @class Roo.BorderLayout
47277 * @extends Roo.LayoutManager
47278 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
47279 * please see: <br><br>
47280 * <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>
47281 * <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>
47284 var layout = new Roo.BorderLayout(document.body, {
47318 preferredTabWidth: 150
47323 var CP = Roo.ContentPanel;
47325 layout.beginUpdate();
47326 layout.add("north", new CP("north", "North"));
47327 layout.add("south", new CP("south", {title: "South", closable: true}));
47328 layout.add("west", new CP("west", {title: "West"}));
47329 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
47330 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
47331 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
47332 layout.getRegion("center").showPanel("center1");
47333 layout.endUpdate();
47336 <b>The container the layout is rendered into can be either the body element or any other element.
47337 If it is not the body element, the container needs to either be an absolute positioned element,
47338 or you will need to add "position:relative" to the css of the container. You will also need to specify
47339 the container size if it is not the body element.</b>
47342 * Create a new BorderLayout
47343 * @param {String/HTMLElement/Element} container The container this layout is bound to
47344 * @param {Object} config Configuration options
47346 Roo.BorderLayout = function(container, config){
47347 config = config || {};
47348 Roo.BorderLayout.superclass.constructor.call(this, container, config);
47349 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
47350 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
47351 var target = this.factory.validRegions[i];
47352 if(config[target]){
47353 this.addRegion(target, config[target]);
47358 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
47360 * Creates and adds a new region if it doesn't already exist.
47361 * @param {String} target The target region key (north, south, east, west or center).
47362 * @param {Object} config The regions config object
47363 * @return {BorderLayoutRegion} The new region
47365 addRegion : function(target, config){
47366 if(!this.regions[target]){
47367 var r = this.factory.create(target, this, config);
47368 this.bindRegion(target, r);
47370 return this.regions[target];
47374 bindRegion : function(name, r){
47375 this.regions[name] = r;
47376 r.on("visibilitychange", this.layout, this);
47377 r.on("paneladded", this.layout, this);
47378 r.on("panelremoved", this.layout, this);
47379 r.on("invalidated", this.layout, this);
47380 r.on("resized", this.onRegionResized, this);
47381 r.on("collapsed", this.onRegionCollapsed, this);
47382 r.on("expanded", this.onRegionExpanded, this);
47386 * Performs a layout update.
47388 layout : function(){
47389 if(this.updating) return;
47390 var size = this.getViewSize();
47391 var w = size.width;
47392 var h = size.height;
47397 //var x = 0, y = 0;
47399 var rs = this.regions;
47400 var north = rs["north"];
47401 var south = rs["south"];
47402 var west = rs["west"];
47403 var east = rs["east"];
47404 var center = rs["center"];
47405 //if(this.hideOnLayout){ // not supported anymore
47406 //c.el.setStyle("display", "none");
47408 if(north && north.isVisible()){
47409 var b = north.getBox();
47410 var m = north.getMargins();
47411 b.width = w - (m.left+m.right);
47414 centerY = b.height + b.y + m.bottom;
47415 centerH -= centerY;
47416 north.updateBox(this.safeBox(b));
47418 if(south && south.isVisible()){
47419 var b = south.getBox();
47420 var m = south.getMargins();
47421 b.width = w - (m.left+m.right);
47423 var totalHeight = (b.height + m.top + m.bottom);
47424 b.y = h - totalHeight + m.top;
47425 centerH -= totalHeight;
47426 south.updateBox(this.safeBox(b));
47428 if(west && west.isVisible()){
47429 var b = west.getBox();
47430 var m = west.getMargins();
47431 b.height = centerH - (m.top+m.bottom);
47433 b.y = centerY + m.top;
47434 var totalWidth = (b.width + m.left + m.right);
47435 centerX += totalWidth;
47436 centerW -= totalWidth;
47437 west.updateBox(this.safeBox(b));
47439 if(east && east.isVisible()){
47440 var b = east.getBox();
47441 var m = east.getMargins();
47442 b.height = centerH - (m.top+m.bottom);
47443 var totalWidth = (b.width + m.left + m.right);
47444 b.x = w - totalWidth + m.left;
47445 b.y = centerY + m.top;
47446 centerW -= totalWidth;
47447 east.updateBox(this.safeBox(b));
47450 var m = center.getMargins();
47452 x: centerX + m.left,
47453 y: centerY + m.top,
47454 width: centerW - (m.left+m.right),
47455 height: centerH - (m.top+m.bottom)
47457 //if(this.hideOnLayout){
47458 //center.el.setStyle("display", "block");
47460 center.updateBox(this.safeBox(centerBox));
47463 this.fireEvent("layout", this);
47467 safeBox : function(box){
47468 box.width = Math.max(0, box.width);
47469 box.height = Math.max(0, box.height);
47474 * Adds a ContentPanel (or subclass) to this layout.
47475 * @param {String} target The target region key (north, south, east, west or center).
47476 * @param {Roo.ContentPanel} panel The panel to add
47477 * @return {Roo.ContentPanel} The added panel
47479 add : function(target, panel){
47481 target = target.toLowerCase();
47482 return this.regions[target].add(panel);
47486 * Remove a ContentPanel (or subclass) to this layout.
47487 * @param {String} target The target region key (north, south, east, west or center).
47488 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
47489 * @return {Roo.ContentPanel} The removed panel
47491 remove : function(target, panel){
47492 target = target.toLowerCase();
47493 return this.regions[target].remove(panel);
47497 * Searches all regions for a panel with the specified id
47498 * @param {String} panelId
47499 * @return {Roo.ContentPanel} The panel or null if it wasn't found
47501 findPanel : function(panelId){
47502 var rs = this.regions;
47503 for(var target in rs){
47504 if(typeof rs[target] != "function"){
47505 var p = rs[target].getPanel(panelId);
47515 * Searches all regions for a panel with the specified id and activates (shows) it.
47516 * @param {String/ContentPanel} panelId The panels id or the panel itself
47517 * @return {Roo.ContentPanel} The shown panel or null
47519 showPanel : function(panelId) {
47520 var rs = this.regions;
47521 for(var target in rs){
47522 var r = rs[target];
47523 if(typeof r != "function"){
47524 if(r.hasPanel(panelId)){
47525 return r.showPanel(panelId);
47533 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
47534 * @param {Roo.state.Provider} provider (optional) An alternate state provider
47536 restoreState : function(provider){
47538 provider = Roo.state.Manager;
47540 var sm = new Roo.LayoutStateManager();
47541 sm.init(this, provider);
47545 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
47546 * object should contain properties for each region to add ContentPanels to, and each property's value should be
47547 * a valid ContentPanel config object. Example:
47549 // Create the main layout
47550 var layout = new Roo.BorderLayout('main-ct', {
47561 // Create and add multiple ContentPanels at once via configs
47564 id: 'source-files',
47566 title:'Ext Source Files',
47579 * @param {Object} regions An object containing ContentPanel configs by region name
47581 batchAdd : function(regions){
47582 this.beginUpdate();
47583 for(var rname in regions){
47584 var lr = this.regions[rname];
47586 this.addTypedPanels(lr, regions[rname]);
47593 addTypedPanels : function(lr, ps){
47594 if(typeof ps == 'string'){
47595 lr.add(new Roo.ContentPanel(ps));
47597 else if(ps instanceof Array){
47598 for(var i =0, len = ps.length; i < len; i++){
47599 this.addTypedPanels(lr, ps[i]);
47602 else if(!ps.events){ // raw config?
47604 delete ps.el; // prevent conflict
47605 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
47607 else { // panel object assumed!
47612 * Adds a xtype elements to the layout.
47616 xtype : 'ContentPanel',
47623 xtype : 'NestedLayoutPanel',
47629 items : [ ... list of content panels or nested layout panels.. ]
47633 * @param {Object} cfg Xtype definition of item to add.
47635 addxtype : function(cfg)
47637 // basically accepts a pannel...
47638 // can accept a layout region..!?!?
47639 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
47641 if (!cfg.xtype.match(/Panel$/)) {
47646 if (typeof(cfg.region) == 'undefined') {
47647 Roo.log("Failed to add Panel, region was not set");
47651 var region = cfg.region;
47657 xitems = cfg.items;
47664 case 'ContentPanel': // ContentPanel (el, cfg)
47665 case 'ScrollPanel': // ContentPanel (el, cfg)
47667 if(cfg.autoCreate) {
47668 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
47670 var el = this.el.createChild();
47671 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
47674 this.add(region, ret);
47678 case 'TreePanel': // our new panel!
47679 cfg.el = this.el.createChild();
47680 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
47681 this.add(region, ret);
47684 case 'NestedLayoutPanel':
47685 // create a new Layout (which is a Border Layout...
47686 var el = this.el.createChild();
47687 var clayout = cfg.layout;
47689 clayout.items = clayout.items || [];
47690 // replace this exitems with the clayout ones..
47691 xitems = clayout.items;
47694 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
47695 cfg.background = false;
47697 var layout = new Roo.BorderLayout(el, clayout);
47699 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
47700 //console.log('adding nested layout panel ' + cfg.toSource());
47701 this.add(region, ret);
47702 nb = {}; /// find first...
47707 // needs grid and region
47709 //var el = this.getRegion(region).el.createChild();
47710 var el = this.el.createChild();
47711 // create the grid first...
47713 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
47715 if (region == 'center' && this.active ) {
47716 cfg.background = false;
47718 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
47720 this.add(region, ret);
47721 if (cfg.background) {
47722 ret.on('activate', function(gp) {
47723 if (!gp.grid.rendered) {
47738 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
47740 // GridPanel (grid, cfg)
47743 this.beginUpdate();
47747 Roo.each(xitems, function(i) {
47748 region = nb && i.region ? i.region : false;
47750 var add = ret.addxtype(i);
47753 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
47754 if (!i.background) {
47755 abn[region] = nb[region] ;
47762 // make the last non-background panel active..
47763 //if (nb) { Roo.log(abn); }
47766 for(var r in abn) {
47767 region = this.getRegion(r);
47769 // tried using nb[r], but it does not work..
47771 region.showPanel(abn[r]);
47782 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
47783 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
47784 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
47785 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
47788 var CP = Roo.ContentPanel;
47790 var layout = Roo.BorderLayout.create({
47794 panels: [new CP("north", "North")]
47803 panels: [new CP("west", {title: "West"})]
47812 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
47821 panels: [new CP("south", {title: "South", closable: true})]
47828 preferredTabWidth: 150,
47830 new CP("center1", {title: "Close Me", closable: true}),
47831 new CP("center2", {title: "Center Panel", closable: false})
47836 layout.getRegion("center").showPanel("center1");
47841 Roo.BorderLayout.create = function(config, targetEl){
47842 var layout = new Roo.BorderLayout(targetEl || document.body, config);
47843 layout.beginUpdate();
47844 var regions = Roo.BorderLayout.RegionFactory.validRegions;
47845 for(var j = 0, jlen = regions.length; j < jlen; j++){
47846 var lr = regions[j];
47847 if(layout.regions[lr] && config[lr].panels){
47848 var r = layout.regions[lr];
47849 var ps = config[lr].panels;
47850 layout.addTypedPanels(r, ps);
47853 layout.endUpdate();
47858 Roo.BorderLayout.RegionFactory = {
47860 validRegions : ["north","south","east","west","center"],
47863 create : function(target, mgr, config){
47864 target = target.toLowerCase();
47865 if(config.lightweight || config.basic){
47866 return new Roo.BasicLayoutRegion(mgr, config, target);
47870 return new Roo.NorthLayoutRegion(mgr, config);
47872 return new Roo.SouthLayoutRegion(mgr, config);
47874 return new Roo.EastLayoutRegion(mgr, config);
47876 return new Roo.WestLayoutRegion(mgr, config);
47878 return new Roo.CenterLayoutRegion(mgr, config);
47880 throw 'Layout region "'+target+'" not supported.';
47884 * Ext JS Library 1.1.1
47885 * Copyright(c) 2006-2007, Ext JS, LLC.
47887 * Originally Released Under LGPL - original licence link has changed is not relivant.
47890 * <script type="text/javascript">
47894 * @class Roo.BasicLayoutRegion
47895 * @extends Roo.util.Observable
47896 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
47897 * and does not have a titlebar, tabs or any other features. All it does is size and position
47898 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
47900 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
47902 this.position = pos;
47905 * @scope Roo.BasicLayoutRegion
47909 * @event beforeremove
47910 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
47911 * @param {Roo.LayoutRegion} this
47912 * @param {Roo.ContentPanel} panel The panel
47913 * @param {Object} e The cancel event object
47915 "beforeremove" : true,
47917 * @event invalidated
47918 * Fires when the layout for this region is changed.
47919 * @param {Roo.LayoutRegion} this
47921 "invalidated" : true,
47923 * @event visibilitychange
47924 * Fires when this region is shown or hidden
47925 * @param {Roo.LayoutRegion} this
47926 * @param {Boolean} visibility true or false
47928 "visibilitychange" : true,
47930 * @event paneladded
47931 * Fires when a panel is added.
47932 * @param {Roo.LayoutRegion} this
47933 * @param {Roo.ContentPanel} panel The panel
47935 "paneladded" : true,
47937 * @event panelremoved
47938 * Fires when a panel is removed.
47939 * @param {Roo.LayoutRegion} this
47940 * @param {Roo.ContentPanel} panel The panel
47942 "panelremoved" : true,
47945 * Fires when this region is collapsed.
47946 * @param {Roo.LayoutRegion} this
47948 "collapsed" : true,
47951 * Fires when this region is expanded.
47952 * @param {Roo.LayoutRegion} this
47957 * Fires when this region is slid into view.
47958 * @param {Roo.LayoutRegion} this
47960 "slideshow" : true,
47963 * Fires when this region slides out of view.
47964 * @param {Roo.LayoutRegion} this
47966 "slidehide" : true,
47968 * @event panelactivated
47969 * Fires when a panel is activated.
47970 * @param {Roo.LayoutRegion} this
47971 * @param {Roo.ContentPanel} panel The activated panel
47973 "panelactivated" : true,
47976 * Fires when the user resizes this region.
47977 * @param {Roo.LayoutRegion} this
47978 * @param {Number} newSize The new size (width for east/west, height for north/south)
47982 /** A collection of panels in this region. @type Roo.util.MixedCollection */
47983 this.panels = new Roo.util.MixedCollection();
47984 this.panels.getKey = this.getPanelId.createDelegate(this);
47986 this.activePanel = null;
47987 // ensure listeners are added...
47989 if (config.listeners || config.events) {
47990 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
47991 listeners : config.listeners || {},
47992 events : config.events || {}
47996 if(skipConfig !== true){
47997 this.applyConfig(config);
48001 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
48002 getPanelId : function(p){
48006 applyConfig : function(config){
48007 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48008 this.config = config;
48013 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
48014 * the width, for horizontal (north, south) the height.
48015 * @param {Number} newSize The new width or height
48017 resizeTo : function(newSize){
48018 var el = this.el ? this.el :
48019 (this.activePanel ? this.activePanel.getEl() : null);
48021 switch(this.position){
48024 el.setWidth(newSize);
48025 this.fireEvent("resized", this, newSize);
48029 el.setHeight(newSize);
48030 this.fireEvent("resized", this, newSize);
48036 getBox : function(){
48037 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
48040 getMargins : function(){
48041 return this.margins;
48044 updateBox : function(box){
48046 var el = this.activePanel.getEl();
48047 el.dom.style.left = box.x + "px";
48048 el.dom.style.top = box.y + "px";
48049 this.activePanel.setSize(box.width, box.height);
48053 * Returns the container element for this region.
48054 * @return {Roo.Element}
48056 getEl : function(){
48057 return this.activePanel;
48061 * Returns true if this region is currently visible.
48062 * @return {Boolean}
48064 isVisible : function(){
48065 return this.activePanel ? true : false;
48068 setActivePanel : function(panel){
48069 panel = this.getPanel(panel);
48070 if(this.activePanel && this.activePanel != panel){
48071 this.activePanel.setActiveState(false);
48072 this.activePanel.getEl().setLeftTop(-10000,-10000);
48074 this.activePanel = panel;
48075 panel.setActiveState(true);
48077 panel.setSize(this.box.width, this.box.height);
48079 this.fireEvent("panelactivated", this, panel);
48080 this.fireEvent("invalidated");
48084 * Show the specified panel.
48085 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
48086 * @return {Roo.ContentPanel} The shown panel or null
48088 showPanel : function(panel){
48089 if(panel = this.getPanel(panel)){
48090 this.setActivePanel(panel);
48096 * Get the active panel for this region.
48097 * @return {Roo.ContentPanel} The active panel or null
48099 getActivePanel : function(){
48100 return this.activePanel;
48104 * Add the passed ContentPanel(s)
48105 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48106 * @return {Roo.ContentPanel} The panel added (if only one was added)
48108 add : function(panel){
48109 if(arguments.length > 1){
48110 for(var i = 0, len = arguments.length; i < len; i++) {
48111 this.add(arguments[i]);
48115 if(this.hasPanel(panel)){
48116 this.showPanel(panel);
48119 var el = panel.getEl();
48120 if(el.dom.parentNode != this.mgr.el.dom){
48121 this.mgr.el.dom.appendChild(el.dom);
48123 if(panel.setRegion){
48124 panel.setRegion(this);
48126 this.panels.add(panel);
48127 el.setStyle("position", "absolute");
48128 if(!panel.background){
48129 this.setActivePanel(panel);
48130 if(this.config.initialSize && this.panels.getCount()==1){
48131 this.resizeTo(this.config.initialSize);
48134 this.fireEvent("paneladded", this, panel);
48139 * Returns true if the panel is in this region.
48140 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48141 * @return {Boolean}
48143 hasPanel : function(panel){
48144 if(typeof panel == "object"){ // must be panel obj
48145 panel = panel.getId();
48147 return this.getPanel(panel) ? true : false;
48151 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48152 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48153 * @param {Boolean} preservePanel Overrides the config preservePanel option
48154 * @return {Roo.ContentPanel} The panel that was removed
48156 remove : function(panel, preservePanel){
48157 panel = this.getPanel(panel);
48162 this.fireEvent("beforeremove", this, panel, e);
48163 if(e.cancel === true){
48166 var panelId = panel.getId();
48167 this.panels.removeKey(panelId);
48172 * Returns the panel specified or null if it's not in this region.
48173 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48174 * @return {Roo.ContentPanel}
48176 getPanel : function(id){
48177 if(typeof id == "object"){ // must be panel obj
48180 return this.panels.get(id);
48184 * Returns this regions position (north/south/east/west/center).
48187 getPosition: function(){
48188 return this.position;
48192 * Ext JS Library 1.1.1
48193 * Copyright(c) 2006-2007, Ext JS, LLC.
48195 * Originally Released Under LGPL - original licence link has changed is not relivant.
48198 * <script type="text/javascript">
48202 * @class Roo.LayoutRegion
48203 * @extends Roo.BasicLayoutRegion
48204 * This class represents a region in a layout manager.
48205 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
48206 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
48207 * @cfg {Boolean} floatable False to disable floating (defaults to true)
48208 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
48209 * @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})
48210 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
48211 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
48212 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
48213 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
48214 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
48215 * @cfg {String} title The title for the region (overrides panel titles)
48216 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
48217 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
48218 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
48219 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
48220 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
48221 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
48222 * the space available, similar to FireFox 1.5 tabs (defaults to false)
48223 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
48224 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
48225 * @cfg {Boolean} showPin True to show a pin button
48226 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
48227 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
48228 * @cfg {Boolean} disableTabTips True to disable tab tooltips
48229 * @cfg {Number} width For East/West panels
48230 * @cfg {Number} height For North/South panels
48231 * @cfg {Boolean} split To show the splitter
48232 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
48234 Roo.LayoutRegion = function(mgr, config, pos){
48235 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
48236 var dh = Roo.DomHelper;
48237 /** This region's container element
48238 * @type Roo.Element */
48239 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
48240 /** This region's title element
48241 * @type Roo.Element */
48243 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
48244 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
48245 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
48247 this.titleEl.enableDisplayMode();
48248 /** This region's title text element
48249 * @type HTMLElement */
48250 this.titleTextEl = this.titleEl.dom.firstChild;
48251 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
48252 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
48253 this.closeBtn.enableDisplayMode();
48254 this.closeBtn.on("click", this.closeClicked, this);
48255 this.closeBtn.hide();
48257 this.createBody(config);
48258 this.visible = true;
48259 this.collapsed = false;
48261 if(config.hideWhenEmpty){
48263 this.on("paneladded", this.validateVisibility, this);
48264 this.on("panelremoved", this.validateVisibility, this);
48266 this.applyConfig(config);
48269 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
48271 createBody : function(){
48272 /** This region's body element
48273 * @type Roo.Element */
48274 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
48277 applyConfig : function(c){
48278 if(c.collapsible && this.position != "center" && !this.collapsedEl){
48279 var dh = Roo.DomHelper;
48280 if(c.titlebar !== false){
48281 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
48282 this.collapseBtn.on("click", this.collapse, this);
48283 this.collapseBtn.enableDisplayMode();
48285 if(c.showPin === true || this.showPin){
48286 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
48287 this.stickBtn.enableDisplayMode();
48288 this.stickBtn.on("click", this.expand, this);
48289 this.stickBtn.hide();
48292 /** This region's collapsed element
48293 * @type Roo.Element */
48294 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
48295 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
48297 if(c.floatable !== false){
48298 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
48299 this.collapsedEl.on("click", this.collapseClick, this);
48302 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
48303 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
48304 id: "message", unselectable: "on", style:{"float":"left"}});
48305 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
48307 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
48308 this.expandBtn.on("click", this.expand, this);
48310 if(this.collapseBtn){
48311 this.collapseBtn.setVisible(c.collapsible == true);
48313 this.cmargins = c.cmargins || this.cmargins ||
48314 (this.position == "west" || this.position == "east" ?
48315 {top: 0, left: 2, right:2, bottom: 0} :
48316 {top: 2, left: 0, right:0, bottom: 2});
48317 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48318 this.bottomTabs = c.tabPosition != "top";
48319 this.autoScroll = c.autoScroll || false;
48320 if(this.autoScroll){
48321 this.bodyEl.setStyle("overflow", "auto");
48323 this.bodyEl.setStyle("overflow", "hidden");
48325 //if(c.titlebar !== false){
48326 if((!c.titlebar && !c.title) || c.titlebar === false){
48327 this.titleEl.hide();
48329 this.titleEl.show();
48331 this.titleTextEl.innerHTML = c.title;
48335 this.duration = c.duration || .30;
48336 this.slideDuration = c.slideDuration || .45;
48339 this.collapse(true);
48346 * Returns true if this region is currently visible.
48347 * @return {Boolean}
48349 isVisible : function(){
48350 return this.visible;
48354 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
48355 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
48357 setCollapsedTitle : function(title){
48358 title = title || " ";
48359 if(this.collapsedTitleTextEl){
48360 this.collapsedTitleTextEl.innerHTML = title;
48364 getBox : function(){
48366 if(!this.collapsed){
48367 b = this.el.getBox(false, true);
48369 b = this.collapsedEl.getBox(false, true);
48374 getMargins : function(){
48375 return this.collapsed ? this.cmargins : this.margins;
48378 highlight : function(){
48379 this.el.addClass("x-layout-panel-dragover");
48382 unhighlight : function(){
48383 this.el.removeClass("x-layout-panel-dragover");
48386 updateBox : function(box){
48388 if(!this.collapsed){
48389 this.el.dom.style.left = box.x + "px";
48390 this.el.dom.style.top = box.y + "px";
48391 this.updateBody(box.width, box.height);
48393 this.collapsedEl.dom.style.left = box.x + "px";
48394 this.collapsedEl.dom.style.top = box.y + "px";
48395 this.collapsedEl.setSize(box.width, box.height);
48398 this.tabs.autoSizeTabs();
48402 updateBody : function(w, h){
48404 this.el.setWidth(w);
48405 w -= this.el.getBorderWidth("rl");
48406 if(this.config.adjustments){
48407 w += this.config.adjustments[0];
48411 this.el.setHeight(h);
48412 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
48413 h -= this.el.getBorderWidth("tb");
48414 if(this.config.adjustments){
48415 h += this.config.adjustments[1];
48417 this.bodyEl.setHeight(h);
48419 h = this.tabs.syncHeight(h);
48422 if(this.panelSize){
48423 w = w !== null ? w : this.panelSize.width;
48424 h = h !== null ? h : this.panelSize.height;
48426 if(this.activePanel){
48427 var el = this.activePanel.getEl();
48428 w = w !== null ? w : el.getWidth();
48429 h = h !== null ? h : el.getHeight();
48430 this.panelSize = {width: w, height: h};
48431 this.activePanel.setSize(w, h);
48433 if(Roo.isIE && this.tabs){
48434 this.tabs.el.repaint();
48439 * Returns the container element for this region.
48440 * @return {Roo.Element}
48442 getEl : function(){
48447 * Hides this region.
48450 if(!this.collapsed){
48451 this.el.dom.style.left = "-2000px";
48454 this.collapsedEl.dom.style.left = "-2000px";
48455 this.collapsedEl.hide();
48457 this.visible = false;
48458 this.fireEvent("visibilitychange", this, false);
48462 * Shows this region if it was previously hidden.
48465 if(!this.collapsed){
48468 this.collapsedEl.show();
48470 this.visible = true;
48471 this.fireEvent("visibilitychange", this, true);
48474 closeClicked : function(){
48475 if(this.activePanel){
48476 this.remove(this.activePanel);
48480 collapseClick : function(e){
48482 e.stopPropagation();
48485 e.stopPropagation();
48491 * Collapses this region.
48492 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
48494 collapse : function(skipAnim){
48495 if(this.collapsed) return;
48496 this.collapsed = true;
48498 this.split.el.hide();
48500 if(this.config.animate && skipAnim !== true){
48501 this.fireEvent("invalidated", this);
48502 this.animateCollapse();
48504 this.el.setLocation(-20000,-20000);
48506 this.collapsedEl.show();
48507 this.fireEvent("collapsed", this);
48508 this.fireEvent("invalidated", this);
48512 animateCollapse : function(){
48517 * Expands this region if it was previously collapsed.
48518 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
48519 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
48521 expand : function(e, skipAnim){
48522 if(e) e.stopPropagation();
48523 if(!this.collapsed || this.el.hasActiveFx()) return;
48525 this.afterSlideIn();
48528 this.collapsed = false;
48529 if(this.config.animate && skipAnim !== true){
48530 this.animateExpand();
48534 this.split.el.show();
48536 this.collapsedEl.setLocation(-2000,-2000);
48537 this.collapsedEl.hide();
48538 this.fireEvent("invalidated", this);
48539 this.fireEvent("expanded", this);
48543 animateExpand : function(){
48547 initTabs : function()
48549 this.bodyEl.setStyle("overflow", "hidden");
48550 var ts = new Roo.TabPanel(
48553 tabPosition: this.bottomTabs ? 'bottom' : 'top',
48554 disableTooltips: this.config.disableTabTips,
48555 toolbar : this.config.toolbar
48558 if(this.config.hideTabs){
48559 ts.stripWrap.setDisplayed(false);
48562 ts.resizeTabs = this.config.resizeTabs === true;
48563 ts.minTabWidth = this.config.minTabWidth || 40;
48564 ts.maxTabWidth = this.config.maxTabWidth || 250;
48565 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
48566 ts.monitorResize = false;
48567 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
48568 ts.bodyEl.addClass('x-layout-tabs-body');
48569 this.panels.each(this.initPanelAsTab, this);
48572 initPanelAsTab : function(panel){
48573 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
48574 this.config.closeOnTab && panel.isClosable());
48575 if(panel.tabTip !== undefined){
48576 ti.setTooltip(panel.tabTip);
48578 ti.on("activate", function(){
48579 this.setActivePanel(panel);
48581 if(this.config.closeOnTab){
48582 ti.on("beforeclose", function(t, e){
48584 this.remove(panel);
48590 updatePanelTitle : function(panel, title){
48591 if(this.activePanel == panel){
48592 this.updateTitle(title);
48595 var ti = this.tabs.getTab(panel.getEl().id);
48597 if(panel.tabTip !== undefined){
48598 ti.setTooltip(panel.tabTip);
48603 updateTitle : function(title){
48604 if(this.titleTextEl && !this.config.title){
48605 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
48609 setActivePanel : function(panel){
48610 panel = this.getPanel(panel);
48611 if(this.activePanel && this.activePanel != panel){
48612 this.activePanel.setActiveState(false);
48614 this.activePanel = panel;
48615 panel.setActiveState(true);
48616 if(this.panelSize){
48617 panel.setSize(this.panelSize.width, this.panelSize.height);
48620 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
48622 this.updateTitle(panel.getTitle());
48624 this.fireEvent("invalidated", this);
48626 this.fireEvent("panelactivated", this, panel);
48630 * Shows the specified panel.
48631 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
48632 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
48634 showPanel : function(panel){
48635 if(panel = this.getPanel(panel)){
48637 var tab = this.tabs.getTab(panel.getEl().id);
48638 if(tab.isHidden()){
48639 this.tabs.unhideTab(tab.id);
48643 this.setActivePanel(panel);
48650 * Get the active panel for this region.
48651 * @return {Roo.ContentPanel} The active panel or null
48653 getActivePanel : function(){
48654 return this.activePanel;
48657 validateVisibility : function(){
48658 if(this.panels.getCount() < 1){
48659 this.updateTitle(" ");
48660 this.closeBtn.hide();
48663 if(!this.isVisible()){
48670 * Adds the passed ContentPanel(s) to this region.
48671 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48672 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
48674 add : function(panel){
48675 if(arguments.length > 1){
48676 for(var i = 0, len = arguments.length; i < len; i++) {
48677 this.add(arguments[i]);
48681 if(this.hasPanel(panel)){
48682 this.showPanel(panel);
48685 panel.setRegion(this);
48686 this.panels.add(panel);
48687 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
48688 this.bodyEl.dom.appendChild(panel.getEl().dom);
48689 if(panel.background !== true){
48690 this.setActivePanel(panel);
48692 this.fireEvent("paneladded", this, panel);
48698 this.initPanelAsTab(panel);
48700 if(panel.background !== true){
48701 this.tabs.activate(panel.getEl().id);
48703 this.fireEvent("paneladded", this, panel);
48708 * Hides the tab for the specified panel.
48709 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48711 hidePanel : function(panel){
48712 if(this.tabs && (panel = this.getPanel(panel))){
48713 this.tabs.hideTab(panel.getEl().id);
48718 * Unhides the tab for a previously hidden panel.
48719 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48721 unhidePanel : function(panel){
48722 if(this.tabs && (panel = this.getPanel(panel))){
48723 this.tabs.unhideTab(panel.getEl().id);
48727 clearPanels : function(){
48728 while(this.panels.getCount() > 0){
48729 this.remove(this.panels.first());
48734 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48735 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48736 * @param {Boolean} preservePanel Overrides the config preservePanel option
48737 * @return {Roo.ContentPanel} The panel that was removed
48739 remove : function(panel, preservePanel){
48740 panel = this.getPanel(panel);
48745 this.fireEvent("beforeremove", this, panel, e);
48746 if(e.cancel === true){
48749 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
48750 var panelId = panel.getId();
48751 this.panels.removeKey(panelId);
48753 document.body.appendChild(panel.getEl().dom);
48756 this.tabs.removeTab(panel.getEl().id);
48757 }else if (!preservePanel){
48758 this.bodyEl.dom.removeChild(panel.getEl().dom);
48760 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
48761 var p = this.panels.first();
48762 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
48763 tempEl.appendChild(p.getEl().dom);
48764 this.bodyEl.update("");
48765 this.bodyEl.dom.appendChild(p.getEl().dom);
48767 this.updateTitle(p.getTitle());
48769 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
48770 this.setActivePanel(p);
48772 panel.setRegion(null);
48773 if(this.activePanel == panel){
48774 this.activePanel = null;
48776 if(this.config.autoDestroy !== false && preservePanel !== true){
48777 try{panel.destroy();}catch(e){}
48779 this.fireEvent("panelremoved", this, panel);
48784 * Returns the TabPanel component used by this region
48785 * @return {Roo.TabPanel}
48787 getTabs : function(){
48791 createTool : function(parentEl, className){
48792 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
48793 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
48794 btn.addClassOnOver("x-layout-tools-button-over");
48799 * Ext JS Library 1.1.1
48800 * Copyright(c) 2006-2007, Ext JS, LLC.
48802 * Originally Released Under LGPL - original licence link has changed is not relivant.
48805 * <script type="text/javascript">
48811 * @class Roo.SplitLayoutRegion
48812 * @extends Roo.LayoutRegion
48813 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
48815 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
48816 this.cursor = cursor;
48817 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
48820 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
48821 splitTip : "Drag to resize.",
48822 collapsibleSplitTip : "Drag to resize. Double click to hide.",
48823 useSplitTips : false,
48825 applyConfig : function(config){
48826 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
48829 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
48830 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
48831 /** The SplitBar for this region
48832 * @type Roo.SplitBar */
48833 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
48834 this.split.on("moved", this.onSplitMove, this);
48835 this.split.useShim = config.useShim === true;
48836 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
48837 if(this.useSplitTips){
48838 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
48840 if(config.collapsible){
48841 this.split.el.on("dblclick", this.collapse, this);
48844 if(typeof config.minSize != "undefined"){
48845 this.split.minSize = config.minSize;
48847 if(typeof config.maxSize != "undefined"){
48848 this.split.maxSize = config.maxSize;
48850 if(config.hideWhenEmpty || config.hidden || config.collapsed){
48851 this.hideSplitter();
48856 getHMaxSize : function(){
48857 var cmax = this.config.maxSize || 10000;
48858 var center = this.mgr.getRegion("center");
48859 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
48862 getVMaxSize : function(){
48863 var cmax = this.config.maxSize || 10000;
48864 var center = this.mgr.getRegion("center");
48865 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
48868 onSplitMove : function(split, newSize){
48869 this.fireEvent("resized", this, newSize);
48873 * Returns the {@link Roo.SplitBar} for this region.
48874 * @return {Roo.SplitBar}
48876 getSplitBar : function(){
48881 this.hideSplitter();
48882 Roo.SplitLayoutRegion.superclass.hide.call(this);
48885 hideSplitter : function(){
48887 this.split.el.setLocation(-2000,-2000);
48888 this.split.el.hide();
48894 this.split.el.show();
48896 Roo.SplitLayoutRegion.superclass.show.call(this);
48899 beforeSlide: function(){
48900 if(Roo.isGecko){// firefox overflow auto bug workaround
48901 this.bodyEl.clip();
48902 if(this.tabs) this.tabs.bodyEl.clip();
48903 if(this.activePanel){
48904 this.activePanel.getEl().clip();
48906 if(this.activePanel.beforeSlide){
48907 this.activePanel.beforeSlide();
48913 afterSlide : function(){
48914 if(Roo.isGecko){// firefox overflow auto bug workaround
48915 this.bodyEl.unclip();
48916 if(this.tabs) this.tabs.bodyEl.unclip();
48917 if(this.activePanel){
48918 this.activePanel.getEl().unclip();
48919 if(this.activePanel.afterSlide){
48920 this.activePanel.afterSlide();
48926 initAutoHide : function(){
48927 if(this.autoHide !== false){
48928 if(!this.autoHideHd){
48929 var st = new Roo.util.DelayedTask(this.slideIn, this);
48930 this.autoHideHd = {
48931 "mouseout": function(e){
48932 if(!e.within(this.el, true)){
48936 "mouseover" : function(e){
48942 this.el.on(this.autoHideHd);
48946 clearAutoHide : function(){
48947 if(this.autoHide !== false){
48948 this.el.un("mouseout", this.autoHideHd.mouseout);
48949 this.el.un("mouseover", this.autoHideHd.mouseover);
48953 clearMonitor : function(){
48954 Roo.get(document).un("click", this.slideInIf, this);
48957 // these names are backwards but not changed for compat
48958 slideOut : function(){
48959 if(this.isSlid || this.el.hasActiveFx()){
48962 this.isSlid = true;
48963 if(this.collapseBtn){
48964 this.collapseBtn.hide();
48966 this.closeBtnState = this.closeBtn.getStyle('display');
48967 this.closeBtn.hide();
48969 this.stickBtn.show();
48972 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
48973 this.beforeSlide();
48974 this.el.setStyle("z-index", 10001);
48975 this.el.slideIn(this.getSlideAnchor(), {
48976 callback: function(){
48978 this.initAutoHide();
48979 Roo.get(document).on("click", this.slideInIf, this);
48980 this.fireEvent("slideshow", this);
48987 afterSlideIn : function(){
48988 this.clearAutoHide();
48989 this.isSlid = false;
48990 this.clearMonitor();
48991 this.el.setStyle("z-index", "");
48992 if(this.collapseBtn){
48993 this.collapseBtn.show();
48995 this.closeBtn.setStyle('display', this.closeBtnState);
48997 this.stickBtn.hide();
48999 this.fireEvent("slidehide", this);
49002 slideIn : function(cb){
49003 if(!this.isSlid || this.el.hasActiveFx()){
49007 this.isSlid = false;
49008 this.beforeSlide();
49009 this.el.slideOut(this.getSlideAnchor(), {
49010 callback: function(){
49011 this.el.setLeftTop(-10000, -10000);
49013 this.afterSlideIn();
49021 slideInIf : function(e){
49022 if(!e.within(this.el)){
49027 animateCollapse : function(){
49028 this.beforeSlide();
49029 this.el.setStyle("z-index", 20000);
49030 var anchor = this.getSlideAnchor();
49031 this.el.slideOut(anchor, {
49032 callback : function(){
49033 this.el.setStyle("z-index", "");
49034 this.collapsedEl.slideIn(anchor, {duration:.3});
49036 this.el.setLocation(-10000,-10000);
49038 this.fireEvent("collapsed", this);
49045 animateExpand : function(){
49046 this.beforeSlide();
49047 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
49048 this.el.setStyle("z-index", 20000);
49049 this.collapsedEl.hide({
49052 this.el.slideIn(this.getSlideAnchor(), {
49053 callback : function(){
49054 this.el.setStyle("z-index", "");
49057 this.split.el.show();
49059 this.fireEvent("invalidated", this);
49060 this.fireEvent("expanded", this);
49088 getAnchor : function(){
49089 return this.anchors[this.position];
49092 getCollapseAnchor : function(){
49093 return this.canchors[this.position];
49096 getSlideAnchor : function(){
49097 return this.sanchors[this.position];
49100 getAlignAdj : function(){
49101 var cm = this.cmargins;
49102 switch(this.position){
49118 getExpandAdj : function(){
49119 var c = this.collapsedEl, cm = this.cmargins;
49120 switch(this.position){
49122 return [-(cm.right+c.getWidth()+cm.left), 0];
49125 return [cm.right+c.getWidth()+cm.left, 0];
49128 return [0, -(cm.top+cm.bottom+c.getHeight())];
49131 return [0, cm.top+cm.bottom+c.getHeight()];
49137 * Ext JS Library 1.1.1
49138 * Copyright(c) 2006-2007, Ext JS, LLC.
49140 * Originally Released Under LGPL - original licence link has changed is not relivant.
49143 * <script type="text/javascript">
49146 * These classes are private internal classes
49148 Roo.CenterLayoutRegion = function(mgr, config){
49149 Roo.LayoutRegion.call(this, mgr, config, "center");
49150 this.visible = true;
49151 this.minWidth = config.minWidth || 20;
49152 this.minHeight = config.minHeight || 20;
49155 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
49157 // center panel can't be hidden
49161 // center panel can't be hidden
49164 getMinWidth: function(){
49165 return this.minWidth;
49168 getMinHeight: function(){
49169 return this.minHeight;
49174 Roo.NorthLayoutRegion = function(mgr, config){
49175 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
49177 this.split.placement = Roo.SplitBar.TOP;
49178 this.split.orientation = Roo.SplitBar.VERTICAL;
49179 this.split.el.addClass("x-layout-split-v");
49181 var size = config.initialSize || config.height;
49182 if(typeof size != "undefined"){
49183 this.el.setHeight(size);
49186 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
49187 orientation: Roo.SplitBar.VERTICAL,
49188 getBox : function(){
49189 if(this.collapsed){
49190 return this.collapsedEl.getBox();
49192 var box = this.el.getBox();
49194 box.height += this.split.el.getHeight();
49199 updateBox : function(box){
49200 if(this.split && !this.collapsed){
49201 box.height -= this.split.el.getHeight();
49202 this.split.el.setLeft(box.x);
49203 this.split.el.setTop(box.y+box.height);
49204 this.split.el.setWidth(box.width);
49206 if(this.collapsed){
49207 this.updateBody(box.width, null);
49209 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49213 Roo.SouthLayoutRegion = function(mgr, config){
49214 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
49216 this.split.placement = Roo.SplitBar.BOTTOM;
49217 this.split.orientation = Roo.SplitBar.VERTICAL;
49218 this.split.el.addClass("x-layout-split-v");
49220 var size = config.initialSize || config.height;
49221 if(typeof size != "undefined"){
49222 this.el.setHeight(size);
49225 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
49226 orientation: Roo.SplitBar.VERTICAL,
49227 getBox : function(){
49228 if(this.collapsed){
49229 return this.collapsedEl.getBox();
49231 var box = this.el.getBox();
49233 var sh = this.split.el.getHeight();
49240 updateBox : function(box){
49241 if(this.split && !this.collapsed){
49242 var sh = this.split.el.getHeight();
49245 this.split.el.setLeft(box.x);
49246 this.split.el.setTop(box.y-sh);
49247 this.split.el.setWidth(box.width);
49249 if(this.collapsed){
49250 this.updateBody(box.width, null);
49252 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49256 Roo.EastLayoutRegion = function(mgr, config){
49257 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
49259 this.split.placement = Roo.SplitBar.RIGHT;
49260 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49261 this.split.el.addClass("x-layout-split-h");
49263 var size = config.initialSize || config.width;
49264 if(typeof size != "undefined"){
49265 this.el.setWidth(size);
49268 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
49269 orientation: Roo.SplitBar.HORIZONTAL,
49270 getBox : function(){
49271 if(this.collapsed){
49272 return this.collapsedEl.getBox();
49274 var box = this.el.getBox();
49276 var sw = this.split.el.getWidth();
49283 updateBox : function(box){
49284 if(this.split && !this.collapsed){
49285 var sw = this.split.el.getWidth();
49287 this.split.el.setLeft(box.x);
49288 this.split.el.setTop(box.y);
49289 this.split.el.setHeight(box.height);
49292 if(this.collapsed){
49293 this.updateBody(null, box.height);
49295 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49299 Roo.WestLayoutRegion = function(mgr, config){
49300 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
49302 this.split.placement = Roo.SplitBar.LEFT;
49303 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49304 this.split.el.addClass("x-layout-split-h");
49306 var size = config.initialSize || config.width;
49307 if(typeof size != "undefined"){
49308 this.el.setWidth(size);
49311 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
49312 orientation: Roo.SplitBar.HORIZONTAL,
49313 getBox : function(){
49314 if(this.collapsed){
49315 return this.collapsedEl.getBox();
49317 var box = this.el.getBox();
49319 box.width += this.split.el.getWidth();
49324 updateBox : function(box){
49325 if(this.split && !this.collapsed){
49326 var sw = this.split.el.getWidth();
49328 this.split.el.setLeft(box.x+box.width);
49329 this.split.el.setTop(box.y);
49330 this.split.el.setHeight(box.height);
49332 if(this.collapsed){
49333 this.updateBody(null, box.height);
49335 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49340 * Ext JS Library 1.1.1
49341 * Copyright(c) 2006-2007, Ext JS, LLC.
49343 * Originally Released Under LGPL - original licence link has changed is not relivant.
49346 * <script type="text/javascript">
49351 * Private internal class for reading and applying state
49353 Roo.LayoutStateManager = function(layout){
49354 // default empty state
49363 Roo.LayoutStateManager.prototype = {
49364 init : function(layout, provider){
49365 this.provider = provider;
49366 var state = provider.get(layout.id+"-layout-state");
49368 var wasUpdating = layout.isUpdating();
49370 layout.beginUpdate();
49372 for(var key in state){
49373 if(typeof state[key] != "function"){
49374 var rstate = state[key];
49375 var r = layout.getRegion(key);
49378 r.resizeTo(rstate.size);
49380 if(rstate.collapsed == true){
49383 r.expand(null, true);
49389 layout.endUpdate();
49391 this.state = state;
49393 this.layout = layout;
49394 layout.on("regionresized", this.onRegionResized, this);
49395 layout.on("regioncollapsed", this.onRegionCollapsed, this);
49396 layout.on("regionexpanded", this.onRegionExpanded, this);
49399 storeState : function(){
49400 this.provider.set(this.layout.id+"-layout-state", this.state);
49403 onRegionResized : function(region, newSize){
49404 this.state[region.getPosition()].size = newSize;
49408 onRegionCollapsed : function(region){
49409 this.state[region.getPosition()].collapsed = true;
49413 onRegionExpanded : function(region){
49414 this.state[region.getPosition()].collapsed = false;
49419 * Ext JS Library 1.1.1
49420 * Copyright(c) 2006-2007, Ext JS, LLC.
49422 * Originally Released Under LGPL - original licence link has changed is not relivant.
49425 * <script type="text/javascript">
49428 * @class Roo.ContentPanel
49429 * @extends Roo.util.Observable
49430 * A basic ContentPanel element.
49431 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
49432 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
49433 * @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
49434 * @cfg {Boolean} closable True if the panel can be closed/removed
49435 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
49436 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
49437 * @cfg {Toolbar} toolbar A toolbar for this panel
49438 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
49439 * @cfg {String} title The title for this panel
49440 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
49441 * @cfg {String} url Calls {@link #setUrl} with this value
49442 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
49443 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
49444 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
49445 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
49448 * Create a new ContentPanel.
49449 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
49450 * @param {String/Object} config A string to set only the title or a config object
49451 * @param {String} content (optional) Set the HTML content for this panel
49452 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
49454 Roo.ContentPanel = function(el, config, content){
49458 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
49462 if (config && config.parentLayout) {
49463 el = config.parentLayout.el.createChild();
49466 if(el.autoCreate){ // xtype is available if this is called from factory
49470 this.el = Roo.get(el);
49471 if(!this.el && config && config.autoCreate){
49472 if(typeof config.autoCreate == "object"){
49473 if(!config.autoCreate.id){
49474 config.autoCreate.id = config.id||el;
49476 this.el = Roo.DomHelper.append(document.body,
49477 config.autoCreate, true);
49479 this.el = Roo.DomHelper.append(document.body,
49480 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
49483 this.closable = false;
49484 this.loaded = false;
49485 this.active = false;
49486 if(typeof config == "string"){
49487 this.title = config;
49489 Roo.apply(this, config);
49492 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
49493 this.wrapEl = this.el.wrap();
49494 this.toolbar.container = this.el.insertSibling(false, 'before');
49495 this.toolbar = new Roo.Toolbar(this.toolbar);
49498 // xtype created footer. - not sure if will work as we normally have to render first..
49499 if (this.footer && !this.footer.el && this.footer.xtype) {
49500 if (!this.wrapEl) {
49501 this.wrapEl = this.el.wrap();
49504 this.footer.container = this.wrapEl.createChild();
49506 this.footer = Roo.factory(this.footer, Roo);
49511 this.resizeEl = Roo.get(this.resizeEl, true);
49513 this.resizeEl = this.el;
49515 // handle view.xtype
49523 * Fires when this panel is activated.
49524 * @param {Roo.ContentPanel} this
49528 * @event deactivate
49529 * Fires when this panel is activated.
49530 * @param {Roo.ContentPanel} this
49532 "deactivate" : true,
49536 * Fires when this panel is resized if fitToFrame is true.
49537 * @param {Roo.ContentPanel} this
49538 * @param {Number} width The width after any component adjustments
49539 * @param {Number} height The height after any component adjustments
49545 * Fires when this tab is created
49546 * @param {Roo.ContentPanel} this
49557 if(this.autoScroll){
49558 this.resizeEl.setStyle("overflow", "auto");
49560 // fix randome scrolling
49561 this.el.on('scroll', function() {
49562 Roo.log('fix random scolling');
49563 this.scrollTo('top',0);
49566 content = content || this.content;
49568 this.setContent(content);
49570 if(config && config.url){
49571 this.setUrl(this.url, this.params, this.loadOnce);
49576 Roo.ContentPanel.superclass.constructor.call(this);
49578 if (this.view && typeof(this.view.xtype) != 'undefined') {
49579 this.view.el = this.el.appendChild(document.createElement("div"));
49580 this.view = Roo.factory(this.view);
49581 this.view.render && this.view.render(false, '');
49585 this.fireEvent('render', this);
49588 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
49590 setRegion : function(region){
49591 this.region = region;
49593 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
49595 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
49600 * Returns the toolbar for this Panel if one was configured.
49601 * @return {Roo.Toolbar}
49603 getToolbar : function(){
49604 return this.toolbar;
49607 setActiveState : function(active){
49608 this.active = active;
49610 this.fireEvent("deactivate", this);
49612 this.fireEvent("activate", this);
49616 * Updates this panel's element
49617 * @param {String} content The new content
49618 * @param {Boolean} loadScripts (optional) true to look for and process scripts
49620 setContent : function(content, loadScripts){
49621 this.el.update(content, loadScripts);
49624 ignoreResize : function(w, h){
49625 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
49628 this.lastSize = {width: w, height: h};
49633 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
49634 * @return {Roo.UpdateManager} The UpdateManager
49636 getUpdateManager : function(){
49637 return this.el.getUpdateManager();
49640 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
49641 * @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:
49644 url: "your-url.php",
49645 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
49646 callback: yourFunction,
49647 scope: yourObject, //(optional scope)
49650 text: "Loading...",
49655 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
49656 * 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.
49657 * @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}
49658 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
49659 * @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.
49660 * @return {Roo.ContentPanel} this
49663 var um = this.el.getUpdateManager();
49664 um.update.apply(um, arguments);
49670 * 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.
49671 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
49672 * @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)
49673 * @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)
49674 * @return {Roo.UpdateManager} The UpdateManager
49676 setUrl : function(url, params, loadOnce){
49677 if(this.refreshDelegate){
49678 this.removeListener("activate", this.refreshDelegate);
49680 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
49681 this.on("activate", this.refreshDelegate);
49682 return this.el.getUpdateManager();
49685 _handleRefresh : function(url, params, loadOnce){
49686 if(!loadOnce || !this.loaded){
49687 var updater = this.el.getUpdateManager();
49688 updater.update(url, params, this._setLoaded.createDelegate(this));
49692 _setLoaded : function(){
49693 this.loaded = true;
49697 * Returns this panel's id
49700 getId : function(){
49705 * Returns this panel's element - used by regiosn to add.
49706 * @return {Roo.Element}
49708 getEl : function(){
49709 return this.wrapEl || this.el;
49712 adjustForComponents : function(width, height)
49714 //Roo.log('adjustForComponents ');
49715 if(this.resizeEl != this.el){
49716 width -= this.el.getFrameWidth('lr');
49717 height -= this.el.getFrameWidth('tb');
49720 var te = this.toolbar.getEl();
49721 height -= te.getHeight();
49722 te.setWidth(width);
49725 var te = this.footer.getEl();
49726 Roo.log("footer:" + te.getHeight());
49728 height -= te.getHeight();
49729 te.setWidth(width);
49733 if(this.adjustments){
49734 width += this.adjustments[0];
49735 height += this.adjustments[1];
49737 return {"width": width, "height": height};
49740 setSize : function(width, height){
49741 if(this.fitToFrame && !this.ignoreResize(width, height)){
49742 if(this.fitContainer && this.resizeEl != this.el){
49743 this.el.setSize(width, height);
49745 var size = this.adjustForComponents(width, height);
49746 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
49747 this.fireEvent('resize', this, size.width, size.height);
49752 * Returns this panel's title
49755 getTitle : function(){
49760 * Set this panel's title
49761 * @param {String} title
49763 setTitle : function(title){
49764 this.title = title;
49766 this.region.updatePanelTitle(this, title);
49771 * Returns true is this panel was configured to be closable
49772 * @return {Boolean}
49774 isClosable : function(){
49775 return this.closable;
49778 beforeSlide : function(){
49780 this.resizeEl.clip();
49783 afterSlide : function(){
49785 this.resizeEl.unclip();
49789 * Force a content refresh from the URL specified in the {@link #setUrl} method.
49790 * Will fail silently if the {@link #setUrl} method has not been called.
49791 * This does not activate the panel, just updates its content.
49793 refresh : function(){
49794 if(this.refreshDelegate){
49795 this.loaded = false;
49796 this.refreshDelegate();
49801 * Destroys this panel
49803 destroy : function(){
49804 this.el.removeAllListeners();
49805 var tempEl = document.createElement("span");
49806 tempEl.appendChild(this.el.dom);
49807 tempEl.innerHTML = "";
49813 * form - if the content panel contains a form - this is a reference to it.
49814 * @type {Roo.form.Form}
49818 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
49819 * This contains a reference to it.
49825 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
49835 * @param {Object} cfg Xtype definition of item to add.
49838 addxtype : function(cfg) {
49840 if (cfg.xtype.match(/^Form$/)) {
49843 //if (this.footer) {
49844 // el = this.footer.container.insertSibling(false, 'before');
49846 el = this.el.createChild();
49849 this.form = new Roo.form.Form(cfg);
49852 if ( this.form.allItems.length) this.form.render(el.dom);
49855 // should only have one of theses..
49856 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
49857 // views.. should not be just added - used named prop 'view''
49859 cfg.el = this.el.appendChild(document.createElement("div"));
49862 var ret = new Roo.factory(cfg);
49864 ret.render && ret.render(false, ''); // render blank..
49873 * @class Roo.GridPanel
49874 * @extends Roo.ContentPanel
49876 * Create a new GridPanel.
49877 * @param {Roo.grid.Grid} grid The grid for this panel
49878 * @param {String/Object} config A string to set only the panel's title, or a config object
49880 Roo.GridPanel = function(grid, config){
49883 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
49884 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
49886 this.wrapper.dom.appendChild(grid.getGridEl().dom);
49888 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
49891 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
49893 // xtype created footer. - not sure if will work as we normally have to render first..
49894 if (this.footer && !this.footer.el && this.footer.xtype) {
49896 this.footer.container = this.grid.getView().getFooterPanel(true);
49897 this.footer.dataSource = this.grid.dataSource;
49898 this.footer = Roo.factory(this.footer, Roo);
49902 grid.monitorWindowResize = false; // turn off autosizing
49903 grid.autoHeight = false;
49904 grid.autoWidth = false;
49906 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
49909 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
49910 getId : function(){
49911 return this.grid.id;
49915 * Returns the grid for this panel
49916 * @return {Roo.grid.Grid}
49918 getGrid : function(){
49922 setSize : function(width, height){
49923 if(!this.ignoreResize(width, height)){
49924 var grid = this.grid;
49925 var size = this.adjustForComponents(width, height);
49926 grid.getGridEl().setSize(size.width, size.height);
49931 beforeSlide : function(){
49932 this.grid.getView().scroller.clip();
49935 afterSlide : function(){
49936 this.grid.getView().scroller.unclip();
49939 destroy : function(){
49940 this.grid.destroy();
49942 Roo.GridPanel.superclass.destroy.call(this);
49948 * @class Roo.NestedLayoutPanel
49949 * @extends Roo.ContentPanel
49951 * Create a new NestedLayoutPanel.
49954 * @param {Roo.BorderLayout} layout The layout for this panel
49955 * @param {String/Object} config A string to set only the title or a config object
49957 Roo.NestedLayoutPanel = function(layout, config)
49959 // construct with only one argument..
49960 /* FIXME - implement nicer consturctors
49961 if (layout.layout) {
49963 layout = config.layout;
49964 delete config.layout;
49966 if (layout.xtype && !layout.getEl) {
49967 // then layout needs constructing..
49968 layout = Roo.factory(layout, Roo);
49973 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
49975 layout.monitorWindowResize = false; // turn off autosizing
49976 this.layout = layout;
49977 this.layout.getEl().addClass("x-layout-nested-layout");
49984 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
49986 setSize : function(width, height){
49987 if(!this.ignoreResize(width, height)){
49988 var size = this.adjustForComponents(width, height);
49989 var el = this.layout.getEl();
49990 el.setSize(size.width, size.height);
49991 var touch = el.dom.offsetWidth;
49992 this.layout.layout();
49993 // ie requires a double layout on the first pass
49994 if(Roo.isIE && !this.initialized){
49995 this.initialized = true;
49996 this.layout.layout();
50001 // activate all subpanels if not currently active..
50003 setActiveState : function(active){
50004 this.active = active;
50006 this.fireEvent("deactivate", this);
50010 this.fireEvent("activate", this);
50011 // not sure if this should happen before or after..
50012 if (!this.layout) {
50013 return; // should not happen..
50016 for (var r in this.layout.regions) {
50017 reg = this.layout.getRegion(r);
50018 if (reg.getActivePanel()) {
50019 //reg.showPanel(reg.getActivePanel()); // force it to activate..
50020 reg.setActivePanel(reg.getActivePanel());
50023 if (!reg.panels.length) {
50026 reg.showPanel(reg.getPanel(0));
50035 * Returns the nested BorderLayout for this panel
50036 * @return {Roo.BorderLayout}
50038 getLayout : function(){
50039 return this.layout;
50043 * Adds a xtype elements to the layout of the nested panel
50047 xtype : 'ContentPanel',
50054 xtype : 'NestedLayoutPanel',
50060 items : [ ... list of content panels or nested layout panels.. ]
50064 * @param {Object} cfg Xtype definition of item to add.
50066 addxtype : function(cfg) {
50067 return this.layout.addxtype(cfg);
50072 Roo.ScrollPanel = function(el, config, content){
50073 config = config || {};
50074 config.fitToFrame = true;
50075 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
50077 this.el.dom.style.overflow = "hidden";
50078 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
50079 this.el.removeClass("x-layout-inactive-content");
50080 this.el.on("mousewheel", this.onWheel, this);
50082 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
50083 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
50084 up.unselectable(); down.unselectable();
50085 up.on("click", this.scrollUp, this);
50086 down.on("click", this.scrollDown, this);
50087 up.addClassOnOver("x-scroller-btn-over");
50088 down.addClassOnOver("x-scroller-btn-over");
50089 up.addClassOnClick("x-scroller-btn-click");
50090 down.addClassOnClick("x-scroller-btn-click");
50091 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
50093 this.resizeEl = this.el;
50094 this.el = wrap; this.up = up; this.down = down;
50097 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
50099 wheelIncrement : 5,
50100 scrollUp : function(){
50101 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
50104 scrollDown : function(){
50105 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
50108 afterScroll : function(){
50109 var el = this.resizeEl;
50110 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
50111 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50112 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50115 setSize : function(){
50116 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
50117 this.afterScroll();
50120 onWheel : function(e){
50121 var d = e.getWheelDelta();
50122 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
50123 this.afterScroll();
50127 setContent : function(content, loadScripts){
50128 this.resizeEl.update(content, loadScripts);
50142 * @class Roo.TreePanel
50143 * @extends Roo.ContentPanel
50145 * Create a new TreePanel. - defaults to fit/scoll contents.
50146 * @param {String/Object} config A string to set only the panel's title, or a config object
50147 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
50149 Roo.TreePanel = function(config){
50150 var el = config.el;
50151 var tree = config.tree;
50152 delete config.tree;
50153 delete config.el; // hopefull!
50155 // wrapper for IE7 strict & safari scroll issue
50157 var treeEl = el.createChild();
50158 config.resizeEl = treeEl;
50162 Roo.TreePanel.superclass.constructor.call(this, el, config);
50165 this.tree = new Roo.tree.TreePanel(treeEl , tree);
50166 //console.log(tree);
50167 this.on('activate', function()
50169 if (this.tree.rendered) {
50172 //console.log('render tree');
50173 this.tree.render();
50175 // this should not be needed.. - it's actually the 'el' that resizes?
50176 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
50178 //this.on('resize', function (cp, w, h) {
50179 // this.tree.innerCt.setWidth(w);
50180 // this.tree.innerCt.setHeight(h);
50181 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
50188 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
50205 * Ext JS Library 1.1.1
50206 * Copyright(c) 2006-2007, Ext JS, LLC.
50208 * Originally Released Under LGPL - original licence link has changed is not relivant.
50211 * <script type="text/javascript">
50216 * @class Roo.ReaderLayout
50217 * @extends Roo.BorderLayout
50218 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
50219 * center region containing two nested regions (a top one for a list view and one for item preview below),
50220 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
50221 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
50222 * expedites the setup of the overall layout and regions for this common application style.
50225 var reader = new Roo.ReaderLayout();
50226 var CP = Roo.ContentPanel; // shortcut for adding
50228 reader.beginUpdate();
50229 reader.add("north", new CP("north", "North"));
50230 reader.add("west", new CP("west", {title: "West"}));
50231 reader.add("east", new CP("east", {title: "East"}));
50233 reader.regions.listView.add(new CP("listView", "List"));
50234 reader.regions.preview.add(new CP("preview", "Preview"));
50235 reader.endUpdate();
50238 * Create a new ReaderLayout
50239 * @param {Object} config Configuration options
50240 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
50241 * document.body if omitted)
50243 Roo.ReaderLayout = function(config, renderTo){
50244 var c = config || {size:{}};
50245 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
50246 north: c.north !== false ? Roo.apply({
50250 }, c.north) : false,
50251 west: c.west !== false ? Roo.apply({
50259 margins:{left:5,right:0,bottom:5,top:5},
50260 cmargins:{left:5,right:5,bottom:5,top:5}
50261 }, c.west) : false,
50262 east: c.east !== false ? Roo.apply({
50270 margins:{left:0,right:5,bottom:5,top:5},
50271 cmargins:{left:5,right:5,bottom:5,top:5}
50272 }, c.east) : false,
50273 center: Roo.apply({
50274 tabPosition: 'top',
50278 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
50282 this.el.addClass('x-reader');
50284 this.beginUpdate();
50286 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
50287 south: c.preview !== false ? Roo.apply({
50294 cmargins:{top:5,left:0, right:0, bottom:0}
50295 }, c.preview) : false,
50296 center: Roo.apply({
50302 this.add('center', new Roo.NestedLayoutPanel(inner,
50303 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
50307 this.regions.preview = inner.getRegion('south');
50308 this.regions.listView = inner.getRegion('center');
50311 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
50313 * Ext JS Library 1.1.1
50314 * Copyright(c) 2006-2007, Ext JS, LLC.
50316 * Originally Released Under LGPL - original licence link has changed is not relivant.
50319 * <script type="text/javascript">
50323 * @class Roo.grid.Grid
50324 * @extends Roo.util.Observable
50325 * This class represents the primary interface of a component based grid control.
50326 * <br><br>Usage:<pre><code>
50327 var grid = new Roo.grid.Grid("my-container-id", {
50330 selModel: mySelectionModel,
50331 autoSizeColumns: true,
50332 monitorWindowResize: false,
50333 trackMouseOver: true
50338 * <b>Common Problems:</b><br/>
50339 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
50340 * element will correct this<br/>
50341 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
50342 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
50343 * are unpredictable.<br/>
50344 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
50345 * grid to calculate dimensions/offsets.<br/>
50347 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50348 * The container MUST have some type of size defined for the grid to fill. The container will be
50349 * automatically set to position relative if it isn't already.
50350 * @param {Object} config A config object that sets properties on this grid.
50352 Roo.grid.Grid = function(container, config){
50353 // initialize the container
50354 this.container = Roo.get(container);
50355 this.container.update("");
50356 this.container.setStyle("overflow", "hidden");
50357 this.container.addClass('x-grid-container');
50359 this.id = this.container.id;
50361 Roo.apply(this, config);
50362 // check and correct shorthanded configs
50364 this.dataSource = this.ds;
50368 this.colModel = this.cm;
50372 this.selModel = this.sm;
50376 if (this.selModel) {
50377 this.selModel = Roo.factory(this.selModel, Roo.grid);
50378 this.sm = this.selModel;
50379 this.sm.xmodule = this.xmodule || false;
50381 if (typeof(this.colModel.config) == 'undefined') {
50382 this.colModel = new Roo.grid.ColumnModel(this.colModel);
50383 this.cm = this.colModel;
50384 this.cm.xmodule = this.xmodule || false;
50386 if (this.dataSource) {
50387 this.dataSource= Roo.factory(this.dataSource, Roo.data);
50388 this.ds = this.dataSource;
50389 this.ds.xmodule = this.xmodule || false;
50396 this.container.setWidth(this.width);
50400 this.container.setHeight(this.height);
50407 * The raw click event for the entire grid.
50408 * @param {Roo.EventObject} e
50413 * The raw dblclick event for the entire grid.
50414 * @param {Roo.EventObject} e
50418 * @event contextmenu
50419 * The raw contextmenu event for the entire grid.
50420 * @param {Roo.EventObject} e
50422 "contextmenu" : true,
50425 * The raw mousedown event for the entire grid.
50426 * @param {Roo.EventObject} e
50428 "mousedown" : true,
50431 * The raw mouseup event for the entire grid.
50432 * @param {Roo.EventObject} e
50437 * The raw mouseover event for the entire grid.
50438 * @param {Roo.EventObject} e
50440 "mouseover" : true,
50443 * The raw mouseout event for the entire grid.
50444 * @param {Roo.EventObject} e
50449 * The raw keypress event for the entire grid.
50450 * @param {Roo.EventObject} e
50455 * The raw keydown event for the entire grid.
50456 * @param {Roo.EventObject} e
50464 * Fires when a cell is clicked
50465 * @param {Grid} this
50466 * @param {Number} rowIndex
50467 * @param {Number} columnIndex
50468 * @param {Roo.EventObject} e
50470 "cellclick" : true,
50472 * @event celldblclick
50473 * Fires when a cell is double clicked
50474 * @param {Grid} this
50475 * @param {Number} rowIndex
50476 * @param {Number} columnIndex
50477 * @param {Roo.EventObject} e
50479 "celldblclick" : true,
50482 * Fires when a row is clicked
50483 * @param {Grid} this
50484 * @param {Number} rowIndex
50485 * @param {Roo.EventObject} e
50489 * @event rowdblclick
50490 * Fires when a row is double clicked
50491 * @param {Grid} this
50492 * @param {Number} rowIndex
50493 * @param {Roo.EventObject} e
50495 "rowdblclick" : true,
50497 * @event headerclick
50498 * Fires when a header is clicked
50499 * @param {Grid} this
50500 * @param {Number} columnIndex
50501 * @param {Roo.EventObject} e
50503 "headerclick" : true,
50505 * @event headerdblclick
50506 * Fires when a header cell is double clicked
50507 * @param {Grid} this
50508 * @param {Number} columnIndex
50509 * @param {Roo.EventObject} e
50511 "headerdblclick" : true,
50513 * @event rowcontextmenu
50514 * Fires when a row is right clicked
50515 * @param {Grid} this
50516 * @param {Number} rowIndex
50517 * @param {Roo.EventObject} e
50519 "rowcontextmenu" : true,
50521 * @event cellcontextmenu
50522 * Fires when a cell is right clicked
50523 * @param {Grid} this
50524 * @param {Number} rowIndex
50525 * @param {Number} cellIndex
50526 * @param {Roo.EventObject} e
50528 "cellcontextmenu" : true,
50530 * @event headercontextmenu
50531 * Fires when a header is right clicked
50532 * @param {Grid} this
50533 * @param {Number} columnIndex
50534 * @param {Roo.EventObject} e
50536 "headercontextmenu" : true,
50538 * @event bodyscroll
50539 * Fires when the body element is scrolled
50540 * @param {Number} scrollLeft
50541 * @param {Number} scrollTop
50543 "bodyscroll" : true,
50545 * @event columnresize
50546 * Fires when the user resizes a column
50547 * @param {Number} columnIndex
50548 * @param {Number} newSize
50550 "columnresize" : true,
50552 * @event columnmove
50553 * Fires when the user moves a column
50554 * @param {Number} oldIndex
50555 * @param {Number} newIndex
50557 "columnmove" : true,
50560 * Fires when row(s) start being dragged
50561 * @param {Grid} this
50562 * @param {Roo.GridDD} dd The drag drop object
50563 * @param {event} e The raw browser event
50565 "startdrag" : true,
50568 * Fires when a drag operation is complete
50569 * @param {Grid} this
50570 * @param {Roo.GridDD} dd The drag drop object
50571 * @param {event} e The raw browser event
50576 * Fires when dragged row(s) are dropped on a valid DD target
50577 * @param {Grid} this
50578 * @param {Roo.GridDD} dd The drag drop object
50579 * @param {String} targetId The target drag drop object
50580 * @param {event} e The raw browser event
50585 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
50586 * @param {Grid} this
50587 * @param {Roo.GridDD} dd The drag drop object
50588 * @param {String} targetId The target drag drop object
50589 * @param {event} e The raw browser event
50594 * Fires when the dragged row(s) first cross another DD target while being dragged
50595 * @param {Grid} this
50596 * @param {Roo.GridDD} dd The drag drop object
50597 * @param {String} targetId The target drag drop object
50598 * @param {event} e The raw browser event
50600 "dragenter" : true,
50603 * Fires when the dragged row(s) leave another DD target while being dragged
50604 * @param {Grid} this
50605 * @param {Roo.GridDD} dd The drag drop object
50606 * @param {String} targetId The target drag drop object
50607 * @param {event} e The raw browser event
50612 * Fires when a row is rendered, so you can change add a style to it.
50613 * @param {GridView} gridview The grid view
50614 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
50620 * Fires when the grid is rendered
50621 * @param {Grid} grid
50626 Roo.grid.Grid.superclass.constructor.call(this);
50628 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
50631 * @cfg {String} ddGroup - drag drop group.
50635 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
50637 minColumnWidth : 25,
50640 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
50641 * <b>on initial render.</b> It is more efficient to explicitly size the columns
50642 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
50644 autoSizeColumns : false,
50647 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
50649 autoSizeHeaders : true,
50652 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
50654 monitorWindowResize : true,
50657 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
50658 * rows measured to get a columns size. Default is 0 (all rows).
50660 maxRowsToMeasure : 0,
50663 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
50665 trackMouseOver : true,
50668 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
50672 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
50674 enableDragDrop : false,
50677 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
50679 enableColumnMove : true,
50682 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
50684 enableColumnHide : true,
50687 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
50689 enableRowHeightSync : false,
50692 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
50697 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
50699 autoHeight : false,
50702 * @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.
50704 autoExpandColumn : false,
50707 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
50710 autoExpandMin : 50,
50713 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
50715 autoExpandMax : 1000,
50718 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
50723 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
50727 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
50737 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
50738 * of a fixed width. Default is false.
50741 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
50744 * Called once after all setup has been completed and the grid is ready to be rendered.
50745 * @return {Roo.grid.Grid} this
50747 render : function()
50749 var c = this.container;
50750 // try to detect autoHeight/width mode
50751 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
50752 this.autoHeight = true;
50754 var view = this.getView();
50757 c.on("click", this.onClick, this);
50758 c.on("dblclick", this.onDblClick, this);
50759 c.on("contextmenu", this.onContextMenu, this);
50760 c.on("keydown", this.onKeyDown, this);
50762 c.on("touchstart", this.onTouchStart, this);
50765 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
50767 this.getSelectionModel().init(this);
50772 this.loadMask = new Roo.LoadMask(this.container,
50773 Roo.apply({store:this.dataSource}, this.loadMask));
50777 if (this.toolbar && this.toolbar.xtype) {
50778 this.toolbar.container = this.getView().getHeaderPanel(true);
50779 this.toolbar = new Roo.Toolbar(this.toolbar);
50781 if (this.footer && this.footer.xtype) {
50782 this.footer.dataSource = this.getDataSource();
50783 this.footer.container = this.getView().getFooterPanel(true);
50784 this.footer = Roo.factory(this.footer, Roo);
50786 if (this.dropTarget && this.dropTarget.xtype) {
50787 delete this.dropTarget.xtype;
50788 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
50792 this.rendered = true;
50793 this.fireEvent('render', this);
50798 * Reconfigures the grid to use a different Store and Column Model.
50799 * The View will be bound to the new objects and refreshed.
50800 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
50801 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
50803 reconfigure : function(dataSource, colModel){
50805 this.loadMask.destroy();
50806 this.loadMask = new Roo.LoadMask(this.container,
50807 Roo.apply({store:dataSource}, this.loadMask));
50809 this.view.bind(dataSource, colModel);
50810 this.dataSource = dataSource;
50811 this.colModel = colModel;
50812 this.view.refresh(true);
50816 onKeyDown : function(e){
50817 this.fireEvent("keydown", e);
50821 * Destroy this grid.
50822 * @param {Boolean} removeEl True to remove the element
50824 destroy : function(removeEl, keepListeners){
50826 this.loadMask.destroy();
50828 var c = this.container;
50829 c.removeAllListeners();
50830 this.view.destroy();
50831 this.colModel.purgeListeners();
50832 if(!keepListeners){
50833 this.purgeListeners();
50836 if(removeEl === true){
50842 processEvent : function(name, e){
50843 // does this fire select???
50844 Roo.log('grid:processEvent ' + name);
50846 if (name != 'touchstart' ) {
50847 this.fireEvent(name, e);
50850 var t = e.getTarget();
50852 var header = v.findHeaderIndex(t);
50853 if(header !== false){
50854 this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
50856 var row = v.findRowIndex(t);
50857 var cell = v.findCellIndex(t);
50858 if (name == 'touchstart') {
50859 // first touch is always a click.
50860 // hopefull this happens after selection is updated.?
50863 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
50864 var cs = this.selModel.getSelectedCell();
50865 if (row == cs[0] && cell == cs[1]){
50869 if (typeof(this.selModel.getSelections) != 'undefined') {
50870 var cs = this.selModel.getSelections();
50871 var ds = this.dataSource;
50872 if (cs.length == 1 && ds.getAt(row) == cs[0]){
50883 this.fireEvent("row" + name, this, row, e);
50884 if(cell !== false){
50885 this.fireEvent("cell" + name, this, row, cell, e);
50892 onClick : function(e){
50893 this.processEvent("click", e);
50896 onTouchStart : function(e){
50897 this.processEvent("touchstart", e);
50901 onContextMenu : function(e, t){
50902 this.processEvent("contextmenu", e);
50906 onDblClick : function(e){
50907 this.processEvent("dblclick", e);
50911 walkCells : function(row, col, step, fn, scope){
50912 var cm = this.colModel, clen = cm.getColumnCount();
50913 var ds = this.dataSource, rlen = ds.getCount(), first = true;
50925 if(fn.call(scope || this, row, col, cm) === true){
50943 if(fn.call(scope || this, row, col, cm) === true){
50955 getSelections : function(){
50956 return this.selModel.getSelections();
50960 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
50961 * but if manual update is required this method will initiate it.
50963 autoSize : function(){
50965 this.view.layout();
50966 if(this.view.adjustForScroll){
50967 this.view.adjustForScroll();
50973 * Returns the grid's underlying element.
50974 * @return {Element} The element
50976 getGridEl : function(){
50977 return this.container;
50980 // private for compatibility, overridden by editor grid
50981 stopEditing : function(){},
50984 * Returns the grid's SelectionModel.
50985 * @return {SelectionModel}
50987 getSelectionModel : function(){
50988 if(!this.selModel){
50989 this.selModel = new Roo.grid.RowSelectionModel();
50991 return this.selModel;
50995 * Returns the grid's DataSource.
50996 * @return {DataSource}
50998 getDataSource : function(){
50999 return this.dataSource;
51003 * Returns the grid's ColumnModel.
51004 * @return {ColumnModel}
51006 getColumnModel : function(){
51007 return this.colModel;
51011 * Returns the grid's GridView object.
51012 * @return {GridView}
51014 getView : function(){
51016 this.view = new Roo.grid.GridView(this.viewConfig);
51021 * Called to get grid's drag proxy text, by default returns this.ddText.
51024 getDragDropText : function(){
51025 var count = this.selModel.getCount();
51026 return String.format(this.ddText, count, count == 1 ? '' : 's');
51030 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
51031 * %0 is replaced with the number of selected rows.
51034 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
51036 * Ext JS Library 1.1.1
51037 * Copyright(c) 2006-2007, Ext JS, LLC.
51039 * Originally Released Under LGPL - original licence link has changed is not relivant.
51042 * <script type="text/javascript">
51045 Roo.grid.AbstractGridView = function(){
51049 "beforerowremoved" : true,
51050 "beforerowsinserted" : true,
51051 "beforerefresh" : true,
51052 "rowremoved" : true,
51053 "rowsinserted" : true,
51054 "rowupdated" : true,
51057 Roo.grid.AbstractGridView.superclass.constructor.call(this);
51060 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
51061 rowClass : "x-grid-row",
51062 cellClass : "x-grid-cell",
51063 tdClass : "x-grid-td",
51064 hdClass : "x-grid-hd",
51065 splitClass : "x-grid-hd-split",
51067 init: function(grid){
51069 var cid = this.grid.getGridEl().id;
51070 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
51071 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
51072 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
51073 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
51076 getColumnRenderers : function(){
51077 var renderers = [];
51078 var cm = this.grid.colModel;
51079 var colCount = cm.getColumnCount();
51080 for(var i = 0; i < colCount; i++){
51081 renderers[i] = cm.getRenderer(i);
51086 getColumnIds : function(){
51088 var cm = this.grid.colModel;
51089 var colCount = cm.getColumnCount();
51090 for(var i = 0; i < colCount; i++){
51091 ids[i] = cm.getColumnId(i);
51096 getDataIndexes : function(){
51097 if(!this.indexMap){
51098 this.indexMap = this.buildIndexMap();
51100 return this.indexMap.colToData;
51103 getColumnIndexByDataIndex : function(dataIndex){
51104 if(!this.indexMap){
51105 this.indexMap = this.buildIndexMap();
51107 return this.indexMap.dataToCol[dataIndex];
51111 * Set a css style for a column dynamically.
51112 * @param {Number} colIndex The index of the column
51113 * @param {String} name The css property name
51114 * @param {String} value The css value
51116 setCSSStyle : function(colIndex, name, value){
51117 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
51118 Roo.util.CSS.updateRule(selector, name, value);
51121 generateRules : function(cm){
51122 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
51123 Roo.util.CSS.removeStyleSheet(rulesId);
51124 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51125 var cid = cm.getColumnId(i);
51126 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
51127 this.tdSelector, cid, " {\n}\n",
51128 this.hdSelector, cid, " {\n}\n",
51129 this.splitSelector, cid, " {\n}\n");
51131 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
51135 * Ext JS Library 1.1.1
51136 * Copyright(c) 2006-2007, Ext JS, LLC.
51138 * Originally Released Under LGPL - original licence link has changed is not relivant.
51141 * <script type="text/javascript">
51145 // This is a support class used internally by the Grid components
51146 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
51148 this.view = grid.getView();
51149 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51150 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
51152 this.setHandleElId(Roo.id(hd));
51153 this.setOuterHandleElId(Roo.id(hd2));
51155 this.scroll = false;
51157 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
51159 getDragData : function(e){
51160 var t = Roo.lib.Event.getTarget(e);
51161 var h = this.view.findHeaderCell(t);
51163 return {ddel: h.firstChild, header:h};
51168 onInitDrag : function(e){
51169 this.view.headersDisabled = true;
51170 var clone = this.dragData.ddel.cloneNode(true);
51171 clone.id = Roo.id();
51172 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
51173 this.proxy.update(clone);
51177 afterValidDrop : function(){
51179 setTimeout(function(){
51180 v.headersDisabled = false;
51184 afterInvalidDrop : function(){
51186 setTimeout(function(){
51187 v.headersDisabled = false;
51193 * Ext JS Library 1.1.1
51194 * Copyright(c) 2006-2007, Ext JS, LLC.
51196 * Originally Released Under LGPL - original licence link has changed is not relivant.
51199 * <script type="text/javascript">
51202 // This is a support class used internally by the Grid components
51203 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
51205 this.view = grid.getView();
51206 // split the proxies so they don't interfere with mouse events
51207 this.proxyTop = Roo.DomHelper.append(document.body, {
51208 cls:"col-move-top", html:" "
51210 this.proxyBottom = Roo.DomHelper.append(document.body, {
51211 cls:"col-move-bottom", html:" "
51213 this.proxyTop.hide = this.proxyBottom.hide = function(){
51214 this.setLeftTop(-100,-100);
51215 this.setStyle("visibility", "hidden");
51217 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51218 // temporarily disabled
51219 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
51220 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
51222 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
51223 proxyOffsets : [-4, -9],
51224 fly: Roo.Element.fly,
51226 getTargetFromEvent : function(e){
51227 var t = Roo.lib.Event.getTarget(e);
51228 var cindex = this.view.findCellIndex(t);
51229 if(cindex !== false){
51230 return this.view.getHeaderCell(cindex);
51235 nextVisible : function(h){
51236 var v = this.view, cm = this.grid.colModel;
51239 if(!cm.isHidden(v.getCellIndex(h))){
51247 prevVisible : function(h){
51248 var v = this.view, cm = this.grid.colModel;
51251 if(!cm.isHidden(v.getCellIndex(h))){
51259 positionIndicator : function(h, n, e){
51260 var x = Roo.lib.Event.getPageX(e);
51261 var r = Roo.lib.Dom.getRegion(n.firstChild);
51262 var px, pt, py = r.top + this.proxyOffsets[1];
51263 if((r.right - x) <= (r.right-r.left)/2){
51264 px = r.right+this.view.borderWidth;
51270 var oldIndex = this.view.getCellIndex(h);
51271 var newIndex = this.view.getCellIndex(n);
51273 if(this.grid.colModel.isFixed(newIndex)){
51277 var locked = this.grid.colModel.isLocked(newIndex);
51282 if(oldIndex < newIndex){
51285 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
51288 px += this.proxyOffsets[0];
51289 this.proxyTop.setLeftTop(px, py);
51290 this.proxyTop.show();
51291 if(!this.bottomOffset){
51292 this.bottomOffset = this.view.mainHd.getHeight();
51294 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
51295 this.proxyBottom.show();
51299 onNodeEnter : function(n, dd, e, data){
51300 if(data.header != n){
51301 this.positionIndicator(data.header, n, e);
51305 onNodeOver : function(n, dd, e, data){
51306 var result = false;
51307 if(data.header != n){
51308 result = this.positionIndicator(data.header, n, e);
51311 this.proxyTop.hide();
51312 this.proxyBottom.hide();
51314 return result ? this.dropAllowed : this.dropNotAllowed;
51317 onNodeOut : function(n, dd, e, data){
51318 this.proxyTop.hide();
51319 this.proxyBottom.hide();
51322 onNodeDrop : function(n, dd, e, data){
51323 var h = data.header;
51325 var cm = this.grid.colModel;
51326 var x = Roo.lib.Event.getPageX(e);
51327 var r = Roo.lib.Dom.getRegion(n.firstChild);
51328 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
51329 var oldIndex = this.view.getCellIndex(h);
51330 var newIndex = this.view.getCellIndex(n);
51331 var locked = cm.isLocked(newIndex);
51335 if(oldIndex < newIndex){
51338 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
51341 cm.setLocked(oldIndex, locked, true);
51342 cm.moveColumn(oldIndex, newIndex);
51343 this.grid.fireEvent("columnmove", oldIndex, newIndex);
51351 * Ext JS Library 1.1.1
51352 * Copyright(c) 2006-2007, Ext JS, LLC.
51354 * Originally Released Under LGPL - original licence link has changed is not relivant.
51357 * <script type="text/javascript">
51361 * @class Roo.grid.GridView
51362 * @extends Roo.util.Observable
51365 * @param {Object} config
51367 Roo.grid.GridView = function(config){
51368 Roo.grid.GridView.superclass.constructor.call(this);
51371 Roo.apply(this, config);
51374 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
51376 unselectable : 'unselectable="on"',
51377 unselectableCls : 'x-unselectable',
51380 rowClass : "x-grid-row",
51382 cellClass : "x-grid-col",
51384 tdClass : "x-grid-td",
51386 hdClass : "x-grid-hd",
51388 splitClass : "x-grid-split",
51390 sortClasses : ["sort-asc", "sort-desc"],
51392 enableMoveAnim : false,
51396 dh : Roo.DomHelper,
51398 fly : Roo.Element.fly,
51400 css : Roo.util.CSS,
51406 scrollIncrement : 22,
51408 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
51410 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
51412 bind : function(ds, cm){
51414 this.ds.un("load", this.onLoad, this);
51415 this.ds.un("datachanged", this.onDataChange, this);
51416 this.ds.un("add", this.onAdd, this);
51417 this.ds.un("remove", this.onRemove, this);
51418 this.ds.un("update", this.onUpdate, this);
51419 this.ds.un("clear", this.onClear, this);
51422 ds.on("load", this.onLoad, this);
51423 ds.on("datachanged", this.onDataChange, this);
51424 ds.on("add", this.onAdd, this);
51425 ds.on("remove", this.onRemove, this);
51426 ds.on("update", this.onUpdate, this);
51427 ds.on("clear", this.onClear, this);
51432 this.cm.un("widthchange", this.onColWidthChange, this);
51433 this.cm.un("headerchange", this.onHeaderChange, this);
51434 this.cm.un("hiddenchange", this.onHiddenChange, this);
51435 this.cm.un("columnmoved", this.onColumnMove, this);
51436 this.cm.un("columnlockchange", this.onColumnLock, this);
51439 this.generateRules(cm);
51440 cm.on("widthchange", this.onColWidthChange, this);
51441 cm.on("headerchange", this.onHeaderChange, this);
51442 cm.on("hiddenchange", this.onHiddenChange, this);
51443 cm.on("columnmoved", this.onColumnMove, this);
51444 cm.on("columnlockchange", this.onColumnLock, this);
51449 init: function(grid){
51450 Roo.grid.GridView.superclass.init.call(this, grid);
51452 this.bind(grid.dataSource, grid.colModel);
51454 grid.on("headerclick", this.handleHeaderClick, this);
51456 if(grid.trackMouseOver){
51457 grid.on("mouseover", this.onRowOver, this);
51458 grid.on("mouseout", this.onRowOut, this);
51460 grid.cancelTextSelection = function(){};
51461 this.gridId = grid.id;
51463 var tpls = this.templates || {};
51466 tpls.master = new Roo.Template(
51467 '<div class="x-grid" hidefocus="true">',
51468 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
51469 '<div class="x-grid-topbar"></div>',
51470 '<div class="x-grid-scroller"><div></div></div>',
51471 '<div class="x-grid-locked">',
51472 '<div class="x-grid-header">{lockedHeader}</div>',
51473 '<div class="x-grid-body">{lockedBody}</div>',
51475 '<div class="x-grid-viewport">',
51476 '<div class="x-grid-header">{header}</div>',
51477 '<div class="x-grid-body">{body}</div>',
51479 '<div class="x-grid-bottombar"></div>',
51481 '<div class="x-grid-resize-proxy"> </div>',
51484 tpls.master.disableformats = true;
51488 tpls.header = new Roo.Template(
51489 '<table border="0" cellspacing="0" cellpadding="0">',
51490 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
51493 tpls.header.disableformats = true;
51495 tpls.header.compile();
51498 tpls.hcell = new Roo.Template(
51499 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
51500 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
51503 tpls.hcell.disableFormats = true;
51505 tpls.hcell.compile();
51508 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
51509 this.unselectableCls + '" ' + this.unselectable +'> </div>');
51510 tpls.hsplit.disableFormats = true;
51512 tpls.hsplit.compile();
51515 tpls.body = new Roo.Template(
51516 '<table border="0" cellspacing="0" cellpadding="0">',
51517 "<tbody>{rows}</tbody>",
51520 tpls.body.disableFormats = true;
51522 tpls.body.compile();
51525 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
51526 tpls.row.disableFormats = true;
51528 tpls.row.compile();
51531 tpls.cell = new Roo.Template(
51532 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
51533 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
51534 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
51537 tpls.cell.disableFormats = true;
51539 tpls.cell.compile();
51541 this.templates = tpls;
51544 // remap these for backwards compat
51545 onColWidthChange : function(){
51546 this.updateColumns.apply(this, arguments);
51548 onHeaderChange : function(){
51549 this.updateHeaders.apply(this, arguments);
51551 onHiddenChange : function(){
51552 this.handleHiddenChange.apply(this, arguments);
51554 onColumnMove : function(){
51555 this.handleColumnMove.apply(this, arguments);
51557 onColumnLock : function(){
51558 this.handleLockChange.apply(this, arguments);
51561 onDataChange : function(){
51563 this.updateHeaderSortState();
51566 onClear : function(){
51570 onUpdate : function(ds, record){
51571 this.refreshRow(record);
51574 refreshRow : function(record){
51575 var ds = this.ds, index;
51576 if(typeof record == 'number'){
51578 record = ds.getAt(index);
51580 index = ds.indexOf(record);
51582 this.insertRows(ds, index, index, true);
51583 this.onRemove(ds, record, index+1, true);
51584 this.syncRowHeights(index, index);
51586 this.fireEvent("rowupdated", this, index, record);
51589 onAdd : function(ds, records, index){
51590 this.insertRows(ds, index, index + (records.length-1));
51593 onRemove : function(ds, record, index, isUpdate){
51594 if(isUpdate !== true){
51595 this.fireEvent("beforerowremoved", this, index, record);
51597 var bt = this.getBodyTable(), lt = this.getLockedTable();
51598 if(bt.rows[index]){
51599 bt.firstChild.removeChild(bt.rows[index]);
51601 if(lt.rows[index]){
51602 lt.firstChild.removeChild(lt.rows[index]);
51604 if(isUpdate !== true){
51605 this.stripeRows(index);
51606 this.syncRowHeights(index, index);
51608 this.fireEvent("rowremoved", this, index, record);
51612 onLoad : function(){
51613 this.scrollToTop();
51617 * Scrolls the grid to the top
51619 scrollToTop : function(){
51621 this.scroller.dom.scrollTop = 0;
51627 * Gets a panel in the header of the grid that can be used for toolbars etc.
51628 * After modifying the contents of this panel a call to grid.autoSize() may be
51629 * required to register any changes in size.
51630 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
51631 * @return Roo.Element
51633 getHeaderPanel : function(doShow){
51635 this.headerPanel.show();
51637 return this.headerPanel;
51641 * Gets a panel in the footer of the grid that can be used for toolbars etc.
51642 * After modifying the contents of this panel a call to grid.autoSize() may be
51643 * required to register any changes in size.
51644 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
51645 * @return Roo.Element
51647 getFooterPanel : function(doShow){
51649 this.footerPanel.show();
51651 return this.footerPanel;
51654 initElements : function(){
51655 var E = Roo.Element;
51656 var el = this.grid.getGridEl().dom.firstChild;
51657 var cs = el.childNodes;
51659 this.el = new E(el);
51661 this.focusEl = new E(el.firstChild);
51662 this.focusEl.swallowEvent("click", true);
51664 this.headerPanel = new E(cs[1]);
51665 this.headerPanel.enableDisplayMode("block");
51667 this.scroller = new E(cs[2]);
51668 this.scrollSizer = new E(this.scroller.dom.firstChild);
51670 this.lockedWrap = new E(cs[3]);
51671 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
51672 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
51674 this.mainWrap = new E(cs[4]);
51675 this.mainHd = new E(this.mainWrap.dom.firstChild);
51676 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
51678 this.footerPanel = new E(cs[5]);
51679 this.footerPanel.enableDisplayMode("block");
51681 this.resizeProxy = new E(cs[6]);
51683 this.headerSelector = String.format(
51684 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
51685 this.lockedHd.id, this.mainHd.id
51688 this.splitterSelector = String.format(
51689 '#{0} div.x-grid-split, #{1} div.x-grid-split',
51690 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
51693 idToCssName : function(s)
51695 return s.replace(/[^a-z0-9]+/ig, '-');
51698 getHeaderCell : function(index){
51699 return Roo.DomQuery.select(this.headerSelector)[index];
51702 getHeaderCellMeasure : function(index){
51703 return this.getHeaderCell(index).firstChild;
51706 getHeaderCellText : function(index){
51707 return this.getHeaderCell(index).firstChild.firstChild;
51710 getLockedTable : function(){
51711 return this.lockedBody.dom.firstChild;
51714 getBodyTable : function(){
51715 return this.mainBody.dom.firstChild;
51718 getLockedRow : function(index){
51719 return this.getLockedTable().rows[index];
51722 getRow : function(index){
51723 return this.getBodyTable().rows[index];
51726 getRowComposite : function(index){
51728 this.rowEl = new Roo.CompositeElementLite();
51730 var els = [], lrow, mrow;
51731 if(lrow = this.getLockedRow(index)){
51734 if(mrow = this.getRow(index)){
51737 this.rowEl.elements = els;
51741 * Gets the 'td' of the cell
51743 * @param {Integer} rowIndex row to select
51744 * @param {Integer} colIndex column to select
51748 getCell : function(rowIndex, colIndex){
51749 var locked = this.cm.getLockedCount();
51751 if(colIndex < locked){
51752 source = this.lockedBody.dom.firstChild;
51754 source = this.mainBody.dom.firstChild;
51755 colIndex -= locked;
51757 return source.rows[rowIndex].childNodes[colIndex];
51760 getCellText : function(rowIndex, colIndex){
51761 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
51764 getCellBox : function(cell){
51765 var b = this.fly(cell).getBox();
51766 if(Roo.isOpera){ // opera fails to report the Y
51767 b.y = cell.offsetTop + this.mainBody.getY();
51772 getCellIndex : function(cell){
51773 var id = String(cell.className).match(this.cellRE);
51775 return parseInt(id[1], 10);
51780 findHeaderIndex : function(n){
51781 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
51782 return r ? this.getCellIndex(r) : false;
51785 findHeaderCell : function(n){
51786 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
51787 return r ? r : false;
51790 findRowIndex : function(n){
51794 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
51795 return r ? r.rowIndex : false;
51798 findCellIndex : function(node){
51799 var stop = this.el.dom;
51800 while(node && node != stop){
51801 if(this.findRE.test(node.className)){
51802 return this.getCellIndex(node);
51804 node = node.parentNode;
51809 getColumnId : function(index){
51810 return this.cm.getColumnId(index);
51813 getSplitters : function()
51815 if(this.splitterSelector){
51816 return Roo.DomQuery.select(this.splitterSelector);
51822 getSplitter : function(index){
51823 return this.getSplitters()[index];
51826 onRowOver : function(e, t){
51828 if((row = this.findRowIndex(t)) !== false){
51829 this.getRowComposite(row).addClass("x-grid-row-over");
51833 onRowOut : function(e, t){
51835 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
51836 this.getRowComposite(row).removeClass("x-grid-row-over");
51840 renderHeaders : function(){
51842 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
51843 var cb = [], lb = [], sb = [], lsb = [], p = {};
51844 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51845 p.cellId = "x-grid-hd-0-" + i;
51846 p.splitId = "x-grid-csplit-0-" + i;
51847 p.id = cm.getColumnId(i);
51848 p.title = cm.getColumnTooltip(i) || "";
51849 p.value = cm.getColumnHeader(i) || "";
51850 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
51851 if(!cm.isLocked(i)){
51852 cb[cb.length] = ct.apply(p);
51853 sb[sb.length] = st.apply(p);
51855 lb[lb.length] = ct.apply(p);
51856 lsb[lsb.length] = st.apply(p);
51859 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
51860 ht.apply({cells: cb.join(""), splits:sb.join("")})];
51863 updateHeaders : function(){
51864 var html = this.renderHeaders();
51865 this.lockedHd.update(html[0]);
51866 this.mainHd.update(html[1]);
51870 * Focuses the specified row.
51871 * @param {Number} row The row index
51873 focusRow : function(row)
51875 //Roo.log('GridView.focusRow');
51876 var x = this.scroller.dom.scrollLeft;
51877 this.focusCell(row, 0, false);
51878 this.scroller.dom.scrollLeft = x;
51882 * Focuses the specified cell.
51883 * @param {Number} row The row index
51884 * @param {Number} col The column index
51885 * @param {Boolean} hscroll false to disable horizontal scrolling
51887 focusCell : function(row, col, hscroll)
51889 //Roo.log('GridView.focusCell');
51890 var el = this.ensureVisible(row, col, hscroll);
51891 this.focusEl.alignTo(el, "tl-tl");
51893 this.focusEl.focus();
51895 this.focusEl.focus.defer(1, this.focusEl);
51900 * Scrolls the specified cell into view
51901 * @param {Number} row The row index
51902 * @param {Number} col The column index
51903 * @param {Boolean} hscroll false to disable horizontal scrolling
51905 ensureVisible : function(row, col, hscroll)
51907 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
51908 //return null; //disable for testing.
51909 if(typeof row != "number"){
51910 row = row.rowIndex;
51912 if(row < 0 && row >= this.ds.getCount()){
51915 col = (col !== undefined ? col : 0);
51916 var cm = this.grid.colModel;
51917 while(cm.isHidden(col)){
51921 var el = this.getCell(row, col);
51925 var c = this.scroller.dom;
51927 var ctop = parseInt(el.offsetTop, 10);
51928 var cleft = parseInt(el.offsetLeft, 10);
51929 var cbot = ctop + el.offsetHeight;
51930 var cright = cleft + el.offsetWidth;
51932 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
51933 var stop = parseInt(c.scrollTop, 10);
51934 var sleft = parseInt(c.scrollLeft, 10);
51935 var sbot = stop + ch;
51936 var sright = sleft + c.clientWidth;
51938 Roo.log('GridView.ensureVisible:' +
51940 ' c.clientHeight:' + c.clientHeight +
51941 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
51949 c.scrollTop = ctop;
51950 //Roo.log("set scrolltop to ctop DISABLE?");
51951 }else if(cbot > sbot){
51952 //Roo.log("set scrolltop to cbot-ch");
51953 c.scrollTop = cbot-ch;
51956 if(hscroll !== false){
51958 c.scrollLeft = cleft;
51959 }else if(cright > sright){
51960 c.scrollLeft = cright-c.clientWidth;
51967 updateColumns : function(){
51968 this.grid.stopEditing();
51969 var cm = this.grid.colModel, colIds = this.getColumnIds();
51970 //var totalWidth = cm.getTotalWidth();
51972 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51973 //if(cm.isHidden(i)) continue;
51974 var w = cm.getColumnWidth(i);
51975 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
51976 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
51978 this.updateSplitters();
51981 generateRules : function(cm){
51982 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
51983 Roo.util.CSS.removeStyleSheet(rulesId);
51984 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51985 var cid = cm.getColumnId(i);
51987 if(cm.config[i].align){
51988 align = 'text-align:'+cm.config[i].align+';';
51991 if(cm.isHidden(i)){
51992 hidden = 'display:none;';
51994 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
51996 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
51997 this.hdSelector, cid, " {\n", align, width, "}\n",
51998 this.tdSelector, cid, " {\n",hidden,"\n}\n",
51999 this.splitSelector, cid, " {\n", hidden , "\n}\n");
52001 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52004 updateSplitters : function(){
52005 var cm = this.cm, s = this.getSplitters();
52006 if(s){ // splitters not created yet
52007 var pos = 0, locked = true;
52008 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52009 if(cm.isHidden(i)) continue;
52010 var w = cm.getColumnWidth(i); // make sure it's a number
52011 if(!cm.isLocked(i) && locked){
52016 s[i].style.left = (pos-this.splitOffset) + "px";
52021 handleHiddenChange : function(colModel, colIndex, hidden){
52023 this.hideColumn(colIndex);
52025 this.unhideColumn(colIndex);
52029 hideColumn : function(colIndex){
52030 var cid = this.getColumnId(colIndex);
52031 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
52032 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
52034 this.updateHeaders();
52036 this.updateSplitters();
52040 unhideColumn : function(colIndex){
52041 var cid = this.getColumnId(colIndex);
52042 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
52043 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
52046 this.updateHeaders();
52048 this.updateSplitters();
52052 insertRows : function(dm, firstRow, lastRow, isUpdate){
52053 if(firstRow == 0 && lastRow == dm.getCount()-1){
52057 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
52059 var s = this.getScrollState();
52060 var markup = this.renderRows(firstRow, lastRow);
52061 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
52062 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
52063 this.restoreScroll(s);
52065 this.fireEvent("rowsinserted", this, firstRow, lastRow);
52066 this.syncRowHeights(firstRow, lastRow);
52067 this.stripeRows(firstRow);
52073 bufferRows : function(markup, target, index){
52074 var before = null, trows = target.rows, tbody = target.tBodies[0];
52075 if(index < trows.length){
52076 before = trows[index];
52078 var b = document.createElement("div");
52079 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
52080 var rows = b.firstChild.rows;
52081 for(var i = 0, len = rows.length; i < len; i++){
52083 tbody.insertBefore(rows[0], before);
52085 tbody.appendChild(rows[0]);
52092 deleteRows : function(dm, firstRow, lastRow){
52093 if(dm.getRowCount()<1){
52094 this.fireEvent("beforerefresh", this);
52095 this.mainBody.update("");
52096 this.lockedBody.update("");
52097 this.fireEvent("refresh", this);
52099 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
52100 var bt = this.getBodyTable();
52101 var tbody = bt.firstChild;
52102 var rows = bt.rows;
52103 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
52104 tbody.removeChild(rows[firstRow]);
52106 this.stripeRows(firstRow);
52107 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
52111 updateRows : function(dataSource, firstRow, lastRow){
52112 var s = this.getScrollState();
52114 this.restoreScroll(s);
52117 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
52121 this.updateHeaderSortState();
52124 getScrollState : function(){
52126 var sb = this.scroller.dom;
52127 return {left: sb.scrollLeft, top: sb.scrollTop};
52130 stripeRows : function(startRow){
52131 if(!this.grid.stripeRows || this.ds.getCount() < 1){
52134 startRow = startRow || 0;
52135 var rows = this.getBodyTable().rows;
52136 var lrows = this.getLockedTable().rows;
52137 var cls = ' x-grid-row-alt ';
52138 for(var i = startRow, len = rows.length; i < len; i++){
52139 var row = rows[i], lrow = lrows[i];
52140 var isAlt = ((i+1) % 2 == 0);
52141 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
52142 if(isAlt == hasAlt){
52146 row.className += " x-grid-row-alt";
52148 row.className = row.className.replace("x-grid-row-alt", "");
52151 lrow.className = row.className;
52156 restoreScroll : function(state){
52157 //Roo.log('GridView.restoreScroll');
52158 var sb = this.scroller.dom;
52159 sb.scrollLeft = state.left;
52160 sb.scrollTop = state.top;
52164 syncScroll : function(){
52165 //Roo.log('GridView.syncScroll');
52166 var sb = this.scroller.dom;
52167 var sh = this.mainHd.dom;
52168 var bs = this.mainBody.dom;
52169 var lv = this.lockedBody.dom;
52170 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
52171 lv.scrollTop = bs.scrollTop = sb.scrollTop;
52174 handleScroll : function(e){
52176 var sb = this.scroller.dom;
52177 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
52181 handleWheel : function(e){
52182 var d = e.getWheelDelta();
52183 this.scroller.dom.scrollTop -= d*22;
52184 // set this here to prevent jumpy scrolling on large tables
52185 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
52189 renderRows : function(startRow, endRow){
52190 // pull in all the crap needed to render rows
52191 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
52192 var colCount = cm.getColumnCount();
52194 if(ds.getCount() < 1){
52198 // build a map for all the columns
52200 for(var i = 0; i < colCount; i++){
52201 var name = cm.getDataIndex(i);
52203 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
52204 renderer : cm.getRenderer(i),
52205 id : cm.getColumnId(i),
52206 locked : cm.isLocked(i)
52210 startRow = startRow || 0;
52211 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
52213 // records to render
52214 var rs = ds.getRange(startRow, endRow);
52216 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
52219 // As much as I hate to duplicate code, this was branched because FireFox really hates
52220 // [].join("") on strings. The performance difference was substantial enough to
52221 // branch this function
52222 doRender : Roo.isGecko ?
52223 function(cs, rs, ds, startRow, colCount, stripe){
52224 var ts = this.templates, ct = ts.cell, rt = ts.row;
52226 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52228 var hasListener = this.grid.hasListener('rowclass');
52230 for(var j = 0, len = rs.length; j < len; j++){
52231 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
52232 for(var i = 0; i < colCount; i++){
52234 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52236 p.css = p.attr = "";
52237 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52238 if(p.value == undefined || p.value === "") p.value = " ";
52239 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52240 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52242 var markup = ct.apply(p);
52250 if(stripe && ((rowIndex+1) % 2 == 0)){
52251 alt.push("x-grid-row-alt")
52254 alt.push( " x-grid-dirty-row");
52257 if(this.getRowClass){
52258 alt.push(this.getRowClass(r, rowIndex));
52264 rowIndex : rowIndex,
52267 this.grid.fireEvent('rowclass', this, rowcfg);
52268 alt.push(rowcfg.rowClass);
52270 rp.alt = alt.join(" ");
52271 lbuf+= rt.apply(rp);
52273 buf+= rt.apply(rp);
52275 return [lbuf, buf];
52277 function(cs, rs, ds, startRow, colCount, stripe){
52278 var ts = this.templates, ct = ts.cell, rt = ts.row;
52280 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52281 var hasListener = this.grid.hasListener('rowclass');
52284 for(var j = 0, len = rs.length; j < len; j++){
52285 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
52286 for(var i = 0; i < colCount; i++){
52288 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52290 p.css = p.attr = "";
52291 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52292 if(p.value == undefined || p.value === "") p.value = " ";
52293 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52294 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52297 var markup = ct.apply(p);
52299 cb[cb.length] = markup;
52301 lcb[lcb.length] = markup;
52305 if(stripe && ((rowIndex+1) % 2 == 0)){
52306 alt.push( "x-grid-row-alt");
52309 alt.push(" x-grid-dirty-row");
52312 if(this.getRowClass){
52313 alt.push( this.getRowClass(r, rowIndex));
52319 rowIndex : rowIndex,
52322 this.grid.fireEvent('rowclass', this, rowcfg);
52323 alt.push(rowcfg.rowClass);
52325 rp.alt = alt.join(" ");
52326 rp.cells = lcb.join("");
52327 lbuf[lbuf.length] = rt.apply(rp);
52328 rp.cells = cb.join("");
52329 buf[buf.length] = rt.apply(rp);
52331 return [lbuf.join(""), buf.join("")];
52334 renderBody : function(){
52335 var markup = this.renderRows();
52336 var bt = this.templates.body;
52337 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
52341 * Refreshes the grid
52342 * @param {Boolean} headersToo
52344 refresh : function(headersToo){
52345 this.fireEvent("beforerefresh", this);
52346 this.grid.stopEditing();
52347 var result = this.renderBody();
52348 this.lockedBody.update(result[0]);
52349 this.mainBody.update(result[1]);
52350 if(headersToo === true){
52351 this.updateHeaders();
52352 this.updateColumns();
52353 this.updateSplitters();
52354 this.updateHeaderSortState();
52356 this.syncRowHeights();
52358 this.fireEvent("refresh", this);
52361 handleColumnMove : function(cm, oldIndex, newIndex){
52362 this.indexMap = null;
52363 var s = this.getScrollState();
52364 this.refresh(true);
52365 this.restoreScroll(s);
52366 this.afterMove(newIndex);
52369 afterMove : function(colIndex){
52370 if(this.enableMoveAnim && Roo.enableFx){
52371 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
52373 // if multisort - fix sortOrder, and reload..
52374 if (this.grid.dataSource.multiSort) {
52375 // the we can call sort again..
52376 var dm = this.grid.dataSource;
52377 var cm = this.grid.colModel;
52379 for(var i = 0; i < cm.config.length; i++ ) {
52381 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
52382 continue; // dont' bother, it's not in sort list or being set.
52385 so.push(cm.config[i].dataIndex);
52388 dm.load(dm.lastOptions);
52395 updateCell : function(dm, rowIndex, dataIndex){
52396 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
52397 if(typeof colIndex == "undefined"){ // not present in grid
52400 var cm = this.grid.colModel;
52401 var cell = this.getCell(rowIndex, colIndex);
52402 var cellText = this.getCellText(rowIndex, colIndex);
52405 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
52406 id : cm.getColumnId(colIndex),
52407 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
52409 var renderer = cm.getRenderer(colIndex);
52410 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
52411 if(typeof val == "undefined" || val === "") val = " ";
52412 cellText.innerHTML = val;
52413 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
52414 this.syncRowHeights(rowIndex, rowIndex);
52417 calcColumnWidth : function(colIndex, maxRowsToMeasure){
52419 if(this.grid.autoSizeHeaders){
52420 var h = this.getHeaderCellMeasure(colIndex);
52421 maxWidth = Math.max(maxWidth, h.scrollWidth);
52424 if(this.cm.isLocked(colIndex)){
52425 tb = this.getLockedTable();
52428 tb = this.getBodyTable();
52429 index = colIndex - this.cm.getLockedCount();
52432 var rows = tb.rows;
52433 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
52434 for(var i = 0; i < stopIndex; i++){
52435 var cell = rows[i].childNodes[index].firstChild;
52436 maxWidth = Math.max(maxWidth, cell.scrollWidth);
52439 return maxWidth + /*margin for error in IE*/ 5;
52442 * Autofit a column to its content.
52443 * @param {Number} colIndex
52444 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
52446 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
52447 if(this.cm.isHidden(colIndex)){
52448 return; // can't calc a hidden column
52451 var cid = this.cm.getColumnId(colIndex);
52452 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
52453 if(this.grid.autoSizeHeaders){
52454 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
52457 var newWidth = this.calcColumnWidth(colIndex);
52458 this.cm.setColumnWidth(colIndex,
52459 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
52460 if(!suppressEvent){
52461 this.grid.fireEvent("columnresize", colIndex, newWidth);
52466 * Autofits all columns to their content and then expands to fit any extra space in the grid
52468 autoSizeColumns : function(){
52469 var cm = this.grid.colModel;
52470 var colCount = cm.getColumnCount();
52471 for(var i = 0; i < colCount; i++){
52472 this.autoSizeColumn(i, true, true);
52474 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
52477 this.updateColumns();
52483 * Autofits all columns to the grid's width proportionate with their current size
52484 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
52486 fitColumns : function(reserveScrollSpace){
52487 var cm = this.grid.colModel;
52488 var colCount = cm.getColumnCount();
52492 for (i = 0; i < colCount; i++){
52493 if(!cm.isHidden(i) && !cm.isFixed(i)){
52494 w = cm.getColumnWidth(i);
52500 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
52501 if(reserveScrollSpace){
52504 var frac = (avail - cm.getTotalWidth())/width;
52505 while (cols.length){
52508 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
52510 this.updateColumns();
52514 onRowSelect : function(rowIndex){
52515 var row = this.getRowComposite(rowIndex);
52516 row.addClass("x-grid-row-selected");
52519 onRowDeselect : function(rowIndex){
52520 var row = this.getRowComposite(rowIndex);
52521 row.removeClass("x-grid-row-selected");
52524 onCellSelect : function(row, col){
52525 var cell = this.getCell(row, col);
52527 Roo.fly(cell).addClass("x-grid-cell-selected");
52531 onCellDeselect : function(row, col){
52532 var cell = this.getCell(row, col);
52534 Roo.fly(cell).removeClass("x-grid-cell-selected");
52538 updateHeaderSortState : function(){
52540 // sort state can be single { field: xxx, direction : yyy}
52541 // or { xxx=>ASC , yyy : DESC ..... }
52544 if (!this.ds.multiSort) {
52545 var state = this.ds.getSortState();
52549 mstate[state.field] = state.direction;
52550 // FIXME... - this is not used here.. but might be elsewhere..
52551 this.sortState = state;
52554 mstate = this.ds.sortToggle;
52556 //remove existing sort classes..
52558 var sc = this.sortClasses;
52559 var hds = this.el.select(this.headerSelector).removeClass(sc);
52561 for(var f in mstate) {
52563 var sortColumn = this.cm.findColumnIndex(f);
52565 if(sortColumn != -1){
52566 var sortDir = mstate[f];
52567 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
52576 handleHeaderClick : function(g, index){
52577 if(this.headersDisabled){
52580 var dm = g.dataSource, cm = g.colModel;
52581 if(!cm.isSortable(index)){
52586 if (dm.multiSort) {
52587 // update the sortOrder
52589 for(var i = 0; i < cm.config.length; i++ ) {
52591 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
52592 continue; // dont' bother, it's not in sort list or being set.
52595 so.push(cm.config[i].dataIndex);
52601 dm.sort(cm.getDataIndex(index));
52605 destroy : function(){
52607 this.colMenu.removeAll();
52608 Roo.menu.MenuMgr.unregister(this.colMenu);
52609 this.colMenu.getEl().remove();
52610 delete this.colMenu;
52613 this.hmenu.removeAll();
52614 Roo.menu.MenuMgr.unregister(this.hmenu);
52615 this.hmenu.getEl().remove();
52618 if(this.grid.enableColumnMove){
52619 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
52621 for(var dd in dds){
52622 if(!dds[dd].config.isTarget && dds[dd].dragElId){
52623 var elid = dds[dd].dragElId;
52625 Roo.get(elid).remove();
52626 } else if(dds[dd].config.isTarget){
52627 dds[dd].proxyTop.remove();
52628 dds[dd].proxyBottom.remove();
52631 if(Roo.dd.DDM.locationCache[dd]){
52632 delete Roo.dd.DDM.locationCache[dd];
52635 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
52638 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
52639 this.bind(null, null);
52640 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
52643 handleLockChange : function(){
52644 this.refresh(true);
52647 onDenyColumnLock : function(){
52651 onDenyColumnHide : function(){
52655 handleHdMenuClick : function(item){
52656 var index = this.hdCtxIndex;
52657 var cm = this.cm, ds = this.ds;
52660 ds.sort(cm.getDataIndex(index), "ASC");
52663 ds.sort(cm.getDataIndex(index), "DESC");
52666 var lc = cm.getLockedCount();
52667 if(cm.getColumnCount(true) <= lc+1){
52668 this.onDenyColumnLock();
52672 cm.setLocked(index, true, true);
52673 cm.moveColumn(index, lc);
52674 this.grid.fireEvent("columnmove", index, lc);
52676 cm.setLocked(index, true);
52680 var lc = cm.getLockedCount();
52681 if((lc-1) != index){
52682 cm.setLocked(index, false, true);
52683 cm.moveColumn(index, lc-1);
52684 this.grid.fireEvent("columnmove", index, lc-1);
52686 cm.setLocked(index, false);
52690 index = cm.getIndexById(item.id.substr(4));
52692 if(item.checked && cm.getColumnCount(true) <= 1){
52693 this.onDenyColumnHide();
52696 cm.setHidden(index, item.checked);
52702 beforeColMenuShow : function(){
52703 var cm = this.cm, colCount = cm.getColumnCount();
52704 this.colMenu.removeAll();
52705 for(var i = 0; i < colCount; i++){
52706 this.colMenu.add(new Roo.menu.CheckItem({
52707 id: "col-"+cm.getColumnId(i),
52708 text: cm.getColumnHeader(i),
52709 checked: !cm.isHidden(i),
52715 handleHdCtx : function(g, index, e){
52717 var hd = this.getHeaderCell(index);
52718 this.hdCtxIndex = index;
52719 var ms = this.hmenu.items, cm = this.cm;
52720 ms.get("asc").setDisabled(!cm.isSortable(index));
52721 ms.get("desc").setDisabled(!cm.isSortable(index));
52722 if(this.grid.enableColLock !== false){
52723 ms.get("lock").setDisabled(cm.isLocked(index));
52724 ms.get("unlock").setDisabled(!cm.isLocked(index));
52726 this.hmenu.show(hd, "tl-bl");
52729 handleHdOver : function(e){
52730 var hd = this.findHeaderCell(e.getTarget());
52731 if(hd && !this.headersDisabled){
52732 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
52733 this.fly(hd).addClass("x-grid-hd-over");
52738 handleHdOut : function(e){
52739 var hd = this.findHeaderCell(e.getTarget());
52741 this.fly(hd).removeClass("x-grid-hd-over");
52745 handleSplitDblClick : function(e, t){
52746 var i = this.getCellIndex(t);
52747 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
52748 this.autoSizeColumn(i, true);
52753 render : function(){
52756 var colCount = cm.getColumnCount();
52758 if(this.grid.monitorWindowResize === true){
52759 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52761 var header = this.renderHeaders();
52762 var body = this.templates.body.apply({rows:""});
52763 var html = this.templates.master.apply({
52766 lockedHeader: header[0],
52770 //this.updateColumns();
52772 this.grid.getGridEl().dom.innerHTML = html;
52774 this.initElements();
52776 // a kludge to fix the random scolling effect in webkit
52777 this.el.on("scroll", function() {
52778 this.el.dom.scrollTop=0; // hopefully not recursive..
52781 this.scroller.on("scroll", this.handleScroll, this);
52782 this.lockedBody.on("mousewheel", this.handleWheel, this);
52783 this.mainBody.on("mousewheel", this.handleWheel, this);
52785 this.mainHd.on("mouseover", this.handleHdOver, this);
52786 this.mainHd.on("mouseout", this.handleHdOut, this);
52787 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
52788 {delegate: "."+this.splitClass});
52790 this.lockedHd.on("mouseover", this.handleHdOver, this);
52791 this.lockedHd.on("mouseout", this.handleHdOut, this);
52792 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
52793 {delegate: "."+this.splitClass});
52795 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
52796 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52799 this.updateSplitters();
52801 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
52802 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52803 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52806 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
52807 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
52809 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
52810 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
52812 if(this.grid.enableColLock !== false){
52813 this.hmenu.add('-',
52814 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
52815 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
52818 if(this.grid.enableColumnHide !== false){
52820 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
52821 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
52822 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
52824 this.hmenu.add('-',
52825 {id:"columns", text: this.columnsText, menu: this.colMenu}
52828 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
52830 this.grid.on("headercontextmenu", this.handleHdCtx, this);
52833 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
52834 this.dd = new Roo.grid.GridDragZone(this.grid, {
52835 ddGroup : this.grid.ddGroup || 'GridDD'
52841 for(var i = 0; i < colCount; i++){
52842 if(cm.isHidden(i)){
52843 this.hideColumn(i);
52845 if(cm.config[i].align){
52846 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
52847 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
52851 this.updateHeaderSortState();
52853 this.beforeInitialResize();
52856 // two part rendering gives faster view to the user
52857 this.renderPhase2.defer(1, this);
52860 renderPhase2 : function(){
52861 // render the rows now
52863 if(this.grid.autoSizeColumns){
52864 this.autoSizeColumns();
52868 beforeInitialResize : function(){
52872 onColumnSplitterMoved : function(i, w){
52873 this.userResized = true;
52874 var cm = this.grid.colModel;
52875 cm.setColumnWidth(i, w, true);
52876 var cid = cm.getColumnId(i);
52877 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
52878 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
52879 this.updateSplitters();
52881 this.grid.fireEvent("columnresize", i, w);
52884 syncRowHeights : function(startIndex, endIndex){
52885 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
52886 startIndex = startIndex || 0;
52887 var mrows = this.getBodyTable().rows;
52888 var lrows = this.getLockedTable().rows;
52889 var len = mrows.length-1;
52890 endIndex = Math.min(endIndex || len, len);
52891 for(var i = startIndex; i <= endIndex; i++){
52892 var m = mrows[i], l = lrows[i];
52893 var h = Math.max(m.offsetHeight, l.offsetHeight);
52894 m.style.height = l.style.height = h + "px";
52899 layout : function(initialRender, is2ndPass){
52901 var auto = g.autoHeight;
52902 var scrollOffset = 16;
52903 var c = g.getGridEl(), cm = this.cm,
52904 expandCol = g.autoExpandColumn,
52906 //c.beginMeasure();
52908 if(!c.dom.offsetWidth){ // display:none?
52910 this.lockedWrap.show();
52911 this.mainWrap.show();
52916 var hasLock = this.cm.isLocked(0);
52918 var tbh = this.headerPanel.getHeight();
52919 var bbh = this.footerPanel.getHeight();
52922 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
52923 var newHeight = ch + c.getBorderWidth("tb");
52925 newHeight = Math.min(g.maxHeight, newHeight);
52927 c.setHeight(newHeight);
52931 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
52934 var s = this.scroller;
52936 var csize = c.getSize(true);
52938 this.el.setSize(csize.width, csize.height);
52940 this.headerPanel.setWidth(csize.width);
52941 this.footerPanel.setWidth(csize.width);
52943 var hdHeight = this.mainHd.getHeight();
52944 var vw = csize.width;
52945 var vh = csize.height - (tbh + bbh);
52949 var bt = this.getBodyTable();
52950 var ltWidth = hasLock ?
52951 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
52953 var scrollHeight = bt.offsetHeight;
52954 var scrollWidth = ltWidth + bt.offsetWidth;
52955 var vscroll = false, hscroll = false;
52957 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
52959 var lw = this.lockedWrap, mw = this.mainWrap;
52960 var lb = this.lockedBody, mb = this.mainBody;
52962 setTimeout(function(){
52963 var t = s.dom.offsetTop;
52964 var w = s.dom.clientWidth,
52965 h = s.dom.clientHeight;
52968 lw.setSize(ltWidth, h);
52970 mw.setLeftTop(ltWidth, t);
52971 mw.setSize(w-ltWidth, h);
52973 lb.setHeight(h-hdHeight);
52974 mb.setHeight(h-hdHeight);
52976 if(is2ndPass !== true && !gv.userResized && expandCol){
52977 // high speed resize without full column calculation
52979 var ci = cm.getIndexById(expandCol);
52981 ci = cm.findColumnIndex(expandCol);
52983 ci = Math.max(0, ci); // make sure it's got at least the first col.
52984 var expandId = cm.getColumnId(ci);
52985 var tw = cm.getTotalWidth(false);
52986 var currentWidth = cm.getColumnWidth(ci);
52987 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
52988 if(currentWidth != cw){
52989 cm.setColumnWidth(ci, cw, true);
52990 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
52991 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
52992 gv.updateSplitters();
52993 gv.layout(false, true);
53005 onWindowResize : function(){
53006 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
53012 appendFooter : function(parentEl){
53016 sortAscText : "Sort Ascending",
53017 sortDescText : "Sort Descending",
53018 lockText : "Lock Column",
53019 unlockText : "Unlock Column",
53020 columnsText : "Columns"
53024 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
53025 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
53026 this.proxy.el.addClass('x-grid3-col-dd');
53029 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
53030 handleMouseDown : function(e){
53034 callHandleMouseDown : function(e){
53035 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
53040 * Ext JS Library 1.1.1
53041 * Copyright(c) 2006-2007, Ext JS, LLC.
53043 * Originally Released Under LGPL - original licence link has changed is not relivant.
53046 * <script type="text/javascript">
53050 // This is a support class used internally by the Grid components
53051 Roo.grid.SplitDragZone = function(grid, hd, hd2){
53053 this.view = grid.getView();
53054 this.proxy = this.view.resizeProxy;
53055 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
53056 "gridSplitters" + this.grid.getGridEl().id, {
53057 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
53059 this.setHandleElId(Roo.id(hd));
53060 this.setOuterHandleElId(Roo.id(hd2));
53061 this.scroll = false;
53063 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
53064 fly: Roo.Element.fly,
53066 b4StartDrag : function(x, y){
53067 this.view.headersDisabled = true;
53068 this.proxy.setHeight(this.view.mainWrap.getHeight());
53069 var w = this.cm.getColumnWidth(this.cellIndex);
53070 var minw = Math.max(w-this.grid.minColumnWidth, 0);
53071 this.resetConstraints();
53072 this.setXConstraint(minw, 1000);
53073 this.setYConstraint(0, 0);
53074 this.minX = x - minw;
53075 this.maxX = x + 1000;
53077 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
53081 handleMouseDown : function(e){
53082 ev = Roo.EventObject.setEvent(e);
53083 var t = this.fly(ev.getTarget());
53084 if(t.hasClass("x-grid-split")){
53085 this.cellIndex = this.view.getCellIndex(t.dom);
53086 this.split = t.dom;
53087 this.cm = this.grid.colModel;
53088 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
53089 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
53094 endDrag : function(e){
53095 this.view.headersDisabled = false;
53096 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
53097 var diff = endX - this.startPos;
53098 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
53101 autoOffset : function(){
53102 this.setDelta(0,0);
53106 * Ext JS Library 1.1.1
53107 * Copyright(c) 2006-2007, Ext JS, LLC.
53109 * Originally Released Under LGPL - original licence link has changed is not relivant.
53112 * <script type="text/javascript">
53116 // This is a support class used internally by the Grid components
53117 Roo.grid.GridDragZone = function(grid, config){
53118 this.view = grid.getView();
53119 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
53120 if(this.view.lockedBody){
53121 this.setHandleElId(Roo.id(this.view.mainBody.dom));
53122 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
53124 this.scroll = false;
53126 this.ddel = document.createElement('div');
53127 this.ddel.className = 'x-grid-dd-wrap';
53130 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
53131 ddGroup : "GridDD",
53133 getDragData : function(e){
53134 var t = Roo.lib.Event.getTarget(e);
53135 var rowIndex = this.view.findRowIndex(t);
53136 var sm = this.grid.selModel;
53138 //Roo.log(rowIndex);
53140 if (sm.getSelectedCell) {
53141 // cell selection..
53142 if (!sm.getSelectedCell()) {
53145 if (rowIndex != sm.getSelectedCell()[0]) {
53151 if(rowIndex !== false){
53156 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
53158 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
53161 if (e.hasModifier()){
53162 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
53165 Roo.log("getDragData");
53170 rowIndex: rowIndex,
53171 selections:sm.getSelections ? sm.getSelections() : (
53172 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
53179 onInitDrag : function(e){
53180 var data = this.dragData;
53181 this.ddel.innerHTML = this.grid.getDragDropText();
53182 this.proxy.update(this.ddel);
53183 // fire start drag?
53186 afterRepair : function(){
53187 this.dragging = false;
53190 getRepairXY : function(e, data){
53194 onEndDrag : function(data, e){
53198 onValidDrop : function(dd, e, id){
53203 beforeInvalidDrop : function(e, id){
53208 * Ext JS Library 1.1.1
53209 * Copyright(c) 2006-2007, Ext JS, LLC.
53211 * Originally Released Under LGPL - original licence link has changed is not relivant.
53214 * <script type="text/javascript">
53219 * @class Roo.grid.ColumnModel
53220 * @extends Roo.util.Observable
53221 * This is the default implementation of a ColumnModel used by the Grid. It defines
53222 * the columns in the grid.
53225 var colModel = new Roo.grid.ColumnModel([
53226 {header: "Ticker", width: 60, sortable: true, locked: true},
53227 {header: "Company Name", width: 150, sortable: true},
53228 {header: "Market Cap.", width: 100, sortable: true},
53229 {header: "$ Sales", width: 100, sortable: true, renderer: money},
53230 {header: "Employees", width: 100, sortable: true, resizable: false}
53235 * The config options listed for this class are options which may appear in each
53236 * individual column definition.
53237 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
53239 * @param {Object} config An Array of column config objects. See this class's
53240 * config objects for details.
53242 Roo.grid.ColumnModel = function(config){
53244 * The config passed into the constructor
53246 this.config = config;
53249 // if no id, create one
53250 // if the column does not have a dataIndex mapping,
53251 // map it to the order it is in the config
53252 for(var i = 0, len = config.length; i < len; i++){
53254 if(typeof c.dataIndex == "undefined"){
53257 if(typeof c.renderer == "string"){
53258 c.renderer = Roo.util.Format[c.renderer];
53260 if(typeof c.id == "undefined"){
53263 if(c.editor && c.editor.xtype){
53264 c.editor = Roo.factory(c.editor, Roo.grid);
53266 if(c.editor && c.editor.isFormField){
53267 c.editor = new Roo.grid.GridEditor(c.editor);
53269 this.lookup[c.id] = c;
53273 * The width of columns which have no width specified (defaults to 100)
53276 this.defaultWidth = 100;
53279 * Default sortable of columns which have no sortable specified (defaults to false)
53282 this.defaultSortable = false;
53286 * @event widthchange
53287 * Fires when the width of a column changes.
53288 * @param {ColumnModel} this
53289 * @param {Number} columnIndex The column index
53290 * @param {Number} newWidth The new width
53292 "widthchange": true,
53294 * @event headerchange
53295 * Fires when the text of a header changes.
53296 * @param {ColumnModel} this
53297 * @param {Number} columnIndex The column index
53298 * @param {Number} newText The new header text
53300 "headerchange": true,
53302 * @event hiddenchange
53303 * Fires when a column is hidden or "unhidden".
53304 * @param {ColumnModel} this
53305 * @param {Number} columnIndex The column index
53306 * @param {Boolean} hidden true if hidden, false otherwise
53308 "hiddenchange": true,
53310 * @event columnmoved
53311 * Fires when a column is moved.
53312 * @param {ColumnModel} this
53313 * @param {Number} oldIndex
53314 * @param {Number} newIndex
53316 "columnmoved" : true,
53318 * @event columlockchange
53319 * Fires when a column's locked state is changed
53320 * @param {ColumnModel} this
53321 * @param {Number} colIndex
53322 * @param {Boolean} locked true if locked
53324 "columnlockchange" : true
53326 Roo.grid.ColumnModel.superclass.constructor.call(this);
53328 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
53330 * @cfg {String} header The header text to display in the Grid view.
53333 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
53334 * {@link Roo.data.Record} definition from which to draw the column's value. If not
53335 * specified, the column's index is used as an index into the Record's data Array.
53338 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
53339 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
53342 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
53343 * Defaults to the value of the {@link #defaultSortable} property.
53344 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
53347 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
53350 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
53353 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
53356 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
53359 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
53360 * given the cell's data value. See {@link #setRenderer}. If not specified, the
53361 * default renderer uses the raw data value.
53364 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
53367 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
53371 * Returns the id of the column at the specified index.
53372 * @param {Number} index The column index
53373 * @return {String} the id
53375 getColumnId : function(index){
53376 return this.config[index].id;
53380 * Returns the column for a specified id.
53381 * @param {String} id The column id
53382 * @return {Object} the column
53384 getColumnById : function(id){
53385 return this.lookup[id];
53390 * Returns the column for a specified dataIndex.
53391 * @param {String} dataIndex The column dataIndex
53392 * @return {Object|Boolean} the column or false if not found
53394 getColumnByDataIndex: function(dataIndex){
53395 var index = this.findColumnIndex(dataIndex);
53396 return index > -1 ? this.config[index] : false;
53400 * Returns the index for a specified column id.
53401 * @param {String} id The column id
53402 * @return {Number} the index, or -1 if not found
53404 getIndexById : function(id){
53405 for(var i = 0, len = this.config.length; i < len; i++){
53406 if(this.config[i].id == id){
53414 * Returns the index for a specified column dataIndex.
53415 * @param {String} dataIndex The column dataIndex
53416 * @return {Number} the index, or -1 if not found
53419 findColumnIndex : function(dataIndex){
53420 for(var i = 0, len = this.config.length; i < len; i++){
53421 if(this.config[i].dataIndex == dataIndex){
53429 moveColumn : function(oldIndex, newIndex){
53430 var c = this.config[oldIndex];
53431 this.config.splice(oldIndex, 1);
53432 this.config.splice(newIndex, 0, c);
53433 this.dataMap = null;
53434 this.fireEvent("columnmoved", this, oldIndex, newIndex);
53437 isLocked : function(colIndex){
53438 return this.config[colIndex].locked === true;
53441 setLocked : function(colIndex, value, suppressEvent){
53442 if(this.isLocked(colIndex) == value){
53445 this.config[colIndex].locked = value;
53446 if(!suppressEvent){
53447 this.fireEvent("columnlockchange", this, colIndex, value);
53451 getTotalLockedWidth : function(){
53452 var totalWidth = 0;
53453 for(var i = 0; i < this.config.length; i++){
53454 if(this.isLocked(i) && !this.isHidden(i)){
53455 this.totalWidth += this.getColumnWidth(i);
53461 getLockedCount : function(){
53462 for(var i = 0, len = this.config.length; i < len; i++){
53463 if(!this.isLocked(i)){
53470 * Returns the number of columns.
53473 getColumnCount : function(visibleOnly){
53474 if(visibleOnly === true){
53476 for(var i = 0, len = this.config.length; i < len; i++){
53477 if(!this.isHidden(i)){
53483 return this.config.length;
53487 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
53488 * @param {Function} fn
53489 * @param {Object} scope (optional)
53490 * @return {Array} result
53492 getColumnsBy : function(fn, scope){
53494 for(var i = 0, len = this.config.length; i < len; i++){
53495 var c = this.config[i];
53496 if(fn.call(scope||this, c, i) === true){
53504 * Returns true if the specified column is sortable.
53505 * @param {Number} col The column index
53506 * @return {Boolean}
53508 isSortable : function(col){
53509 if(typeof this.config[col].sortable == "undefined"){
53510 return this.defaultSortable;
53512 return this.config[col].sortable;
53516 * Returns the rendering (formatting) function defined for the column.
53517 * @param {Number} col The column index.
53518 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
53520 getRenderer : function(col){
53521 if(!this.config[col].renderer){
53522 return Roo.grid.ColumnModel.defaultRenderer;
53524 return this.config[col].renderer;
53528 * Sets the rendering (formatting) function for a column.
53529 * @param {Number} col The column index
53530 * @param {Function} fn The function to use to process the cell's raw data
53531 * to return HTML markup for the grid view. The render function is called with
53532 * the following parameters:<ul>
53533 * <li>Data value.</li>
53534 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
53535 * <li>css A CSS style string to apply to the table cell.</li>
53536 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
53537 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
53538 * <li>Row index</li>
53539 * <li>Column index</li>
53540 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
53542 setRenderer : function(col, fn){
53543 this.config[col].renderer = fn;
53547 * Returns the width for the specified column.
53548 * @param {Number} col The column index
53551 getColumnWidth : function(col){
53552 return this.config[col].width * 1 || this.defaultWidth;
53556 * Sets the width for a column.
53557 * @param {Number} col The column index
53558 * @param {Number} width The new width
53560 setColumnWidth : function(col, width, suppressEvent){
53561 this.config[col].width = width;
53562 this.totalWidth = null;
53563 if(!suppressEvent){
53564 this.fireEvent("widthchange", this, col, width);
53569 * Returns the total width of all columns.
53570 * @param {Boolean} includeHidden True to include hidden column widths
53573 getTotalWidth : function(includeHidden){
53574 if(!this.totalWidth){
53575 this.totalWidth = 0;
53576 for(var i = 0, len = this.config.length; i < len; i++){
53577 if(includeHidden || !this.isHidden(i)){
53578 this.totalWidth += this.getColumnWidth(i);
53582 return this.totalWidth;
53586 * Returns the header for the specified column.
53587 * @param {Number} col The column index
53590 getColumnHeader : function(col){
53591 return this.config[col].header;
53595 * Sets the header for a column.
53596 * @param {Number} col The column index
53597 * @param {String} header The new header
53599 setColumnHeader : function(col, header){
53600 this.config[col].header = header;
53601 this.fireEvent("headerchange", this, col, header);
53605 * Returns the tooltip for the specified column.
53606 * @param {Number} col The column index
53609 getColumnTooltip : function(col){
53610 return this.config[col].tooltip;
53613 * Sets the tooltip for a column.
53614 * @param {Number} col The column index
53615 * @param {String} tooltip The new tooltip
53617 setColumnTooltip : function(col, tooltip){
53618 this.config[col].tooltip = tooltip;
53622 * Returns the dataIndex for the specified column.
53623 * @param {Number} col The column index
53626 getDataIndex : function(col){
53627 return this.config[col].dataIndex;
53631 * Sets the dataIndex for a column.
53632 * @param {Number} col The column index
53633 * @param {Number} dataIndex The new dataIndex
53635 setDataIndex : function(col, dataIndex){
53636 this.config[col].dataIndex = dataIndex;
53642 * Returns true if the cell is editable.
53643 * @param {Number} colIndex The column index
53644 * @param {Number} rowIndex The row index
53645 * @return {Boolean}
53647 isCellEditable : function(colIndex, rowIndex){
53648 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
53652 * Returns the editor defined for the cell/column.
53653 * return false or null to disable editing.
53654 * @param {Number} colIndex The column index
53655 * @param {Number} rowIndex The row index
53658 getCellEditor : function(colIndex, rowIndex){
53659 return this.config[colIndex].editor;
53663 * Sets if a column is editable.
53664 * @param {Number} col The column index
53665 * @param {Boolean} editable True if the column is editable
53667 setEditable : function(col, editable){
53668 this.config[col].editable = editable;
53673 * Returns true if the column is hidden.
53674 * @param {Number} colIndex The column index
53675 * @return {Boolean}
53677 isHidden : function(colIndex){
53678 return this.config[colIndex].hidden;
53683 * Returns true if the column width cannot be changed
53685 isFixed : function(colIndex){
53686 return this.config[colIndex].fixed;
53690 * Returns true if the column can be resized
53691 * @return {Boolean}
53693 isResizable : function(colIndex){
53694 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
53697 * Sets if a column is hidden.
53698 * @param {Number} colIndex The column index
53699 * @param {Boolean} hidden True if the column is hidden
53701 setHidden : function(colIndex, hidden){
53702 this.config[colIndex].hidden = hidden;
53703 this.totalWidth = null;
53704 this.fireEvent("hiddenchange", this, colIndex, hidden);
53708 * Sets the editor for a column.
53709 * @param {Number} col The column index
53710 * @param {Object} editor The editor object
53712 setEditor : function(col, editor){
53713 this.config[col].editor = editor;
53717 Roo.grid.ColumnModel.defaultRenderer = function(value){
53718 if(typeof value == "string" && value.length < 1){
53724 // Alias for backwards compatibility
53725 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
53728 * Ext JS Library 1.1.1
53729 * Copyright(c) 2006-2007, Ext JS, LLC.
53731 * Originally Released Under LGPL - original licence link has changed is not relivant.
53734 * <script type="text/javascript">
53738 * @class Roo.grid.AbstractSelectionModel
53739 * @extends Roo.util.Observable
53740 * Abstract base class for grid SelectionModels. It provides the interface that should be
53741 * implemented by descendant classes. This class should not be directly instantiated.
53744 Roo.grid.AbstractSelectionModel = function(){
53745 this.locked = false;
53746 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
53749 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
53750 /** @ignore Called by the grid automatically. Do not call directly. */
53751 init : function(grid){
53757 * Locks the selections.
53760 this.locked = true;
53764 * Unlocks the selections.
53766 unlock : function(){
53767 this.locked = false;
53771 * Returns true if the selections are locked.
53772 * @return {Boolean}
53774 isLocked : function(){
53775 return this.locked;
53779 * Ext JS Library 1.1.1
53780 * Copyright(c) 2006-2007, Ext JS, LLC.
53782 * Originally Released Under LGPL - original licence link has changed is not relivant.
53785 * <script type="text/javascript">
53788 * @extends Roo.grid.AbstractSelectionModel
53789 * @class Roo.grid.RowSelectionModel
53790 * The default SelectionModel used by {@link Roo.grid.Grid}.
53791 * It supports multiple selections and keyboard selection/navigation.
53793 * @param {Object} config
53795 Roo.grid.RowSelectionModel = function(config){
53796 Roo.apply(this, config);
53797 this.selections = new Roo.util.MixedCollection(false, function(o){
53802 this.lastActive = false;
53806 * @event selectionchange
53807 * Fires when the selection changes
53808 * @param {SelectionModel} this
53810 "selectionchange" : true,
53812 * @event afterselectionchange
53813 * Fires after the selection changes (eg. by key press or clicking)
53814 * @param {SelectionModel} this
53816 "afterselectionchange" : true,
53818 * @event beforerowselect
53819 * Fires when a row is selected being selected, return false to cancel.
53820 * @param {SelectionModel} this
53821 * @param {Number} rowIndex The selected index
53822 * @param {Boolean} keepExisting False if other selections will be cleared
53824 "beforerowselect" : true,
53827 * Fires when a row is selected.
53828 * @param {SelectionModel} this
53829 * @param {Number} rowIndex The selected index
53830 * @param {Roo.data.Record} r The record
53832 "rowselect" : true,
53834 * @event rowdeselect
53835 * Fires when a row is deselected.
53836 * @param {SelectionModel} this
53837 * @param {Number} rowIndex The selected index
53839 "rowdeselect" : true
53841 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
53842 this.locked = false;
53845 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
53847 * @cfg {Boolean} singleSelect
53848 * True to allow selection of only one row at a time (defaults to false)
53850 singleSelect : false,
53853 initEvents : function(){
53855 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
53856 this.grid.on("mousedown", this.handleMouseDown, this);
53857 }else{ // allow click to work like normal
53858 this.grid.on("rowclick", this.handleDragableRowClick, this);
53861 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
53862 "up" : function(e){
53864 this.selectPrevious(e.shiftKey);
53865 }else if(this.last !== false && this.lastActive !== false){
53866 var last = this.last;
53867 this.selectRange(this.last, this.lastActive-1);
53868 this.grid.getView().focusRow(this.lastActive);
53869 if(last !== false){
53873 this.selectFirstRow();
53875 this.fireEvent("afterselectionchange", this);
53877 "down" : function(e){
53879 this.selectNext(e.shiftKey);
53880 }else if(this.last !== false && this.lastActive !== false){
53881 var last = this.last;
53882 this.selectRange(this.last, this.lastActive+1);
53883 this.grid.getView().focusRow(this.lastActive);
53884 if(last !== false){
53888 this.selectFirstRow();
53890 this.fireEvent("afterselectionchange", this);
53895 var view = this.grid.view;
53896 view.on("refresh", this.onRefresh, this);
53897 view.on("rowupdated", this.onRowUpdated, this);
53898 view.on("rowremoved", this.onRemove, this);
53902 onRefresh : function(){
53903 var ds = this.grid.dataSource, i, v = this.grid.view;
53904 var s = this.selections;
53905 s.each(function(r){
53906 if((i = ds.indexOfId(r.id)) != -1){
53915 onRemove : function(v, index, r){
53916 this.selections.remove(r);
53920 onRowUpdated : function(v, index, r){
53921 if(this.isSelected(r)){
53922 v.onRowSelect(index);
53928 * @param {Array} records The records to select
53929 * @param {Boolean} keepExisting (optional) True to keep existing selections
53931 selectRecords : function(records, keepExisting){
53933 this.clearSelections();
53935 var ds = this.grid.dataSource;
53936 for(var i = 0, len = records.length; i < len; i++){
53937 this.selectRow(ds.indexOf(records[i]), true);
53942 * Gets the number of selected rows.
53945 getCount : function(){
53946 return this.selections.length;
53950 * Selects the first row in the grid.
53952 selectFirstRow : function(){
53957 * Select the last row.
53958 * @param {Boolean} keepExisting (optional) True to keep existing selections
53960 selectLastRow : function(keepExisting){
53961 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
53965 * Selects the row immediately following the last selected row.
53966 * @param {Boolean} keepExisting (optional) True to keep existing selections
53968 selectNext : function(keepExisting){
53969 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
53970 this.selectRow(this.last+1, keepExisting);
53971 this.grid.getView().focusRow(this.last);
53976 * Selects the row that precedes the last selected row.
53977 * @param {Boolean} keepExisting (optional) True to keep existing selections
53979 selectPrevious : function(keepExisting){
53981 this.selectRow(this.last-1, keepExisting);
53982 this.grid.getView().focusRow(this.last);
53987 * Returns the selected records
53988 * @return {Array} Array of selected records
53990 getSelections : function(){
53991 return [].concat(this.selections.items);
53995 * Returns the first selected record.
53998 getSelected : function(){
53999 return this.selections.itemAt(0);
54004 * Clears all selections.
54006 clearSelections : function(fast){
54007 if(this.locked) return;
54009 var ds = this.grid.dataSource;
54010 var s = this.selections;
54011 s.each(function(r){
54012 this.deselectRow(ds.indexOfId(r.id));
54016 this.selections.clear();
54023 * Selects all rows.
54025 selectAll : function(){
54026 if(this.locked) return;
54027 this.selections.clear();
54028 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
54029 this.selectRow(i, true);
54034 * Returns True if there is a selection.
54035 * @return {Boolean}
54037 hasSelection : function(){
54038 return this.selections.length > 0;
54042 * Returns True if the specified row is selected.
54043 * @param {Number/Record} record The record or index of the record to check
54044 * @return {Boolean}
54046 isSelected : function(index){
54047 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
54048 return (r && this.selections.key(r.id) ? true : false);
54052 * Returns True if the specified record id is selected.
54053 * @param {String} id The id of record to check
54054 * @return {Boolean}
54056 isIdSelected : function(id){
54057 return (this.selections.key(id) ? true : false);
54061 handleMouseDown : function(e, t){
54062 var view = this.grid.getView(), rowIndex;
54063 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
54066 if(e.shiftKey && this.last !== false){
54067 var last = this.last;
54068 this.selectRange(last, rowIndex, e.ctrlKey);
54069 this.last = last; // reset the last
54070 view.focusRow(rowIndex);
54072 var isSelected = this.isSelected(rowIndex);
54073 if(e.button !== 0 && isSelected){
54074 view.focusRow(rowIndex);
54075 }else if(e.ctrlKey && isSelected){
54076 this.deselectRow(rowIndex);
54077 }else if(!isSelected){
54078 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
54079 view.focusRow(rowIndex);
54082 this.fireEvent("afterselectionchange", this);
54085 handleDragableRowClick : function(grid, rowIndex, e)
54087 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
54088 this.selectRow(rowIndex, false);
54089 grid.view.focusRow(rowIndex);
54090 this.fireEvent("afterselectionchange", this);
54095 * Selects multiple rows.
54096 * @param {Array} rows Array of the indexes of the row to select
54097 * @param {Boolean} keepExisting (optional) True to keep existing selections
54099 selectRows : function(rows, keepExisting){
54101 this.clearSelections();
54103 for(var i = 0, len = rows.length; i < len; i++){
54104 this.selectRow(rows[i], true);
54109 * Selects a range of rows. All rows in between startRow and endRow are also selected.
54110 * @param {Number} startRow The index of the first row in the range
54111 * @param {Number} endRow The index of the last row in the range
54112 * @param {Boolean} keepExisting (optional) True to retain existing selections
54114 selectRange : function(startRow, endRow, keepExisting){
54115 if(this.locked) return;
54117 this.clearSelections();
54119 if(startRow <= endRow){
54120 for(var i = startRow; i <= endRow; i++){
54121 this.selectRow(i, true);
54124 for(var i = startRow; i >= endRow; i--){
54125 this.selectRow(i, true);
54131 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
54132 * @param {Number} startRow The index of the first row in the range
54133 * @param {Number} endRow The index of the last row in the range
54135 deselectRange : function(startRow, endRow, preventViewNotify){
54136 if(this.locked) return;
54137 for(var i = startRow; i <= endRow; i++){
54138 this.deselectRow(i, preventViewNotify);
54144 * @param {Number} row The index of the row to select
54145 * @param {Boolean} keepExisting (optional) True to keep existing selections
54147 selectRow : function(index, keepExisting, preventViewNotify){
54148 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
54149 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
54150 if(!keepExisting || this.singleSelect){
54151 this.clearSelections();
54153 var r = this.grid.dataSource.getAt(index);
54154 this.selections.add(r);
54155 this.last = this.lastActive = index;
54156 if(!preventViewNotify){
54157 this.grid.getView().onRowSelect(index);
54159 this.fireEvent("rowselect", this, index, r);
54160 this.fireEvent("selectionchange", this);
54166 * @param {Number} row The index of the row to deselect
54168 deselectRow : function(index, preventViewNotify){
54169 if(this.locked) return;
54170 if(this.last == index){
54173 if(this.lastActive == index){
54174 this.lastActive = false;
54176 var r = this.grid.dataSource.getAt(index);
54177 this.selections.remove(r);
54178 if(!preventViewNotify){
54179 this.grid.getView().onRowDeselect(index);
54181 this.fireEvent("rowdeselect", this, index);
54182 this.fireEvent("selectionchange", this);
54186 restoreLast : function(){
54188 this.last = this._last;
54193 acceptsNav : function(row, col, cm){
54194 return !cm.isHidden(col) && cm.isCellEditable(col, row);
54198 onEditorKey : function(field, e){
54199 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
54204 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
54206 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54208 }else if(k == e.ENTER && !e.ctrlKey){
54212 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
54214 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
54216 }else if(k == e.ESC){
54220 g.startEditing(newCell[0], newCell[1]);
54225 * Ext JS Library 1.1.1
54226 * Copyright(c) 2006-2007, Ext JS, LLC.
54228 * Originally Released Under LGPL - original licence link has changed is not relivant.
54231 * <script type="text/javascript">
54234 * @class Roo.grid.CellSelectionModel
54235 * @extends Roo.grid.AbstractSelectionModel
54236 * This class provides the basic implementation for cell selection in a grid.
54238 * @param {Object} config The object containing the configuration of this model.
54239 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
54241 Roo.grid.CellSelectionModel = function(config){
54242 Roo.apply(this, config);
54244 this.selection = null;
54248 * @event beforerowselect
54249 * Fires before a cell is selected.
54250 * @param {SelectionModel} this
54251 * @param {Number} rowIndex The selected row index
54252 * @param {Number} colIndex The selected cell index
54254 "beforecellselect" : true,
54256 * @event cellselect
54257 * Fires when a cell is selected.
54258 * @param {SelectionModel} this
54259 * @param {Number} rowIndex The selected row index
54260 * @param {Number} colIndex The selected cell index
54262 "cellselect" : true,
54264 * @event selectionchange
54265 * Fires when the active selection changes.
54266 * @param {SelectionModel} this
54267 * @param {Object} selection null for no selection or an object (o) with two properties
54269 <li>o.record: the record object for the row the selection is in</li>
54270 <li>o.cell: An array of [rowIndex, columnIndex]</li>
54273 "selectionchange" : true,
54276 * Fires when the tab (or enter) was pressed on the last editable cell
54277 * You can use this to trigger add new row.
54278 * @param {SelectionModel} this
54282 * @event beforeeditnext
54283 * Fires before the next editable sell is made active
54284 * You can use this to skip to another cell or fire the tabend
54285 * if you set cell to false
54286 * @param {Object} eventdata object : { cell : [ row, col ] }
54288 "beforeeditnext" : true
54290 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
54293 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
54295 enter_is_tab: false,
54298 initEvents : function(){
54299 this.grid.on("mousedown", this.handleMouseDown, this);
54300 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
54301 var view = this.grid.view;
54302 view.on("refresh", this.onViewChange, this);
54303 view.on("rowupdated", this.onRowUpdated, this);
54304 view.on("beforerowremoved", this.clearSelections, this);
54305 view.on("beforerowsinserted", this.clearSelections, this);
54306 if(this.grid.isEditor){
54307 this.grid.on("beforeedit", this.beforeEdit, this);
54312 beforeEdit : function(e){
54313 this.select(e.row, e.column, false, true, e.record);
54317 onRowUpdated : function(v, index, r){
54318 if(this.selection && this.selection.record == r){
54319 v.onCellSelect(index, this.selection.cell[1]);
54324 onViewChange : function(){
54325 this.clearSelections(true);
54329 * Returns the currently selected cell,.
54330 * @return {Array} The selected cell (row, column) or null if none selected.
54332 getSelectedCell : function(){
54333 return this.selection ? this.selection.cell : null;
54337 * Clears all selections.
54338 * @param {Boolean} true to prevent the gridview from being notified about the change.
54340 clearSelections : function(preventNotify){
54341 var s = this.selection;
54343 if(preventNotify !== true){
54344 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
54346 this.selection = null;
54347 this.fireEvent("selectionchange", this, null);
54352 * Returns true if there is a selection.
54353 * @return {Boolean}
54355 hasSelection : function(){
54356 return this.selection ? true : false;
54360 handleMouseDown : function(e, t){
54361 var v = this.grid.getView();
54362 if(this.isLocked()){
54365 var row = v.findRowIndex(t);
54366 var cell = v.findCellIndex(t);
54367 if(row !== false && cell !== false){
54368 this.select(row, cell);
54374 * @param {Number} rowIndex
54375 * @param {Number} collIndex
54377 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
54378 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
54379 this.clearSelections();
54380 r = r || this.grid.dataSource.getAt(rowIndex);
54383 cell : [rowIndex, colIndex]
54385 if(!preventViewNotify){
54386 var v = this.grid.getView();
54387 v.onCellSelect(rowIndex, colIndex);
54388 if(preventFocus !== true){
54389 v.focusCell(rowIndex, colIndex);
54392 this.fireEvent("cellselect", this, rowIndex, colIndex);
54393 this.fireEvent("selectionchange", this, this.selection);
54398 isSelectable : function(rowIndex, colIndex, cm){
54399 return !cm.isHidden(colIndex);
54403 handleKeyDown : function(e){
54404 //Roo.log('Cell Sel Model handleKeyDown');
54405 if(!e.isNavKeyPress()){
54408 var g = this.grid, s = this.selection;
54411 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
54413 this.select(cell[0], cell[1]);
54418 var walk = function(row, col, step){
54419 return g.walkCells(row, col, step, sm.isSelectable, sm);
54421 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
54428 // handled by onEditorKey
54429 if (g.isEditor && g.editing) {
54433 newCell = walk(r, c-1, -1);
54435 newCell = walk(r, c+1, 1);
54440 newCell = walk(r+1, c, 1);
54444 newCell = walk(r-1, c, -1);
54448 newCell = walk(r, c+1, 1);
54452 newCell = walk(r, c-1, -1);
54457 if(g.isEditor && !g.editing){
54458 g.startEditing(r, c);
54467 this.select(newCell[0], newCell[1]);
54473 acceptsNav : function(row, col, cm){
54474 return !cm.isHidden(col) && cm.isCellEditable(col, row);
54478 * @param {Number} field (not used) - as it's normally used as a listener
54479 * @param {Number} e - event - fake it by using
54481 * var e = Roo.EventObjectImpl.prototype;
54482 * e.keyCode = e.TAB
54486 onEditorKey : function(field, e){
54488 var k = e.getKey(),
54491 ed = g.activeEditor,
54493 ///Roo.log('onEditorKey' + k);
54496 if (this.enter_is_tab && k == e.ENTER) {
54502 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
54504 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54510 } else if(k == e.ENTER && !e.ctrlKey){
54513 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54515 } else if(k == e.ESC){
54520 var ecall = { cell : newCell, forward : forward };
54521 this.fireEvent('beforeeditnext', ecall );
54522 newCell = ecall.cell;
54523 forward = ecall.forward;
54527 //Roo.log('next cell after edit');
54528 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
54529 } else if (forward) {
54530 // tabbed past last
54531 this.fireEvent.defer(100, this, ['tabend',this]);
54536 * Ext JS Library 1.1.1
54537 * Copyright(c) 2006-2007, Ext JS, LLC.
54539 * Originally Released Under LGPL - original licence link has changed is not relivant.
54542 * <script type="text/javascript">
54546 * @class Roo.grid.EditorGrid
54547 * @extends Roo.grid.Grid
54548 * Class for creating and editable grid.
54549 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54550 * The container MUST have some type of size defined for the grid to fill. The container will be
54551 * automatically set to position relative if it isn't already.
54552 * @param {Object} dataSource The data model to bind to
54553 * @param {Object} colModel The column model with info about this grid's columns
54555 Roo.grid.EditorGrid = function(container, config){
54556 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
54557 this.getGridEl().addClass("xedit-grid");
54559 if(!this.selModel){
54560 this.selModel = new Roo.grid.CellSelectionModel();
54563 this.activeEditor = null;
54567 * @event beforeedit
54568 * Fires before cell editing is triggered. The edit event object has the following properties <br />
54569 * <ul style="padding:5px;padding-left:16px;">
54570 * <li>grid - This grid</li>
54571 * <li>record - The record being edited</li>
54572 * <li>field - The field name being edited</li>
54573 * <li>value - The value for the field being edited.</li>
54574 * <li>row - The grid row index</li>
54575 * <li>column - The grid column index</li>
54576 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
54578 * @param {Object} e An edit event (see above for description)
54580 "beforeedit" : true,
54583 * Fires after a cell is edited. <br />
54584 * <ul style="padding:5px;padding-left:16px;">
54585 * <li>grid - This grid</li>
54586 * <li>record - The record being edited</li>
54587 * <li>field - The field name being edited</li>
54588 * <li>value - The value being set</li>
54589 * <li>originalValue - The original value for the field, before the edit.</li>
54590 * <li>row - The grid row index</li>
54591 * <li>column - The grid column index</li>
54593 * @param {Object} e An edit event (see above for description)
54595 "afteredit" : true,
54597 * @event validateedit
54598 * Fires after a cell is edited, but before the value is set in the record.
54599 * You can use this to modify the value being set in the field, Return false
54600 * to cancel the change. The edit event object has the following properties <br />
54601 * <ul style="padding:5px;padding-left:16px;">
54602 * <li>editor - This editor</li>
54603 * <li>grid - This grid</li>
54604 * <li>record - The record being edited</li>
54605 * <li>field - The field name being edited</li>
54606 * <li>value - The value being set</li>
54607 * <li>originalValue - The original value for the field, before the edit.</li>
54608 * <li>row - The grid row index</li>
54609 * <li>column - The grid column index</li>
54610 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
54612 * @param {Object} e An edit event (see above for description)
54614 "validateedit" : true
54616 this.on("bodyscroll", this.stopEditing, this);
54617 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
54620 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
54622 * @cfg {Number} clicksToEdit
54623 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
54630 trackMouseOver: false, // causes very odd FF errors
54632 onCellDblClick : function(g, row, col){
54633 this.startEditing(row, col);
54636 onEditComplete : function(ed, value, startValue){
54637 this.editing = false;
54638 this.activeEditor = null;
54639 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
54641 var field = this.colModel.getDataIndex(ed.col);
54646 originalValue: startValue,
54653 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
54656 if(String(value) !== String(startValue)){
54658 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
54659 r.set(field, e.value);
54660 // if we are dealing with a combo box..
54661 // then we also set the 'name' colum to be the displayField
54662 if (ed.field.displayField && ed.field.name) {
54663 r.set(ed.field.name, ed.field.el.dom.value);
54666 delete e.cancel; //?? why!!!
54667 this.fireEvent("afteredit", e);
54670 this.fireEvent("afteredit", e); // always fire it!
54672 this.view.focusCell(ed.row, ed.col);
54676 * Starts editing the specified for the specified row/column
54677 * @param {Number} rowIndex
54678 * @param {Number} colIndex
54680 startEditing : function(row, col){
54681 this.stopEditing();
54682 if(this.colModel.isCellEditable(col, row)){
54683 this.view.ensureVisible(row, col, true);
54685 var r = this.dataSource.getAt(row);
54686 var field = this.colModel.getDataIndex(col);
54687 var cell = Roo.get(this.view.getCell(row,col));
54692 value: r.data[field],
54697 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
54698 this.editing = true;
54699 var ed = this.colModel.getCellEditor(col, row);
54705 ed.render(ed.parentEl || document.body);
54711 (function(){ // complex but required for focus issues in safari, ie and opera
54715 ed.on("complete", this.onEditComplete, this, {single: true});
54716 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
54717 this.activeEditor = ed;
54718 var v = r.data[field];
54719 ed.startEdit(this.view.getCell(row, col), v);
54720 // combo's with 'displayField and name set
54721 if (ed.field.displayField && ed.field.name) {
54722 ed.field.el.dom.value = r.data[ed.field.name];
54726 }).defer(50, this);
54732 * Stops any active editing
54734 stopEditing : function(){
54735 if(this.activeEditor){
54736 this.activeEditor.completeEdit();
54738 this.activeEditor = null;
54742 * Called to get grid's drag proxy text, by default returns this.ddText.
54745 getDragDropText : function(){
54746 var count = this.selModel.getSelectedCell() ? 1 : 0;
54747 return String.format(this.ddText, count, count == 1 ? '' : 's');
54752 * Ext JS Library 1.1.1
54753 * Copyright(c) 2006-2007, Ext JS, LLC.
54755 * Originally Released Under LGPL - original licence link has changed is not relivant.
54758 * <script type="text/javascript">
54761 // private - not really -- you end up using it !
54762 // This is a support class used internally by the Grid components
54765 * @class Roo.grid.GridEditor
54766 * @extends Roo.Editor
54767 * Class for creating and editable grid elements.
54768 * @param {Object} config any settings (must include field)
54770 Roo.grid.GridEditor = function(field, config){
54771 if (!config && field.field) {
54773 field = Roo.factory(config.field, Roo.form);
54775 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
54776 field.monitorTab = false;
54779 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
54782 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
54785 alignment: "tl-tl",
54788 cls: "x-small-editor x-grid-editor",
54793 * Ext JS Library 1.1.1
54794 * Copyright(c) 2006-2007, Ext JS, LLC.
54796 * Originally Released Under LGPL - original licence link has changed is not relivant.
54799 * <script type="text/javascript">
54804 Roo.grid.PropertyRecord = Roo.data.Record.create([
54805 {name:'name',type:'string'}, 'value'
54809 Roo.grid.PropertyStore = function(grid, source){
54811 this.store = new Roo.data.Store({
54812 recordType : Roo.grid.PropertyRecord
54814 this.store.on('update', this.onUpdate, this);
54816 this.setSource(source);
54818 Roo.grid.PropertyStore.superclass.constructor.call(this);
54823 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
54824 setSource : function(o){
54826 this.store.removeAll();
54829 if(this.isEditableValue(o[k])){
54830 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
54833 this.store.loadRecords({records: data}, {}, true);
54836 onUpdate : function(ds, record, type){
54837 if(type == Roo.data.Record.EDIT){
54838 var v = record.data['value'];
54839 var oldValue = record.modified['value'];
54840 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
54841 this.source[record.id] = v;
54843 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
54850 getProperty : function(row){
54851 return this.store.getAt(row);
54854 isEditableValue: function(val){
54855 if(val && val instanceof Date){
54857 }else if(typeof val == 'object' || typeof val == 'function'){
54863 setValue : function(prop, value){
54864 this.source[prop] = value;
54865 this.store.getById(prop).set('value', value);
54868 getSource : function(){
54869 return this.source;
54873 Roo.grid.PropertyColumnModel = function(grid, store){
54876 g.PropertyColumnModel.superclass.constructor.call(this, [
54877 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
54878 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
54880 this.store = store;
54881 this.bselect = Roo.DomHelper.append(document.body, {
54882 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
54883 {tag: 'option', value: 'true', html: 'true'},
54884 {tag: 'option', value: 'false', html: 'false'}
54887 Roo.id(this.bselect);
54890 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
54891 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
54892 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
54893 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
54894 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
54896 this.renderCellDelegate = this.renderCell.createDelegate(this);
54897 this.renderPropDelegate = this.renderProp.createDelegate(this);
54900 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
54904 valueText : 'Value',
54906 dateFormat : 'm/j/Y',
54909 renderDate : function(dateVal){
54910 return dateVal.dateFormat(this.dateFormat);
54913 renderBool : function(bVal){
54914 return bVal ? 'true' : 'false';
54917 isCellEditable : function(colIndex, rowIndex){
54918 return colIndex == 1;
54921 getRenderer : function(col){
54923 this.renderCellDelegate : this.renderPropDelegate;
54926 renderProp : function(v){
54927 return this.getPropertyName(v);
54930 renderCell : function(val){
54932 if(val instanceof Date){
54933 rv = this.renderDate(val);
54934 }else if(typeof val == 'boolean'){
54935 rv = this.renderBool(val);
54937 return Roo.util.Format.htmlEncode(rv);
54940 getPropertyName : function(name){
54941 var pn = this.grid.propertyNames;
54942 return pn && pn[name] ? pn[name] : name;
54945 getCellEditor : function(colIndex, rowIndex){
54946 var p = this.store.getProperty(rowIndex);
54947 var n = p.data['name'], val = p.data['value'];
54949 if(typeof(this.grid.customEditors[n]) == 'string'){
54950 return this.editors[this.grid.customEditors[n]];
54952 if(typeof(this.grid.customEditors[n]) != 'undefined'){
54953 return this.grid.customEditors[n];
54955 if(val instanceof Date){
54956 return this.editors['date'];
54957 }else if(typeof val == 'number'){
54958 return this.editors['number'];
54959 }else if(typeof val == 'boolean'){
54960 return this.editors['boolean'];
54962 return this.editors['string'];
54968 * @class Roo.grid.PropertyGrid
54969 * @extends Roo.grid.EditorGrid
54970 * This class represents the interface of a component based property grid control.
54971 * <br><br>Usage:<pre><code>
54972 var grid = new Roo.grid.PropertyGrid("my-container-id", {
54980 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54981 * The container MUST have some type of size defined for the grid to fill. The container will be
54982 * automatically set to position relative if it isn't already.
54983 * @param {Object} config A config object that sets properties on this grid.
54985 Roo.grid.PropertyGrid = function(container, config){
54986 config = config || {};
54987 var store = new Roo.grid.PropertyStore(this);
54988 this.store = store;
54989 var cm = new Roo.grid.PropertyColumnModel(this, store);
54990 store.store.sort('name', 'ASC');
54991 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
54994 enableColLock:false,
54995 enableColumnMove:false,
54997 trackMouseOver: false,
55000 this.getGridEl().addClass('x-props-grid');
55001 this.lastEditRow = null;
55002 this.on('columnresize', this.onColumnResize, this);
55005 * @event beforepropertychange
55006 * Fires before a property changes (return false to stop?)
55007 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55008 * @param {String} id Record Id
55009 * @param {String} newval New Value
55010 * @param {String} oldval Old Value
55012 "beforepropertychange": true,
55014 * @event propertychange
55015 * Fires after a property changes
55016 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55017 * @param {String} id Record Id
55018 * @param {String} newval New Value
55019 * @param {String} oldval Old Value
55021 "propertychange": true
55023 this.customEditors = this.customEditors || {};
55025 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
55028 * @cfg {Object} customEditors map of colnames=> custom editors.
55029 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
55030 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
55031 * false disables editing of the field.
55035 * @cfg {Object} propertyNames map of property Names to their displayed value
55038 render : function(){
55039 Roo.grid.PropertyGrid.superclass.render.call(this);
55040 this.autoSize.defer(100, this);
55043 autoSize : function(){
55044 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
55046 this.view.fitColumns();
55050 onColumnResize : function(){
55051 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
55055 * Sets the data for the Grid
55056 * accepts a Key => Value object of all the elements avaiable.
55057 * @param {Object} data to appear in grid.
55059 setSource : function(source){
55060 this.store.setSource(source);
55064 * Gets all the data from the grid.
55065 * @return {Object} data data stored in grid
55067 getSource : function(){
55068 return this.store.getSource();
55072 * Ext JS Library 1.1.1
55073 * Copyright(c) 2006-2007, Ext JS, LLC.
55075 * Originally Released Under LGPL - original licence link has changed is not relivant.
55078 * <script type="text/javascript">
55082 * @class Roo.LoadMask
55083 * A simple utility class for generically masking elements while loading data. If the element being masked has
55084 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
55085 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
55086 * element's UpdateManager load indicator and will be destroyed after the initial load.
55088 * Create a new LoadMask
55089 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
55090 * @param {Object} config The config object
55092 Roo.LoadMask = function(el, config){
55093 this.el = Roo.get(el);
55094 Roo.apply(this, config);
55096 this.store.on('beforeload', this.onBeforeLoad, this);
55097 this.store.on('load', this.onLoad, this);
55098 this.store.on('loadexception', this.onLoadException, this);
55099 this.removeMask = false;
55101 var um = this.el.getUpdateManager();
55102 um.showLoadIndicator = false; // disable the default indicator
55103 um.on('beforeupdate', this.onBeforeLoad, this);
55104 um.on('update', this.onLoad, this);
55105 um.on('failure', this.onLoad, this);
55106 this.removeMask = true;
55110 Roo.LoadMask.prototype = {
55112 * @cfg {Boolean} removeMask
55113 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
55114 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
55117 * @cfg {String} msg
55118 * The text to display in a centered loading message box (defaults to 'Loading...')
55120 msg : 'Loading...',
55122 * @cfg {String} msgCls
55123 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
55125 msgCls : 'x-mask-loading',
55128 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
55134 * Disables the mask to prevent it from being displayed
55136 disable : function(){
55137 this.disabled = true;
55141 * Enables the mask so that it can be displayed
55143 enable : function(){
55144 this.disabled = false;
55147 onLoadException : function()
55149 Roo.log(arguments);
55151 if (typeof(arguments[3]) != 'undefined') {
55152 Roo.MessageBox.alert("Error loading",arguments[3]);
55156 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
55157 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
55166 this.el.unmask(this.removeMask);
55169 onLoad : function()
55171 this.el.unmask(this.removeMask);
55175 onBeforeLoad : function(){
55176 if(!this.disabled){
55177 this.el.mask(this.msg, this.msgCls);
55182 destroy : function(){
55184 this.store.un('beforeload', this.onBeforeLoad, this);
55185 this.store.un('load', this.onLoad, this);
55186 this.store.un('loadexception', this.onLoadException, this);
55188 var um = this.el.getUpdateManager();
55189 um.un('beforeupdate', this.onBeforeLoad, this);
55190 um.un('update', this.onLoad, this);
55191 um.un('failure', this.onLoad, this);
55196 * Ext JS Library 1.1.1
55197 * Copyright(c) 2006-2007, Ext JS, LLC.
55199 * Originally Released Under LGPL - original licence link has changed is not relivant.
55202 * <script type="text/javascript">
55207 * @class Roo.XTemplate
55208 * @extends Roo.Template
55209 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
55211 var t = new Roo.XTemplate(
55212 '<select name="{name}">',
55213 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
55217 // then append, applying the master template values
55220 * Supported features:
55225 {a_variable} - output encoded.
55226 {a_variable.format:("Y-m-d")} - call a method on the variable
55227 {a_variable:raw} - unencoded output
55228 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
55229 {a_variable:this.method_on_template(...)} - call a method on the template object.
55234 <tpl for="a_variable or condition.."></tpl>
55235 <tpl if="a_variable or condition"></tpl>
55236 <tpl exec="some javascript"></tpl>
55237 <tpl name="named_template"></tpl> (experimental)
55239 <tpl for="."></tpl> - just iterate the property..
55240 <tpl for=".."></tpl> - iterates with the parent (probably the template)
55244 Roo.XTemplate = function()
55246 Roo.XTemplate.superclass.constructor.apply(this, arguments);
55253 Roo.extend(Roo.XTemplate, Roo.Template, {
55256 * The various sub templates
55261 * basic tag replacing syntax
55264 * // you can fake an object call by doing this
55268 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
55271 * compile the template
55273 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
55276 compile: function()
55280 s = ['<tpl>', s, '</tpl>'].join('');
55282 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
55283 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
55284 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
55285 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
55286 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
55291 while(true == !!(m = s.match(re))){
55292 var forMatch = m[0].match(nameRe),
55293 ifMatch = m[0].match(ifRe),
55294 execMatch = m[0].match(execRe),
55295 namedMatch = m[0].match(namedRe),
55300 name = forMatch && forMatch[1] ? forMatch[1] : '';
55303 // if - puts fn into test..
55304 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
55306 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
55311 // exec - calls a function... returns empty if true is returned.
55312 exp = execMatch && execMatch[1] ? execMatch[1] : null;
55314 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
55322 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
55323 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
55324 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
55327 var uid = namedMatch ? namedMatch[1] : id;
55331 id: namedMatch ? namedMatch[1] : id,
55338 s = s.replace(m[0], '');
55340 s = s.replace(m[0], '{xtpl'+ id + '}');
55345 for(var i = tpls.length-1; i >= 0; --i){
55346 this.compileTpl(tpls[i]);
55347 this.tpls[tpls[i].id] = tpls[i];
55349 this.master = tpls[tpls.length-1];
55353 * same as applyTemplate, except it's done to one of the subTemplates
55354 * when using named templates, you can do:
55356 * var str = pl.applySubTemplate('your-name', values);
55359 * @param {Number} id of the template
55360 * @param {Object} values to apply to template
55361 * @param {Object} parent (normaly the instance of this object)
55363 applySubTemplate : function(id, values, parent)
55367 var t = this.tpls[id];
55371 if(t.test && !t.test.call(this, values, parent)){
55375 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
55376 Roo.log(e.toString());
55382 if(t.exec && t.exec.call(this, values, parent)){
55386 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
55387 Roo.log(e.toString());
55392 var vs = t.target ? t.target.call(this, values, parent) : values;
55393 parent = t.target ? values : parent;
55394 if(t.target && vs instanceof Array){
55396 for(var i = 0, len = vs.length; i < len; i++){
55397 buf[buf.length] = t.compiled.call(this, vs[i], parent);
55399 return buf.join('');
55401 return t.compiled.call(this, vs, parent);
55403 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
55404 Roo.log(e.toString());
55405 Roo.log(t.compiled);
55410 compileTpl : function(tpl)
55412 var fm = Roo.util.Format;
55413 var useF = this.disableFormats !== true;
55414 var sep = Roo.isGecko ? "+" : ",";
55415 var undef = function(str) {
55416 Roo.log("Property not found :" + str);
55420 var fn = function(m, name, format, args)
55422 //Roo.log(arguments);
55423 args = args ? args.replace(/\\'/g,"'") : args;
55424 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
55425 if (typeof(format) == 'undefined') {
55426 format= 'htmlEncode';
55428 if (format == 'raw' ) {
55432 if(name.substr(0, 4) == 'xtpl'){
55433 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
55436 // build an array of options to determine if value is undefined..
55438 // basically get 'xxxx.yyyy' then do
55439 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
55440 // (function () { Roo.log("Property not found"); return ''; })() :
55445 Roo.each(name.split('.'), function(st) {
55446 lookfor += (lookfor.length ? '.': '') + st;
55447 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
55450 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
55453 if(format && useF){
55455 args = args ? ',' + args : "";
55457 if(format.substr(0, 5) != "this."){
55458 format = "fm." + format + '(';
55460 format = 'this.call("'+ format.substr(5) + '", ';
55464 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
55468 // called with xxyx.yuu:(test,test)
55470 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
55472 // raw.. - :raw modifier..
55473 return "'"+ sep + udef_st + name + ")"+sep+"'";
55477 // branched to use + in gecko and [].join() in others
55479 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
55480 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
55483 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
55484 body.push(tpl.body.replace(/(\r\n|\n)/g,
55485 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
55486 body.push("'].join('');};};");
55487 body = body.join('');
55490 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
55492 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
55498 applyTemplate : function(values){
55499 return this.master.compiled.call(this, values, {});
55500 //var s = this.subs;
55503 apply : function(){
55504 return this.applyTemplate.apply(this, arguments);
55509 Roo.XTemplate.from = function(el){
55510 el = Roo.getDom(el);
55511 return new Roo.XTemplate(el.value || el.innerHTML);
55513 * Original code for Roojs - LGPL
55514 * <script type="text/javascript">
55518 * @class Roo.XComponent
55519 * A delayed Element creator...
55520 * Or a way to group chunks of interface together.
55522 * Mypart.xyx = new Roo.XComponent({
55524 parent : 'Mypart.xyz', // empty == document.element.!!
55528 disabled : function() {}
55530 tree : function() { // return an tree of xtype declared components
55534 xtype : 'NestedLayoutPanel',
55541 * It can be used to build a big heiracy, with parent etc.
55542 * or you can just use this to render a single compoent to a dom element
55543 * MYPART.render(Roo.Element | String(id) | dom_element )
55545 * @extends Roo.util.Observable
55547 * @param cfg {Object} configuration of component
55550 Roo.XComponent = function(cfg) {
55551 Roo.apply(this, cfg);
55555 * Fires when this the componnt is built
55556 * @param {Roo.XComponent} c the component
55561 this.region = this.region || 'center'; // default..
55562 Roo.XComponent.register(this);
55563 this.modules = false;
55564 this.el = false; // where the layout goes..
55568 Roo.extend(Roo.XComponent, Roo.util.Observable, {
55571 * The created element (with Roo.factory())
55572 * @type {Roo.Layout}
55578 * for BC - use el in new code
55579 * @type {Roo.Layout}
55585 * for BC - use el in new code
55586 * @type {Roo.Layout}
55591 * @cfg {Function|boolean} disabled
55592 * If this module is disabled by some rule, return true from the funtion
55597 * @cfg {String} parent
55598 * Name of parent element which it get xtype added to..
55603 * @cfg {String} order
55604 * Used to set the order in which elements are created (usefull for multiple tabs)
55609 * @cfg {String} name
55610 * String to display while loading.
55614 * @cfg {String} region
55615 * Region to render component to (defaults to center)
55620 * @cfg {Array} items
55621 * A single item array - the first element is the root of the tree..
55622 * It's done this way to stay compatible with the Xtype system...
55628 * The method that retuns the tree of parts that make up this compoennt
55635 * render element to dom or tree
55636 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
55639 render : function(el)
55643 var hp = this.parent ? 1 : 0;
55645 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
55646 // if parent is a '#.....' string, then let's use that..
55647 var ename = this.parent.substr(1)
55648 this.parent = false;
55649 el = Roo.get(ename);
55651 Roo.log("Warning - element can not be found :#" + ename );
55657 if (!this.parent) {
55659 el = el ? Roo.get(el) : false;
55661 // it's a top level one..
55663 el : new Roo.BorderLayout(el || document.body, {
55669 tabPosition: 'top',
55670 //resizeTabs: true,
55671 alwaysShowTabs: el && hp? false : true,
55672 hideTabs: el || !hp ? true : false,
55679 if (!this.parent.el) {
55680 // probably an old style ctor, which has been disabled.
55684 // The 'tree' method is '_tree now'
55686 var tree = this._tree ? this._tree() : this.tree();
55687 tree.region = tree.region || this.region;
55688 this.el = this.parent.el.addxtype(tree);
55689 this.fireEvent('built', this);
55691 this.panel = this.el;
55692 this.layout = this.panel.layout;
55693 this.parentLayout = this.parent.layout || false;
55699 Roo.apply(Roo.XComponent, {
55701 * @property hideProgress
55702 * true to disable the building progress bar.. usefull on single page renders.
55705 hideProgress : false,
55707 * @property buildCompleted
55708 * True when the builder has completed building the interface.
55711 buildCompleted : false,
55714 * @property topModule
55715 * the upper most module - uses document.element as it's constructor.
55722 * @property modules
55723 * array of modules to be created by registration system.
55724 * @type {Array} of Roo.XComponent
55729 * @property elmodules
55730 * array of modules to be created by which use #ID
55731 * @type {Array} of Roo.XComponent
55738 * Register components to be built later.
55740 * This solves the following issues
55741 * - Building is not done on page load, but after an authentication process has occured.
55742 * - Interface elements are registered on page load
55743 * - Parent Interface elements may not be loaded before child, so this handles that..
55750 module : 'Pman.Tab.projectMgr',
55752 parent : 'Pman.layout',
55753 disabled : false, // or use a function..
55756 * * @param {Object} details about module
55758 register : function(obj) {
55760 Roo.XComponent.event.fireEvent('register', obj);
55761 switch(typeof(obj.disabled) ) {
55767 if ( obj.disabled() ) {
55773 if (obj.disabled) {
55779 this.modules.push(obj);
55783 * convert a string to an object..
55784 * eg. 'AAA.BBB' -> finds AAA.BBB
55788 toObject : function(str)
55790 if (!str || typeof(str) == 'object') {
55793 if (str.substring(0,1) == '#') {
55797 var ar = str.split('.');
55802 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
55804 throw "Module not found : " + str;
55808 throw "Module not found : " + str;
55810 Roo.each(ar, function(e) {
55811 if (typeof(o[e]) == 'undefined') {
55812 throw "Module not found : " + str;
55823 * move modules into their correct place in the tree..
55826 preBuild : function ()
55829 Roo.each(this.modules , function (obj)
55831 Roo.XComponent.event.fireEvent('beforebuild', obj);
55833 var opar = obj.parent;
55835 obj.parent = this.toObject(opar);
55837 Roo.log("parent:toObject failed: " + e.toString());
55842 Roo.debug && Roo.log("GOT top level module");
55843 Roo.debug && Roo.log(obj);
55844 obj.modules = new Roo.util.MixedCollection(false,
55845 function(o) { return o.order + '' }
55847 this.topModule = obj;
55850 // parent is a string (usually a dom element name..)
55851 if (typeof(obj.parent) == 'string') {
55852 this.elmodules.push(obj);
55855 if (obj.parent.constructor != Roo.XComponent) {
55856 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
55858 if (!obj.parent.modules) {
55859 obj.parent.modules = new Roo.util.MixedCollection(false,
55860 function(o) { return o.order + '' }
55863 if (obj.parent.disabled) {
55864 obj.disabled = true;
55866 obj.parent.modules.add(obj);
55871 * make a list of modules to build.
55872 * @return {Array} list of modules.
55875 buildOrder : function()
55878 var cmp = function(a,b) {
55879 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
55881 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
55882 throw "No top level modules to build";
55885 // make a flat list in order of modules to build.
55886 var mods = this.topModule ? [ this.topModule ] : [];
55889 // elmodules (is a list of DOM based modules )
55890 Roo.each(this.elmodules, function(e) {
55892 if (!this.topModule &&
55893 typeof(e.parent) == 'string' &&
55894 e.parent.substring(0,1) == '#' &&
55895 Roo.get(e.parent.substr(1))
55898 _this.topModule = e;
55904 // add modules to their parents..
55905 var addMod = function(m) {
55906 Roo.debug && Roo.log("build Order: add: " + m.name);
55909 if (m.modules && !m.disabled) {
55910 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
55911 m.modules.keySort('ASC', cmp );
55912 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
55914 m.modules.each(addMod);
55916 Roo.debug && Roo.log("build Order: no child modules");
55918 // not sure if this is used any more..
55920 m.finalize.name = m.name + " (clean up) ";
55921 mods.push(m.finalize);
55925 if (this.topModule && this.topModule.modules) {
55926 this.topModule.modules.keySort('ASC', cmp );
55927 this.topModule.modules.each(addMod);
55933 * Build the registered modules.
55934 * @param {Object} parent element.
55935 * @param {Function} optional method to call after module has been added.
55943 var mods = this.buildOrder();
55945 //this.allmods = mods;
55946 //Roo.debug && Roo.log(mods);
55948 if (!mods.length) { // should not happen
55949 throw "NO modules!!!";
55953 var msg = "Building Interface...";
55954 // flash it up as modal - so we store the mask!?
55955 if (!this.hideProgress) {
55956 Roo.MessageBox.show({ title: 'loading' });
55957 Roo.MessageBox.show({
55958 title: "Please wait...",
55967 var total = mods.length;
55970 var progressRun = function() {
55971 if (!mods.length) {
55972 Roo.debug && Roo.log('hide?');
55973 if (!this.hideProgress) {
55974 Roo.MessageBox.hide();
55976 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
55982 var m = mods.shift();
55985 Roo.debug && Roo.log(m);
55986 // not sure if this is supported any more.. - modules that are are just function
55987 if (typeof(m) == 'function') {
55989 return progressRun.defer(10, _this);
55993 msg = "Building Interface " + (total - mods.length) +
55995 (m.name ? (' - ' + m.name) : '');
55996 Roo.debug && Roo.log(msg);
55997 if (!this.hideProgress) {
55998 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
56002 // is the module disabled?
56003 var disabled = (typeof(m.disabled) == 'function') ?
56004 m.disabled.call(m.module.disabled) : m.disabled;
56008 return progressRun(); // we do not update the display!
56016 // it's 10 on top level, and 1 on others??? why...
56017 return progressRun.defer(10, _this);
56020 progressRun.defer(1, _this);
56034 * wrapper for event.on - aliased later..
56035 * Typically use to register a event handler for register:
56037 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
56046 Roo.XComponent.event = new Roo.util.Observable({
56050 * Fires when an Component is registered,
56051 * set the disable property on the Component to stop registration.
56052 * @param {Roo.XComponent} c the component being registerd.
56057 * @event beforebuild
56058 * Fires before each Component is built
56059 * can be used to apply permissions.
56060 * @param {Roo.XComponent} c the component being registerd.
56063 'beforebuild' : true,
56065 * @event buildcomplete
56066 * Fires on the top level element when all elements have been built
56067 * @param {Roo.XComponent} the top level component.
56069 'buildcomplete' : true
56074 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);