4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64 isTouch = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
622 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623 * you may want to set this to true.
626 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
631 * Selects a single element as a Roo Element
632 * This is about as close as you can get to jQuery's $('do crazy stuff')
633 * @param {String} selector The selector/xpath query
634 * @param {Node} root (optional) The start of the query (defaults to document).
635 * @return {Roo.Element}
637 selectNode : function(selector, root)
639 var node = Roo.DomQuery.selectNode(selector,root);
640 return node ? Roo.get(node) : new Roo.Element(false);
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
652 * Ext JS Library 1.1.1
653 * Copyright(c) 2006-2007, Ext JS, LLC.
655 * Originally Released Under LGPL - original licence link has changed is not relivant.
658 * <script type="text/javascript">
662 // wrappedn so fnCleanup is not in global scope...
664 function fnCleanUp() {
665 var p = Function.prototype;
666 delete p.createSequence;
668 delete p.createDelegate;
669 delete p.createCallback;
670 delete p.createInterceptor;
672 window.detachEvent("onunload", fnCleanUp);
674 window.attachEvent("onunload", fnCleanUp);
681 * These functions are available on every Function object (any JavaScript function).
683 Roo.apply(Function.prototype, {
685 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687 * Will create a function that is bound to those 2 args.
688 * @return {Function} The new function
690 createCallback : function(/*args...*/){
691 // make args available, in function below
692 var args = arguments;
695 return method.apply(window, args);
700 * Creates a delegate (callback) that sets the scope to obj.
701 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702 * Will create a function that is automatically scoped to this.
703 * @param {Object} obj (optional) The object for which the scope is set
704 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706 * if a number the args are inserted at the specified position
707 * @return {Function} The new function
709 createDelegate : function(obj, args, appendArgs){
712 var callArgs = args || arguments;
713 if(appendArgs === true){
714 callArgs = Array.prototype.slice.call(arguments, 0);
715 callArgs = callArgs.concat(args);
716 }else if(typeof appendArgs == "number"){
717 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
721 return method.apply(obj || window, callArgs);
726 * Calls this function after the number of millseconds specified.
727 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728 * @param {Object} obj (optional) The object for which the scope is set
729 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731 * if a number the args are inserted at the specified position
732 * @return {Number} The timeout id that can be used with clearTimeout
734 defer : function(millis, obj, args, appendArgs){
735 var fn = this.createDelegate(obj, args, appendArgs);
737 return setTimeout(fn, millis);
743 * Create a combined function call sequence of the original function + the passed function.
744 * The resulting function returns the results of the original function.
745 * The passed fcn is called with the parameters of the original function
746 * @param {Function} fcn The function to sequence
747 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748 * @return {Function} The new function
750 createSequence : function(fcn, scope){
751 if(typeof fcn != "function"){
756 var retval = method.apply(this || window, arguments);
757 fcn.apply(scope || this || window, arguments);
763 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function.
767 * @param {Function} fcn The function to call before the original
768 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769 * @return {Function} The new function
771 createInterceptor : function(fcn, scope){
772 if(typeof fcn != "function"){
779 if(fcn.apply(scope || this || window, arguments) === false){
782 return method.apply(this || window, arguments);
788 * Ext JS Library 1.1.1
789 * Copyright(c) 2006-2007, Ext JS, LLC.
791 * Originally Released Under LGPL - original licence link has changed is not relivant.
794 * <script type="text/javascript">
797 Roo.applyIf(String, {
802 * Escapes the passed string for ' and \
803 * @param {String} string The string to escape
804 * @return {String} The escaped string
807 escape : function(string) {
808 return string.replace(/('|\\)/g, "\\$1");
812 * Pads the left side of a string with a specified character. This is especially useful
813 * for normalizing number and date strings. Example usage:
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
818 * @param {String} string The original string
819 * @param {Number} size The total length of the output string
820 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821 * @return {String} The padded string
824 leftPad : function (val, size, ch) {
825 var result = new String(val);
826 if(ch === null || ch === undefined || ch === '') {
829 while (result.length < size) {
830 result = ch + result;
836 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
837 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
843 * @param {String} string The tokenized string to be formatted
844 * @param {String} value1 The value to replace token {0}
845 * @param {String} value2 Etc...
846 * @return {String} The formatted string
849 format : function(format){
850 var args = Array.prototype.slice.call(arguments, 1);
851 return format.replace(/\{(\d+)\}/g, function(m, i){
852 return Roo.util.Format.htmlEncode(args[i]);
858 * Utility function that allows you to easily switch a string between two alternating values. The passed value
859 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
860 * they are already different, the first value passed in is returned. Note that this method returns the new value
861 * but does not change the current string.
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
869 * @param {String} value The value to compare to the current string
870 * @param {String} other The new value to use if the string already equals the first value passed in
871 * @return {String} The new value
874 String.prototype.toggle = function(value, other){
875 return this == value ? other : value;
878 * Ext JS Library 1.1.1
879 * Copyright(c) 2006-2007, Ext JS, LLC.
881 * Originally Released Under LGPL - original licence link has changed is not relivant.
884 * <script type="text/javascript">
890 Roo.applyIf(Number.prototype, {
892 * Checks whether or not the current number is within a desired range. If the number is already within the
893 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894 * exceeded. Note that this method returns the constrained value but does not change the current number.
895 * @param {Number} min The minimum number in the range
896 * @param {Number} max The maximum number in the range
897 * @return {Number} The constrained value if outside the range, otherwise the current value
899 constrain : function(min, max){
900 return Math.min(Math.max(this, min), max);
904 * Ext JS Library 1.1.1
905 * Copyright(c) 2006-2007, Ext JS, LLC.
907 * Originally Released Under LGPL - original licence link has changed is not relivant.
910 * <script type="text/javascript">
915 Roo.applyIf(Array.prototype, {
917 * Checks whether or not the specified object exists in the array.
918 * @param {Object} o The object to check for
919 * @return {Number} The index of o in the array (or -1 if it is not found)
921 indexOf : function(o){
922 for (var i = 0, len = this.length; i < len; i++){
923 if(this[i] == o) return i;
929 * Removes the specified object from the array. If the object is not found nothing happens.
930 * @param {Object} o The object to remove
932 remove : function(o){
933 var index = this.indexOf(o);
935 this.splice(index, 1);
939 * Map (JS 1.6 compatibility)
940 * @param {Function} function to call
944 var len = this.length >>> 0;
945 if (typeof fun != "function")
946 throw new TypeError();
948 var res = new Array(len);
949 var thisp = arguments[1];
950 for (var i = 0; i < len; i++)
953 res[i] = fun.call(thisp, this[i], i, this);
964 * Ext JS Library 1.1.1
965 * Copyright(c) 2006-2007, Ext JS, LLC.
967 * Originally Released Under LGPL - original licence link has changed is not relivant.
970 * <script type="text/javascript">
976 * The date parsing and format syntax is a subset of
977 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978 * supported will provide results equivalent to their PHP versions.
980 * Following is the list of all currently supported formats:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
985 Format Output Description
986 ------ ---------- --------------------------------------------------------------
987 d 10 Day of the month, 2 digits with leading zeros
988 D Wed A textual representation of a day, three letters
989 j 10 Day of the month without leading zeros
990 l Wednesday A full textual representation of the day of the week
991 S th English ordinal day of month suffix, 2 chars (use with j)
992 w 3 Numeric representation of the day of the week
993 z 9 The julian date, or day of the year (0-365)
994 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995 F January A full textual representation of the month
996 m 01 Numeric representation of a month, with leading zeros
997 M Jan Month name abbreviation, three letters
998 n 1 Numeric representation of a month, without leading zeros
999 t 31 Number of days in the given month
1000 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1001 Y 2007 A full numeric representation of a year, 4 digits
1002 y 07 A two digit representation of a year
1003 a pm Lowercase Ante meridiem and Post meridiem
1004 A PM Uppercase Ante meridiem and Post meridiem
1005 g 3 12-hour format of an hour without leading zeros
1006 G 15 24-hour format of an hour without leading zeros
1007 h 03 12-hour format of an hour with leading zeros
1008 H 15 24-hour format of an hour with leading zeros
1009 i 05 Minutes with leading zeros
1010 s 01 Seconds, with leading zeros
1011 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1013 T CST Timezone setting of the machine running the code
1014 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1017 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d')); //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1022 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1025 * Here are some standard date/time patterns that you might find helpful. They
1026 * are not part of the source of Date.js, but to use them you can simply copy this
1027 * block of code into any script that is included after Date.js and they will also become
1028 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1031 ISO8601Long:"Y-m-d H:i:s",
1032 ISO8601Short:"Y-m-d",
1034 LongDate: "l, F d, Y",
1035 FullDateTime: "l, F d, Y g:i:s A",
1038 LongTime: "g:i:s A",
1039 SortableDateTime: "Y-m-d\\TH:i:s",
1040 UniversalSortableDateTime: "Y-m-d H:i:sO",
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1053 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054 * They generate precompiled functions from date formats instead of parsing and
1055 * processing the pattern every time you format a date. These functions are available
1056 * on every Date object (any javascript function).
1058 * The original article and download are here:
1059 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1066 Returns the number of milliseconds between this date and date
1067 @param {Date} date (optional) Defaults to now
1068 @return {Number} The diff in milliseconds
1069 @member Date getElapsed
1071 Date.prototype.getElapsed = function(date) {
1072 return Math.abs((date || new Date()).getTime()-this.getTime());
1074 // was in date file..
1078 Date.parseFunctions = {count:0};
1080 Date.parseRegexes = [];
1082 Date.formatFunctions = {count:0};
1085 Date.prototype.dateFormat = function(format) {
1086 if (Date.formatFunctions[format] == null) {
1087 Date.createNewFormat(format);
1089 var func = Date.formatFunctions[format];
1090 return this[func]();
1095 * Formats a date given the supplied format string
1096 * @param {String} format The format string
1097 * @return {String} The formatted date
1100 Date.prototype.format = Date.prototype.dateFormat;
1103 Date.createNewFormat = function(format) {
1104 var funcName = "format" + Date.formatFunctions.count++;
1105 Date.formatFunctions[format] = funcName;
1106 var code = "Date.prototype." + funcName + " = function(){return ";
1107 var special = false;
1109 for (var i = 0; i < format.length; ++i) {
1110 ch = format.charAt(i);
1111 if (!special && ch == "\\") {
1116 code += "'" + String.escape(ch) + "' + ";
1119 code += Date.getFormatCode(ch);
1122 /** eval:var:zzzzzzzzzzzzz */
1123 eval(code.substring(0, code.length - 3) + ";}");
1127 Date.getFormatCode = function(character) {
1128 switch (character) {
1130 return "String.leftPad(this.getDate(), 2, '0') + ";
1132 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1134 return "this.getDate() + ";
1136 return "Date.dayNames[this.getDay()] + ";
1138 return "this.getSuffix() + ";
1140 return "this.getDay() + ";
1142 return "this.getDayOfYear() + ";
1144 return "this.getWeekOfYear() + ";
1146 return "Date.monthNames[this.getMonth()] + ";
1148 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1150 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1152 return "(this.getMonth() + 1) + ";
1154 return "this.getDaysInMonth() + ";
1156 return "(this.isLeapYear() ? 1 : 0) + ";
1158 return "this.getFullYear() + ";
1160 return "('' + this.getFullYear()).substring(2, 4) + ";
1162 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1164 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1166 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1168 return "this.getHours() + ";
1170 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1172 return "String.leftPad(this.getHours(), 2, '0') + ";
1174 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1176 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1178 return "this.getGMTOffset() + ";
1180 return "this.getGMTColonOffset() + ";
1182 return "this.getTimezone() + ";
1184 return "(this.getTimezoneOffset() * -60) + ";
1186 return "'" + String.escape(character) + "' + ";
1191 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1193 * the date format that is not specified will default to the current date value for that part. Time parts can also
1194 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1195 * string or the parse operation will fail.
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1210 * @param {String} input The unparsed date as a string
1211 * @param {String} format The format the date is in
1212 * @return {Date} The parsed date
1215 Date.parseDate = function(input, format) {
1216 if (Date.parseFunctions[format] == null) {
1217 Date.createParser(format);
1219 var func = Date.parseFunctions[format];
1220 return Date[func](input);
1225 Date.createParser = function(format) {
1226 var funcName = "parse" + Date.parseFunctions.count++;
1227 var regexNum = Date.parseRegexes.length;
1228 var currentGroup = 1;
1229 Date.parseFunctions[format] = funcName;
1231 var code = "Date." + funcName + " = function(input){\n"
1232 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233 + "var d = new Date();\n"
1234 + "y = d.getFullYear();\n"
1235 + "m = d.getMonth();\n"
1236 + "d = d.getDate();\n"
1237 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238 + "if (results && results.length > 0) {";
1241 var special = false;
1243 for (var i = 0; i < format.length; ++i) {
1244 ch = format.charAt(i);
1245 if (!special && ch == "\\") {
1250 regex += String.escape(ch);
1253 var obj = Date.formatCodeToRegex(ch, currentGroup);
1254 currentGroup += obj.g;
1256 if (obj.g && obj.c) {
1262 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i, s);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265 + "{v = new Date(y, m, d, h, i);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267 + "{v = new Date(y, m, d, h);}\n"
1268 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269 + "{v = new Date(y, m, d);}\n"
1270 + "else if (y >= 0 && m >= 0)\n"
1271 + "{v = new Date(y, m);}\n"
1272 + "else if (y >= 0)\n"
1273 + "{v = new Date(y);}\n"
1274 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1279 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280 /** eval:var:zzzzzzzzzzzzz */
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286 switch (character) {
1290 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1293 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294 s:"(\\d{1,2})"}; // day of month without leading zeroes
1297 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298 s:"(\\d{2})"}; // day of month with leading zeroes
1302 s:"(?:" + Date.dayNames.join("|") + ")"};
1306 s:"(?:st|nd|rd|th)"};
1321 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322 s:"(" + Date.monthNames.join("|") + ")"};
1325 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1329 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1333 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1345 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1349 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1354 c:"if (results[" + currentGroup + "] == 'am') {\n"
1355 + "if (h == 12) { h = 0; }\n"
1356 + "} else { if (h < 12) { h += 12; }}",
1360 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361 + "if (h == 12) { h = 0; }\n"
1362 + "} else { if (h < 12) { h += 12; }}",
1367 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1372 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1376 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1380 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1385 "o = results[", currentGroup, "];\n",
1386 "var sn = o.substring(0,1);\n", // get + / - sign
1387 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1392 s:"([+\-]\\d{2,4})"};
1398 "o = results[", currentGroup, "];\n",
1399 "var sn = o.substring(0,1);\n",
1400 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401 "var mn = o.substring(4,6) % 60;\n",
1402 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1409 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1412 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1418 s:String.escape(character)};
1423 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424 * @return {String} The abbreviated timezone name (e.g. 'CST')
1426 Date.prototype.getTimezone = function() {
1427 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1431 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1434 Date.prototype.getGMTOffset = function() {
1435 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1441 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442 * @return {String} 2-characters representing hours and 2-characters representing minutes
1443 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1445 Date.prototype.getGMTColonOffset = function() {
1446 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1449 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1453 * Get the numeric day number of the year, adjusted for leap year.
1454 * @return {Number} 0 through 364 (365 in leap years)
1456 Date.prototype.getDayOfYear = function() {
1458 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459 for (var i = 0; i < this.getMonth(); ++i) {
1460 num += Date.daysInMonth[i];
1462 return num + this.getDate() - 1;
1466 * Get the string representation of the numeric week number of the year
1467 * (equivalent to the format specifier 'W').
1468 * @return {String} '00' through '52'
1470 Date.prototype.getWeekOfYear = function() {
1471 // Skip to Thursday of this week
1472 var now = this.getDayOfYear() + (4 - this.getDay());
1473 // Find the first Thursday of the year
1474 var jan1 = new Date(this.getFullYear(), 0, 1);
1475 var then = (7 - jan1.getDay() + 4);
1476 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1480 * Whether or not the current date is in a leap year.
1481 * @return {Boolean} True if the current date is in a leap year, else false
1483 Date.prototype.isLeapYear = function() {
1484 var year = this.getFullYear();
1485 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1489 * Get the first day of the current month, adjusted for leap year. The returned value
1490 * is the numeric day index within the week (0-6) which can be used in conjunction with
1491 * the {@link #monthNames} array to retrieve the textual day name.
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1497 * @return {Number} The day number (0-6)
1499 Date.prototype.getFirstDayOfMonth = function() {
1500 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501 return (day < 0) ? (day + 7) : day;
1505 * Get the last day of the current month, adjusted for leap year. The returned value
1506 * is the numeric day index within the week (0-6) which can be used in conjunction with
1507 * the {@link #monthNames} array to retrieve the textual day name.
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1513 * @return {Number} The day number (0-6)
1515 Date.prototype.getLastDayOfMonth = function() {
1516 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517 return (day < 0) ? (day + 7) : day;
1522 * Get the first date of this date's month
1525 Date.prototype.getFirstDateOfMonth = function() {
1526 return new Date(this.getFullYear(), this.getMonth(), 1);
1530 * Get the last date of this date's month
1533 Date.prototype.getLastDateOfMonth = function() {
1534 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1537 * Get the number of days in the current month, adjusted for leap year.
1538 * @return {Number} The number of days in the month
1540 Date.prototype.getDaysInMonth = function() {
1541 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542 return Date.daysInMonth[this.getMonth()];
1546 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547 * @return {String} 'st, 'nd', 'rd' or 'th'
1549 Date.prototype.getSuffix = function() {
1550 switch (this.getDate()) {
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1570 * An array of textual month names.
1571 * Override these values for international dates, for example...
1572 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1591 * An array of textual day names.
1592 * Override these values for international dates, for example...
1593 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1609 Date.monthNumbers = {
1624 * Creates and returns a new Date instance with the exact same date value as the called instance.
1625 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626 * variable will also be changed. When the intention is to create a new variable that will not
1627 * modify the original instance, you should create a clone.
1629 * Example of correctly cloning a date:
1632 var orig = new Date('10/1/2006');
1635 document.write(orig); //returns 'Thu Oct 05 2006'!
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1641 document.write(orig); //returns 'Thu Oct 01 2006'
1643 * @return {Date} The new Date instance
1645 Date.prototype.clone = function() {
1646 return new Date(this.getTime());
1650 * Clears any time information from this date
1651 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652 @return {Date} this or the clone
1654 Date.prototype.clearTime = function(clone){
1656 return this.clone().clearTime();
1661 this.setMilliseconds(0);
1666 // safari setMonth is broken
1668 Date.brokenSetMonth = Date.prototype.setMonth;
1669 Date.prototype.setMonth = function(num){
1671 var n = Math.ceil(-num);
1672 var back_year = Math.ceil(n/12);
1673 var month = (n % 12) ? 12 - n % 12 : 0 ;
1674 this.setFullYear(this.getFullYear() - back_year);
1675 return Date.brokenSetMonth.call(this, month);
1677 return Date.brokenSetMonth.apply(this, arguments);
1682 /** Date interval constant
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1706 /** Date interval constant
1712 * Provides a convenient method of performing basic date arithmetic. This method
1713 * does not modify the Date instance being called - it creates and returns
1714 * a new Date instance containing the resulting date value.
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1731 * @param {String} interval A valid date interval enum value
1732 * @param {Number} value The amount to add to the current date
1733 * @return {Date} The new Date instance
1735 Date.prototype.add = function(interval, value){
1736 var d = this.clone();
1737 if (!interval || value === 0) return d;
1738 switch(interval.toLowerCase()){
1740 d.setMilliseconds(this.getMilliseconds() + value);
1743 d.setSeconds(this.getSeconds() + value);
1746 d.setMinutes(this.getMinutes() + value);
1749 d.setHours(this.getHours() + value);
1752 d.setDate(this.getDate() + value);
1755 var day = this.getDate();
1757 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1760 d.setMonth(this.getMonth() + value);
1763 d.setFullYear(this.getFullYear() + value);
1770 * Ext JS Library 1.1.1
1771 * Copyright(c) 2006-2007, Ext JS, LLC.
1773 * Originally Released Under LGPL - original licence link has changed is not relivant.
1776 * <script type="text/javascript">
1780 * @class Roo.lib.Dom
1783 * Dom utils (from YIU afaik)
1788 * Get the view width
1789 * @param {Boolean} full True will get the full document, otherwise it's the view width
1790 * @return {Number} The width
1793 getViewWidth : function(full) {
1794 return full ? this.getDocumentWidth() : this.getViewportWidth();
1797 * Get the view height
1798 * @param {Boolean} full True will get the full document, otherwise it's the view height
1799 * @return {Number} The height
1801 getViewHeight : function(full) {
1802 return full ? this.getDocumentHeight() : this.getViewportHeight();
1805 getDocumentHeight: function() {
1806 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807 return Math.max(scrollHeight, this.getViewportHeight());
1810 getDocumentWidth: function() {
1811 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812 return Math.max(scrollWidth, this.getViewportWidth());
1815 getViewportHeight: function() {
1816 var height = self.innerHeight;
1817 var mode = document.compatMode;
1819 if ((mode || Roo.isIE) && !Roo.isOpera) {
1820 height = (mode == "CSS1Compat") ?
1821 document.documentElement.clientHeight :
1822 document.body.clientHeight;
1828 getViewportWidth: function() {
1829 var width = self.innerWidth;
1830 var mode = document.compatMode;
1832 if (mode || Roo.isIE) {
1833 width = (mode == "CSS1Compat") ?
1834 document.documentElement.clientWidth :
1835 document.body.clientWidth;
1840 isAncestor : function(p, c) {
1847 if (p.contains && !Roo.isSafari) {
1848 return p.contains(c);
1849 } else if (p.compareDocumentPosition) {
1850 return !!(p.compareDocumentPosition(c) & 16);
1852 var parent = c.parentNode;
1857 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1860 parent = parent.parentNode;
1866 getRegion : function(el) {
1867 return Roo.lib.Region.getRegion(el);
1870 getY : function(el) {
1871 return this.getXY(el)[1];
1874 getX : function(el) {
1875 return this.getXY(el)[0];
1878 getXY : function(el) {
1879 var p, pe, b, scroll, bd = document.body;
1880 el = Roo.getDom(el);
1881 var fly = Roo.lib.AnimBase.fly;
1882 if (el.getBoundingClientRect) {
1883 b = el.getBoundingClientRect();
1884 scroll = fly(document).getScroll();
1885 return [b.left + scroll.left, b.top + scroll.top];
1891 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1898 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1905 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1913 if (p != el && pe.getStyle('overflow') != 'visible') {
1921 if (Roo.isSafari && hasAbsolute) {
1926 if (Roo.isGecko && !hasAbsolute) {
1928 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1933 while (p && p != bd) {
1934 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1946 setXY : function(el, xy) {
1947 el = Roo.fly(el, '_setXY');
1949 var pts = el.translatePoints(xy);
1950 if (xy[0] !== false) {
1951 el.dom.style.left = pts.left + "px";
1953 if (xy[1] !== false) {
1954 el.dom.style.top = pts.top + "px";
1958 setX : function(el, x) {
1959 this.setXY(el, [x, false]);
1962 setY : function(el, y) {
1963 this.setXY(el, [false, y]);
1967 * Portions of this file are based on pieces of Yahoo User Interface Library
1968 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969 * YUI licensed under the BSD License:
1970 * http://developer.yahoo.net/yui/license.txt
1971 * <script type="text/javascript">
1975 Roo.lib.Event = function() {
1976 var loadComplete = false;
1978 var unloadListeners = [];
1980 var onAvailStack = [];
1982 var lastError = null;
1995 startInterval: function() {
1996 if (!this._interval) {
1998 var callback = function() {
1999 self._tryPreloadAttach();
2001 this._interval = setInterval(callback, this.POLL_INTERVAL);
2006 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007 onAvailStack.push({ id: p_id,
2010 override: p_override,
2011 checkReady: false });
2013 retryCount = this.POLL_RETRYS;
2014 this.startInterval();
2018 addListener: function(el, eventName, fn) {
2019 el = Roo.getDom(el);
2024 if ("unload" == eventName) {
2025 unloadListeners[unloadListeners.length] =
2026 [el, eventName, fn];
2030 var wrappedFn = function(e) {
2031 return fn(Roo.lib.Event.getEvent(e));
2034 var li = [el, eventName, fn, wrappedFn];
2036 var index = listeners.length;
2037 listeners[index] = li;
2039 this.doAdd(el, eventName, wrappedFn, false);
2045 removeListener: function(el, eventName, fn) {
2048 el = Roo.getDom(el);
2051 return this.purgeElement(el, false, eventName);
2055 if ("unload" == eventName) {
2057 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058 var li = unloadListeners[i];
2061 li[1] == eventName &&
2063 unloadListeners.splice(i, 1);
2071 var cacheItem = null;
2074 var index = arguments[3];
2076 if ("undefined" == typeof index) {
2077 index = this._getCacheIndex(el, eventName, fn);
2081 cacheItem = listeners[index];
2084 if (!el || !cacheItem) {
2088 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2090 delete listeners[index][this.WFN];
2091 delete listeners[index][this.FN];
2092 listeners.splice(index, 1);
2099 getTarget: function(ev, resolveTextNode) {
2100 ev = ev.browserEvent || ev;
2101 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2102 var t = ev.target || ev.srcElement;
2103 return this.resolveTextNode(t);
2107 resolveTextNode: function(node) {
2108 if (Roo.isSafari && node && 3 == node.nodeType) {
2109 return node.parentNode;
2116 getPageX: function(ev) {
2117 ev = ev.browserEvent || ev;
2118 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2120 if (!x && 0 !== x) {
2121 x = ev.clientX || 0;
2124 x += this.getScroll()[1];
2132 getPageY: function(ev) {
2133 ev = ev.browserEvent || ev;
2134 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2136 if (!y && 0 !== y) {
2137 y = ev.clientY || 0;
2140 y += this.getScroll()[0];
2149 getXY: function(ev) {
2150 ev = ev.browserEvent || ev;
2151 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 return [this.getPageX(ev), this.getPageY(ev)];
2156 getRelatedTarget: function(ev) {
2157 ev = ev.browserEvent || ev;
2158 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2159 var t = ev.relatedTarget;
2161 if (ev.type == "mouseout") {
2163 } else if (ev.type == "mouseover") {
2168 return this.resolveTextNode(t);
2172 getTime: function(ev) {
2173 ev = ev.browserEvent || ev;
2174 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2176 var t = new Date().getTime();
2180 this.lastError = ex;
2189 stopEvent: function(ev) {
2190 this.stopPropagation(ev);
2191 this.preventDefault(ev);
2195 stopPropagation: function(ev) {
2196 ev = ev.browserEvent || ev;
2197 if (ev.stopPropagation) {
2198 ev.stopPropagation();
2200 ev.cancelBubble = true;
2205 preventDefault: function(ev) {
2206 ev = ev.browserEvent || ev;
2207 if(ev.preventDefault) {
2208 ev.preventDefault();
2210 ev.returnValue = false;
2215 getEvent: function(e) {
2216 var ev = e || window.event;
2218 var c = this.getEvent.caller;
2220 ev = c.arguments[0];
2221 if (ev && Event == ev.constructor) {
2231 getCharCode: function(ev) {
2232 ev = ev.browserEvent || ev;
2233 return ev.charCode || ev.keyCode || 0;
2237 _getCacheIndex: function(el, eventName, fn) {
2238 for (var i = 0,len = listeners.length; i < len; ++i) {
2239 var li = listeners[i];
2241 li[this.FN] == fn &&
2242 li[this.EL] == el &&
2243 li[this.TYPE] == eventName) {
2255 getEl: function(id) {
2256 return document.getElementById(id);
2260 clearCache: function() {
2264 _load: function(e) {
2265 loadComplete = true;
2266 var EU = Roo.lib.Event;
2270 EU.doRemove(window, "load", EU._load);
2275 _tryPreloadAttach: function() {
2284 var tryAgain = !loadComplete;
2286 tryAgain = (retryCount > 0);
2291 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292 var item = onAvailStack[i];
2294 var el = this.getEl(item.id);
2297 if (!item.checkReady ||
2300 (document && document.body)) {
2303 if (item.override) {
2304 if (item.override === true) {
2307 scope = item.override;
2310 item.fn.call(scope, item.obj);
2311 onAvailStack[i] = null;
2314 notAvail.push(item);
2319 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2323 this.startInterval();
2325 clearInterval(this._interval);
2326 this._interval = null;
2329 this.locked = false;
2336 purgeElement: function(el, recurse, eventName) {
2337 var elListeners = this.getListeners(el, eventName);
2339 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340 var l = elListeners[i];
2341 this.removeListener(el, l.type, l.fn);
2345 if (recurse && el && el.childNodes) {
2346 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347 this.purgeElement(el.childNodes[i], recurse, eventName);
2353 getListeners: function(el, eventName) {
2354 var results = [], searchLists;
2356 searchLists = [listeners, unloadListeners];
2357 } else if (eventName == "unload") {
2358 searchLists = [unloadListeners];
2360 searchLists = [listeners];
2363 for (var j = 0; j < searchLists.length; ++j) {
2364 var searchList = searchLists[j];
2365 if (searchList && searchList.length > 0) {
2366 for (var i = 0,len = searchList.length; i < len; ++i) {
2367 var l = searchList[i];
2368 if (l && l[this.EL] === el &&
2369 (!eventName || eventName === l[this.TYPE])) {
2374 adjust: l[this.ADJ_SCOPE],
2382 return (results.length) ? results : null;
2386 _unload: function(e) {
2388 var EU = Roo.lib.Event, i, j, l, len, index;
2390 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391 l = unloadListeners[i];
2394 if (l[EU.ADJ_SCOPE]) {
2395 if (l[EU.ADJ_SCOPE] === true) {
2398 scope = l[EU.ADJ_SCOPE];
2401 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402 unloadListeners[i] = null;
2408 unloadListeners = null;
2410 if (listeners && listeners.length > 0) {
2411 j = listeners.length;
2414 l = listeners[index];
2416 EU.removeListener(l[EU.EL], l[EU.TYPE],
2426 EU.doRemove(window, "unload", EU._unload);
2431 getScroll: function() {
2432 var dd = document.documentElement, db = document.body;
2433 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434 return [dd.scrollTop, dd.scrollLeft];
2436 return [db.scrollTop, db.scrollLeft];
2443 doAdd: function () {
2444 if (window.addEventListener) {
2445 return function(el, eventName, fn, capture) {
2446 el.addEventListener(eventName, fn, (capture));
2448 } else if (window.attachEvent) {
2449 return function(el, eventName, fn, capture) {
2450 el.attachEvent("on" + eventName, fn);
2459 doRemove: function() {
2460 if (window.removeEventListener) {
2461 return function (el, eventName, fn, capture) {
2462 el.removeEventListener(eventName, fn, (capture));
2464 } else if (window.detachEvent) {
2465 return function (el, eventName, fn) {
2466 el.detachEvent("on" + eventName, fn);
2478 var E = Roo.lib.Event;
2479 E.on = E.addListener;
2480 E.un = E.removeListener;
2482 if (document && document.body) {
2485 E.doAdd(window, "load", E._load);
2487 E.doAdd(window, "unload", E._unload);
2488 E._tryPreloadAttach();
2492 * Portions of this file are based on pieces of Yahoo User Interface Library
2493 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494 * YUI licensed under the BSD License:
2495 * http://developer.yahoo.net/yui/license.txt
2496 * <script type="text/javascript">
2502 * @class Roo.lib.Ajax
2509 request : function(method, uri, cb, data, options) {
2511 var hs = options.headers;
2514 if(hs.hasOwnProperty(h)){
2515 this.initHeader(h, hs[h], false);
2519 if(options.xmlData){
2520 this.initHeader('Content-Type', 'text/xml', false);
2522 data = options.xmlData;
2526 return this.asyncRequest(method, uri, cb, data);
2529 serializeForm : function(form) {
2530 if(typeof form == 'string') {
2531 form = (document.getElementById(form) || document.forms[form]);
2534 var el, name, val, disabled, data = '', hasSubmit = false;
2535 for (var i = 0; i < form.elements.length; i++) {
2536 el = form.elements[i];
2537 disabled = form.elements[i].disabled;
2538 name = form.elements[i].name;
2539 val = form.elements[i].value;
2541 if (!disabled && name){
2545 case 'select-multiple':
2546 for (var j = 0; j < el.options.length; j++) {
2547 if (el.options[j].selected) {
2549 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2560 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2573 if(hasSubmit == false) {
2574 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2579 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2584 data = data.substr(0, data.length - 1);
2592 useDefaultHeader:true,
2594 defaultPostHeader:'application/x-www-form-urlencoded',
2596 useDefaultXhrHeader:true,
2598 defaultXhrHeader:'XMLHttpRequest',
2600 hasDefaultHeaders:true,
2612 setProgId:function(id)
2614 this.activeX.unshift(id);
2617 setDefaultPostHeader:function(b)
2619 this.useDefaultHeader = b;
2622 setDefaultXhrHeader:function(b)
2624 this.useDefaultXhrHeader = b;
2627 setPollingInterval:function(i)
2629 if (typeof i == 'number' && isFinite(i)) {
2630 this.pollInterval = i;
2634 createXhrObject:function(transactionId)
2640 http = new XMLHttpRequest();
2642 obj = { conn:http, tId:transactionId };
2646 for (var i = 0; i < this.activeX.length; ++i) {
2650 http = new ActiveXObject(this.activeX[i]);
2652 obj = { conn:http, tId:transactionId };
2665 getConnectionObject:function()
2668 var tId = this.transactionId;
2672 o = this.createXhrObject(tId);
2674 this.transactionId++;
2685 asyncRequest:function(method, uri, callback, postData)
2687 var o = this.getConnectionObject();
2693 o.conn.open(method, uri, true);
2695 if (this.useDefaultXhrHeader) {
2696 if (!this.defaultHeaders['X-Requested-With']) {
2697 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2701 if(postData && this.useDefaultHeader){
2702 this.initHeader('Content-Type', this.defaultPostHeader);
2705 if (this.hasDefaultHeaders || this.hasHeaders) {
2709 this.handleReadyState(o, callback);
2710 o.conn.send(postData || null);
2716 handleReadyState:function(o, callback)
2720 if (callback && callback.timeout) {
2722 this.timeout[o.tId] = window.setTimeout(function() {
2723 oConn.abort(o, callback, true);
2724 }, callback.timeout);
2727 this.poll[o.tId] = window.setInterval(
2729 if (o.conn && o.conn.readyState == 4) {
2730 window.clearInterval(oConn.poll[o.tId]);
2731 delete oConn.poll[o.tId];
2733 if(callback && callback.timeout) {
2734 window.clearTimeout(oConn.timeout[o.tId]);
2735 delete oConn.timeout[o.tId];
2738 oConn.handleTransactionResponse(o, callback);
2741 , this.pollInterval);
2744 handleTransactionResponse:function(o, callback, isAbort)
2748 this.releaseObject(o);
2752 var httpStatus, responseObject;
2756 if (o.conn.status !== undefined && o.conn.status != 0) {
2757 httpStatus = o.conn.status;
2769 if (httpStatus >= 200 && httpStatus < 300) {
2770 responseObject = this.createResponseObject(o, callback.argument);
2771 if (callback.success) {
2772 if (!callback.scope) {
2773 callback.success(responseObject);
2778 callback.success.apply(callback.scope, [responseObject]);
2783 switch (httpStatus) {
2791 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792 if (callback.failure) {
2793 if (!callback.scope) {
2794 callback.failure(responseObject);
2797 callback.failure.apply(callback.scope, [responseObject]);
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.failure) {
2804 if (!callback.scope) {
2805 callback.failure(responseObject);
2808 callback.failure.apply(callback.scope, [responseObject]);
2814 this.releaseObject(o);
2815 responseObject = null;
2818 createResponseObject:function(o, callbackArg)
2825 var headerStr = o.conn.getAllResponseHeaders();
2826 var header = headerStr.split('\n');
2827 for (var i = 0; i < header.length; i++) {
2828 var delimitPos = header[i].indexOf(':');
2829 if (delimitPos != -1) {
2830 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2838 obj.status = o.conn.status;
2839 obj.statusText = o.conn.statusText;
2840 obj.getResponseHeader = headerObj;
2841 obj.getAllResponseHeaders = headerStr;
2842 obj.responseText = o.conn.responseText;
2843 obj.responseXML = o.conn.responseXML;
2845 if (typeof callbackArg !== undefined) {
2846 obj.argument = callbackArg;
2852 createExceptionObject:function(tId, callbackArg, isAbort)
2855 var COMM_ERROR = 'communication failure';
2856 var ABORT_CODE = -1;
2857 var ABORT_ERROR = 'transaction aborted';
2863 obj.status = ABORT_CODE;
2864 obj.statusText = ABORT_ERROR;
2867 obj.status = COMM_CODE;
2868 obj.statusText = COMM_ERROR;
2872 obj.argument = callbackArg;
2878 initHeader:function(label, value, isDefault)
2880 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2882 if (headerObj[label] === undefined) {
2883 headerObj[label] = value;
2888 headerObj[label] = value + "," + headerObj[label];
2892 this.hasDefaultHeaders = true;
2895 this.hasHeaders = true;
2900 setHeader:function(o)
2902 if (this.hasDefaultHeaders) {
2903 for (var prop in this.defaultHeaders) {
2904 if (this.defaultHeaders.hasOwnProperty(prop)) {
2905 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2910 if (this.hasHeaders) {
2911 for (var prop in this.headers) {
2912 if (this.headers.hasOwnProperty(prop)) {
2913 o.conn.setRequestHeader(prop, this.headers[prop]);
2917 this.hasHeaders = false;
2921 resetDefaultHeaders:function() {
2922 delete this.defaultHeaders;
2923 this.defaultHeaders = {};
2924 this.hasDefaultHeaders = false;
2927 abort:function(o, callback, isTimeout)
2929 if(this.isCallInProgress(o)) {
2931 window.clearInterval(this.poll[o.tId]);
2932 delete this.poll[o.tId];
2934 delete this.timeout[o.tId];
2937 this.handleTransactionResponse(o, callback, true);
2947 isCallInProgress:function(o)
2950 return o.conn.readyState != 4 && o.conn.readyState != 0;
2959 releaseObject:function(o)
2968 'MSXML2.XMLHTTP.3.0',
2976 * Portions of this file are based on pieces of Yahoo User Interface Library
2977 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978 * YUI licensed under the BSD License:
2979 * http://developer.yahoo.net/yui/license.txt
2980 * <script type="text/javascript">
2984 Roo.lib.Region = function(t, r, b, l) {
2994 Roo.lib.Region.prototype = {
2995 contains : function(region) {
2996 return ( region.left >= this.left &&
2997 region.right <= this.right &&
2998 region.top >= this.top &&
2999 region.bottom <= this.bottom );
3003 getArea : function() {
3004 return ( (this.bottom - this.top) * (this.right - this.left) );
3007 intersect : function(region) {
3008 var t = Math.max(this.top, region.top);
3009 var r = Math.min(this.right, region.right);
3010 var b = Math.min(this.bottom, region.bottom);
3011 var l = Math.max(this.left, region.left);
3013 if (b >= t && r >= l) {
3014 return new Roo.lib.Region(t, r, b, l);
3019 union : function(region) {
3020 var t = Math.min(this.top, region.top);
3021 var r = Math.max(this.right, region.right);
3022 var b = Math.max(this.bottom, region.bottom);
3023 var l = Math.min(this.left, region.left);
3025 return new Roo.lib.Region(t, r, b, l);
3028 adjust : function(t, l, b, r) {
3037 Roo.lib.Region.getRegion = function(el) {
3038 var p = Roo.lib.Dom.getXY(el);
3041 var r = p[0] + el.offsetWidth;
3042 var b = p[1] + el.offsetHeight;
3045 return new Roo.lib.Region(t, r, b, l);
3048 * Portions of this file are based on pieces of Yahoo User Interface Library
3049 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050 * YUI licensed under the BSD License:
3051 * http://developer.yahoo.net/yui/license.txt
3052 * <script type="text/javascript">
3055 //@@dep Roo.lib.Region
3058 Roo.lib.Point = function(x, y) {
3059 if (x instanceof Array) {
3063 this.x = this.right = this.left = this[0] = x;
3064 this.y = this.top = this.bottom = this[1] = y;
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3069 * Portions of this file are based on pieces of Yahoo User Interface Library
3070 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071 * YUI licensed under the BSD License:
3072 * http://developer.yahoo.net/yui/license.txt
3073 * <script type="text/javascript">
3080 scroll : function(el, args, duration, easing, cb, scope) {
3081 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3084 motion : function(el, args, duration, easing, cb, scope) {
3085 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3088 color : function(el, args, duration, easing, cb, scope) {
3089 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3092 run : function(el, args, duration, easing, cb, scope, type) {
3093 type = type || Roo.lib.AnimBase;
3094 if (typeof easing == "string") {
3095 easing = Roo.lib.Easing[easing];
3097 var anim = new type(el, args, duration, easing);
3098 anim.animateX(function() {
3099 Roo.callback(cb, scope);
3105 * Portions of this file are based on pieces of Yahoo User Interface Library
3106 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107 * YUI licensed under the BSD License:
3108 * http://developer.yahoo.net/yui/license.txt
3109 * <script type="text/javascript">
3117 if (!libFlyweight) {
3118 libFlyweight = new Roo.Element.Flyweight();
3120 libFlyweight.dom = el;
3121 return libFlyweight;
3124 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3128 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3130 this.init(el, attributes, duration, method);
3134 Roo.lib.AnimBase.fly = fly;
3138 Roo.lib.AnimBase.prototype = {
3140 toString: function() {
3141 var el = this.getEl();
3142 var id = el.id || el.tagName;
3143 return ("Anim " + id);
3147 noNegatives: /width|height|opacity|padding/i,
3148 offsetAttribute: /^((width|height)|(top|left))$/,
3149 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3150 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3154 doMethod: function(attr, start, end) {
3155 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3159 setAttribute: function(attr, val, unit) {
3160 if (this.patterns.noNegatives.test(attr)) {
3161 val = (val > 0) ? val : 0;
3164 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3168 getAttribute: function(attr) {
3169 var el = this.getEl();
3170 var val = fly(el).getStyle(attr);
3172 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173 return parseFloat(val);
3176 var a = this.patterns.offsetAttribute.exec(attr) || [];
3177 var pos = !!( a[3] );
3178 var box = !!( a[2] );
3181 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3191 getDefaultUnit: function(attr) {
3192 if (this.patterns.defaultUnit.test(attr)) {
3199 animateX : function(callback, scope) {
3200 var f = function() {
3201 this.onComplete.removeListener(f);
3202 if (typeof callback == "function") {
3203 callback.call(scope || this, this);
3206 this.onComplete.addListener(f, this);
3211 setRuntimeAttribute: function(attr) {
3214 var attributes = this.attributes;
3216 this.runtimeAttributes[attr] = {};
3218 var isset = function(prop) {
3219 return (typeof prop !== 'undefined');
3222 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3226 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3229 if (isset(attributes[attr]['to'])) {
3230 end = attributes[attr]['to'];
3231 } else if (isset(attributes[attr]['by'])) {
3232 if (start.constructor == Array) {
3234 for (var i = 0, len = start.length; i < len; ++i) {
3235 end[i] = start[i] + attributes[attr]['by'][i];
3238 end = start + attributes[attr]['by'];
3242 this.runtimeAttributes[attr].start = start;
3243 this.runtimeAttributes[attr].end = end;
3246 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3250 init: function(el, attributes, duration, method) {
3252 var isAnimated = false;
3255 var startTime = null;
3258 var actualFrames = 0;
3261 el = Roo.getDom(el);
3264 this.attributes = attributes || {};
3267 this.duration = duration || 1;
3270 this.method = method || Roo.lib.Easing.easeNone;
3273 this.useSeconds = true;
3276 this.currentFrame = 0;
3279 this.totalFrames = Roo.lib.AnimMgr.fps;
3282 this.getEl = function() {
3287 this.isAnimated = function() {
3292 this.getStartTime = function() {
3296 this.runtimeAttributes = {};
3299 this.animate = function() {
3300 if (this.isAnimated()) {
3304 this.currentFrame = 0;
3306 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3308 Roo.lib.AnimMgr.registerElement(this);
3312 this.stop = function(finish) {
3314 this.currentFrame = this.totalFrames;
3315 this._onTween.fire();
3317 Roo.lib.AnimMgr.stop(this);
3320 var onStart = function() {
3321 this.onStart.fire();
3323 this.runtimeAttributes = {};
3324 for (var attr in this.attributes) {
3325 this.setRuntimeAttribute(attr);
3330 startTime = new Date();
3334 var onTween = function() {
3336 duration: new Date() - this.getStartTime(),
3337 currentFrame: this.currentFrame
3340 data.toString = function() {
3342 'duration: ' + data.duration +
3343 ', currentFrame: ' + data.currentFrame
3347 this.onTween.fire(data);
3349 var runtimeAttributes = this.runtimeAttributes;
3351 for (var attr in runtimeAttributes) {
3352 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3358 var onComplete = function() {
3359 var actual_duration = (new Date() - startTime) / 1000 ;
3362 duration: actual_duration,
3363 frames: actualFrames,
3364 fps: actualFrames / actual_duration
3367 data.toString = function() {
3369 'duration: ' + data.duration +
3370 ', frames: ' + data.frames +
3371 ', fps: ' + data.fps
3377 this.onComplete.fire(data);
3381 this._onStart = new Roo.util.Event(this);
3382 this.onStart = new Roo.util.Event(this);
3383 this.onTween = new Roo.util.Event(this);
3384 this._onTween = new Roo.util.Event(this);
3385 this.onComplete = new Roo.util.Event(this);
3386 this._onComplete = new Roo.util.Event(this);
3387 this._onStart.addListener(onStart);
3388 this._onTween.addListener(onTween);
3389 this._onComplete.addListener(onComplete);
3394 * Portions of this file are based on pieces of Yahoo User Interface Library
3395 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396 * YUI licensed under the BSD License:
3397 * http://developer.yahoo.net/yui/license.txt
3398 * <script type="text/javascript">
3402 Roo.lib.AnimMgr = new function() {
3419 this.registerElement = function(tween) {
3420 queue[queue.length] = tween;
3422 tween._onStart.fire();
3427 this.unRegister = function(tween, index) {
3428 tween._onComplete.fire();
3429 index = index || getIndex(tween);
3431 queue.splice(index, 1);
3435 if (tweenCount <= 0) {
3441 this.start = function() {
3442 if (thread === null) {
3443 thread = setInterval(this.run, this.delay);
3448 this.stop = function(tween) {
3450 clearInterval(thread);
3452 for (var i = 0, len = queue.length; i < len; ++i) {
3453 if (queue[0].isAnimated()) {
3454 this.unRegister(queue[0], 0);
3463 this.unRegister(tween);
3468 this.run = function() {
3469 for (var i = 0, len = queue.length; i < len; ++i) {
3470 var tween = queue[i];
3471 if (!tween || !tween.isAnimated()) {
3475 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3477 tween.currentFrame += 1;
3479 if (tween.useSeconds) {
3480 correctFrame(tween);
3482 tween._onTween.fire();
3485 Roo.lib.AnimMgr.stop(tween, i);
3490 var getIndex = function(anim) {
3491 for (var i = 0, len = queue.length; i < len; ++i) {
3492 if (queue[i] == anim) {
3500 var correctFrame = function(tween) {
3501 var frames = tween.totalFrames;
3502 var frame = tween.currentFrame;
3503 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504 var elapsed = (new Date() - tween.getStartTime());
3507 if (elapsed < tween.duration * 1000) {
3508 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3510 tweak = frames - (frame + 1);
3512 if (tweak > 0 && isFinite(tweak)) {
3513 if (tween.currentFrame + tweak >= frames) {
3514 tweak = frames - (frame + 1);
3517 tween.currentFrame += tweak;
3523 * Portions of this file are based on pieces of Yahoo User Interface Library
3524 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525 * YUI licensed under the BSD License:
3526 * http://developer.yahoo.net/yui/license.txt
3527 * <script type="text/javascript">
3530 Roo.lib.Bezier = new function() {
3532 this.getPosition = function(points, t) {
3533 var n = points.length;
3536 for (var i = 0; i < n; ++i) {
3537 tmp[i] = [points[i][0], points[i][1]];
3540 for (var j = 1; j < n; ++j) {
3541 for (i = 0; i < n - j; ++i) {
3542 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3547 return [ tmp[0][0], tmp[0][1] ];
3551 * Portions of this file are based on pieces of Yahoo User Interface Library
3552 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553 * YUI licensed under the BSD License:
3554 * http://developer.yahoo.net/yui/license.txt
3555 * <script type="text/javascript">
3560 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3564 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3566 var fly = Roo.lib.AnimBase.fly;
3568 var superclass = Y.ColorAnim.superclass;
3569 var proto = Y.ColorAnim.prototype;
3571 proto.toString = function() {
3572 var el = this.getEl();
3573 var id = el.id || el.tagName;
3574 return ("ColorAnim " + id);
3577 proto.patterns.color = /color$/i;
3578 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3584 proto.parseColor = function(s) {
3585 if (s.length == 3) {
3589 var c = this.patterns.hex.exec(s);
3590 if (c && c.length == 4) {
3591 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3594 c = this.patterns.rgb.exec(s);
3595 if (c && c.length == 4) {
3596 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3599 c = this.patterns.hex3.exec(s);
3600 if (c && c.length == 4) {
3601 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3606 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607 proto.getAttribute = function(attr) {
3608 var el = this.getEl();
3609 if (this.patterns.color.test(attr)) {
3610 var val = fly(el).getStyle(attr);
3612 if (this.patterns.transparent.test(val)) {
3613 var parent = el.parentNode;
3614 val = fly(parent).getStyle(attr);
3616 while (parent && this.patterns.transparent.test(val)) {
3617 parent = parent.parentNode;
3618 val = fly(parent).getStyle(attr);
3619 if (parent.tagName.toUpperCase() == 'HTML') {
3625 val = superclass.getAttribute.call(this, attr);
3630 proto.getAttribute = function(attr) {
3631 var el = this.getEl();
3632 if (this.patterns.color.test(attr)) {
3633 var val = fly(el).getStyle(attr);
3635 if (this.patterns.transparent.test(val)) {
3636 var parent = el.parentNode;
3637 val = fly(parent).getStyle(attr);
3639 while (parent && this.patterns.transparent.test(val)) {
3640 parent = parent.parentNode;
3641 val = fly(parent).getStyle(attr);
3642 if (parent.tagName.toUpperCase() == 'HTML') {
3648 val = superclass.getAttribute.call(this, attr);
3654 proto.doMethod = function(attr, start, end) {
3657 if (this.patterns.color.test(attr)) {
3659 for (var i = 0, len = start.length; i < len; ++i) {
3660 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3663 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3666 val = superclass.doMethod.call(this, attr, start, end);
3672 proto.setRuntimeAttribute = function(attr) {
3673 superclass.setRuntimeAttribute.call(this, attr);
3675 if (this.patterns.color.test(attr)) {
3676 var attributes = this.attributes;
3677 var start = this.parseColor(this.runtimeAttributes[attr].start);
3678 var end = this.parseColor(this.runtimeAttributes[attr].end);
3680 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681 end = this.parseColor(attributes[attr].by);
3683 for (var i = 0, len = start.length; i < len; ++i) {
3684 end[i] = start[i] + end[i];
3688 this.runtimeAttributes[attr].start = start;
3689 this.runtimeAttributes[attr].end = end;
3695 * Portions of this file are based on pieces of Yahoo User Interface Library
3696 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697 * YUI licensed under the BSD License:
3698 * http://developer.yahoo.net/yui/license.txt
3699 * <script type="text/javascript">
3705 easeNone: function (t, b, c, d) {
3706 return c * t / d + b;
3710 easeIn: function (t, b, c, d) {
3711 return c * (t /= d) * t + b;
3715 easeOut: function (t, b, c, d) {
3716 return -c * (t /= d) * (t - 2) + b;
3720 easeBoth: function (t, b, c, d) {
3721 if ((t /= d / 2) < 1) {
3722 return c / 2 * t * t + b;
3725 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3729 easeInStrong: function (t, b, c, d) {
3730 return c * (t /= d) * t * t * t + b;
3734 easeOutStrong: function (t, b, c, d) {
3735 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3739 easeBothStrong: function (t, b, c, d) {
3740 if ((t /= d / 2) < 1) {
3741 return c / 2 * t * t * t * t + b;
3744 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3749 elasticIn: function (t, b, c, d, a, p) {
3753 if ((t /= d) == 1) {
3760 if (!a || a < Math.abs(c)) {
3765 var s = p / (2 * Math.PI) * Math.asin(c / a);
3768 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3772 elasticOut: function (t, b, c, d, a, p) {
3776 if ((t /= d) == 1) {
3783 if (!a || a < Math.abs(c)) {
3788 var s = p / (2 * Math.PI) * Math.asin(c / a);
3791 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3795 elasticBoth: function (t, b, c, d, a, p) {
3800 if ((t /= d / 2) == 2) {
3808 if (!a || a < Math.abs(c)) {
3813 var s = p / (2 * Math.PI) * Math.asin(c / a);
3817 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3820 return a * Math.pow(2, -10 * (t -= 1)) *
3821 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3826 backIn: function (t, b, c, d, s) {
3827 if (typeof s == 'undefined') {
3830 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3834 backOut: function (t, b, c, d, s) {
3835 if (typeof s == 'undefined') {
3838 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3842 backBoth: function (t, b, c, d, s) {
3843 if (typeof s == 'undefined') {
3847 if ((t /= d / 2 ) < 1) {
3848 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3850 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3854 bounceIn: function (t, b, c, d) {
3855 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3859 bounceOut: function (t, b, c, d) {
3860 if ((t /= d) < (1 / 2.75)) {
3861 return c * (7.5625 * t * t) + b;
3862 } else if (t < (2 / 2.75)) {
3863 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864 } else if (t < (2.5 / 2.75)) {
3865 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3867 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3871 bounceBoth: function (t, b, c, d) {
3873 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3875 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3878 * Portions of this file are based on pieces of Yahoo User Interface Library
3879 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880 * YUI licensed under the BSD License:
3881 * http://developer.yahoo.net/yui/license.txt
3882 * <script type="text/javascript">
3886 Roo.lib.Motion = function(el, attributes, duration, method) {
3888 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3892 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3896 var superclass = Y.Motion.superclass;
3897 var proto = Y.Motion.prototype;
3899 proto.toString = function() {
3900 var el = this.getEl();
3901 var id = el.id || el.tagName;
3902 return ("Motion " + id);
3905 proto.patterns.points = /^points$/i;
3907 proto.setAttribute = function(attr, val, unit) {
3908 if (this.patterns.points.test(attr)) {
3909 unit = unit || 'px';
3910 superclass.setAttribute.call(this, 'left', val[0], unit);
3911 superclass.setAttribute.call(this, 'top', val[1], unit);
3913 superclass.setAttribute.call(this, attr, val, unit);
3917 proto.getAttribute = function(attr) {
3918 if (this.patterns.points.test(attr)) {
3920 superclass.getAttribute.call(this, 'left'),
3921 superclass.getAttribute.call(this, 'top')
3924 val = superclass.getAttribute.call(this, attr);
3930 proto.doMethod = function(attr, start, end) {
3933 if (this.patterns.points.test(attr)) {
3934 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3937 val = superclass.doMethod.call(this, attr, start, end);
3942 proto.setRuntimeAttribute = function(attr) {
3943 if (this.patterns.points.test(attr)) {
3944 var el = this.getEl();
3945 var attributes = this.attributes;
3947 var control = attributes['points']['control'] || [];
3951 if (control.length > 0 && !(control[0] instanceof Array)) {
3952 control = [control];
3955 for (i = 0,len = control.length; i < len; ++i) {
3956 tmp[i] = control[i];
3961 Roo.fly(el).position();
3963 if (isset(attributes['points']['from'])) {
3964 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3967 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3970 start = this.getAttribute('points');
3973 if (isset(attributes['points']['to'])) {
3974 end = translateValues.call(this, attributes['points']['to'], start);
3976 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977 for (i = 0,len = control.length; i < len; ++i) {
3978 control[i] = translateValues.call(this, control[i], start);
3982 } else if (isset(attributes['points']['by'])) {
3983 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3985 for (i = 0,len = control.length; i < len; ++i) {
3986 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3990 this.runtimeAttributes[attr] = [start];
3992 if (control.length > 0) {
3993 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3996 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3999 superclass.setRuntimeAttribute.call(this, attr);
4003 var translateValues = function(val, start) {
4004 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4010 var isset = function(prop) {
4011 return (typeof prop !== 'undefined');
4015 * Portions of this file are based on pieces of Yahoo User Interface Library
4016 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017 * YUI licensed under the BSD License:
4018 * http://developer.yahoo.net/yui/license.txt
4019 * <script type="text/javascript">
4023 Roo.lib.Scroll = function(el, attributes, duration, method) {
4025 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4029 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4033 var superclass = Y.Scroll.superclass;
4034 var proto = Y.Scroll.prototype;
4036 proto.toString = function() {
4037 var el = this.getEl();
4038 var id = el.id || el.tagName;
4039 return ("Scroll " + id);
4042 proto.doMethod = function(attr, start, end) {
4045 if (attr == 'scroll') {
4047 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4052 val = superclass.doMethod.call(this, attr, start, end);
4057 proto.getAttribute = function(attr) {
4059 var el = this.getEl();
4061 if (attr == 'scroll') {
4062 val = [ el.scrollLeft, el.scrollTop ];
4064 val = superclass.getAttribute.call(this, attr);
4070 proto.setAttribute = function(attr, val, unit) {
4071 var el = this.getEl();
4073 if (attr == 'scroll') {
4074 el.scrollLeft = val[0];
4075 el.scrollTop = val[1];
4077 superclass.setAttribute.call(this, attr, val, unit);
4083 * Ext JS Library 1.1.1
4084 * Copyright(c) 2006-2007, Ext JS, LLC.
4086 * Originally Released Under LGPL - original licence link has changed is not relivant.
4089 * <script type="text/javascript">
4093 // nasty IE9 hack - what a pile of crap that is..
4095 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096 Range.prototype.createContextualFragment = function (html) {
4097 var doc = window.document;
4098 var container = doc.createElement("div");
4099 container.innerHTML = html;
4100 var frag = doc.createDocumentFragment(), n;
4101 while ((n = container.firstChild)) {
4102 frag.appendChild(n);
4109 * @class Roo.DomHelper
4110 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4114 Roo.DomHelper = function(){
4115 var tempTableEl = null;
4116 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117 var tableRe = /^table|tbody|tr|td$/i;
4119 // build as innerHTML where available
4121 var createHtml = function(o){
4122 if(typeof o == 'string'){
4131 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132 if(attr == "style"){
4134 if(typeof s == "function"){
4137 if(typeof s == "string"){
4138 b += ' style="' + s + '"';
4139 }else if(typeof s == "object"){
4142 if(typeof s[key] != "function"){
4143 b += key + ":" + s[key] + ";";
4150 b += ' class="' + o["cls"] + '"';
4151 }else if(attr == "htmlFor"){
4152 b += ' for="' + o["htmlFor"] + '"';
4154 b += " " + attr + '="' + o[attr] + '"';
4158 if(emptyTags.test(o.tag)){
4162 var cn = o.children || o.cn;
4164 //http://bugs.kde.org/show_bug.cgi?id=71506
4165 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166 for(var i = 0, len = cn.length; i < len; i++) {
4167 b += createHtml(cn[i], b);
4170 b += createHtml(cn, b);
4176 b += "</" + o.tag + ">";
4183 var createDom = function(o, parentNode){
4185 // defininition craeted..
4187 if (o.ns && o.ns != 'html') {
4189 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190 xmlns[o.ns] = o.xmlns;
4193 if (typeof(xmlns[o.ns]) == 'undefined') {
4194 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4200 if (typeof(o) == 'string') {
4201 return parentNode.appendChild(document.createTextNode(o));
4203 o.tag = o.tag || div;
4204 if (o.ns && Roo.isIE) {
4206 o.tag = o.ns + ':' + o.tag;
4209 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4210 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4213 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4214 attr == "style" || typeof o[attr] == "function") continue;
4216 if(attr=="cls" && Roo.isIE){
4217 el.className = o["cls"];
4219 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220 else el[attr] = o[attr];
4223 Roo.DomHelper.applyStyles(el, o.style);
4224 var cn = o.children || o.cn;
4226 //http://bugs.kde.org/show_bug.cgi?id=71506
4227 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228 for(var i = 0, len = cn.length; i < len; i++) {
4229 createDom(cn[i], el);
4236 el.innerHTML = o.html;
4239 parentNode.appendChild(el);
4244 var ieTable = function(depth, s, h, e){
4245 tempTableEl.innerHTML = [s, h, e].join('');
4246 var i = -1, el = tempTableEl;
4253 // kill repeat to save bytes
4257 tbe = '</tbody>'+te,
4263 * Nasty code for IE's broken table implementation
4265 var insertIntoTable = function(tag, where, el, html){
4267 tempTableEl = document.createElement('div');
4272 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4275 if(where == 'beforebegin'){
4279 before = el.nextSibling;
4282 node = ieTable(4, trs, html, tre);
4284 else if(tag == 'tr'){
4285 if(where == 'beforebegin'){
4288 node = ieTable(3, tbs, html, tbe);
4289 } else if(where == 'afterend'){
4290 before = el.nextSibling;
4292 node = ieTable(3, tbs, html, tbe);
4293 } else{ // INTO a TR
4294 if(where == 'afterbegin'){
4295 before = el.firstChild;
4297 node = ieTable(4, trs, html, tre);
4299 } else if(tag == 'tbody'){
4300 if(where == 'beforebegin'){
4303 node = ieTable(2, ts, html, te);
4304 } else if(where == 'afterend'){
4305 before = el.nextSibling;
4307 node = ieTable(2, ts, html, te);
4309 if(where == 'afterbegin'){
4310 before = el.firstChild;
4312 node = ieTable(3, tbs, html, tbe);
4315 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4318 if(where == 'afterbegin'){
4319 before = el.firstChild;
4321 node = ieTable(2, ts, html, te);
4323 el.insertBefore(node, before);
4328 /** True to force the use of DOM instead of html fragments @type Boolean */
4332 * Returns the markup for the passed Element(s) config
4333 * @param {Object} o The Dom object spec (and children)
4336 markup : function(o){
4337 return createHtml(o);
4341 * Applies a style specification to an element
4342 * @param {String/HTMLElement} el The element to apply styles to
4343 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344 * a function which returns such a specification.
4346 applyStyles : function(el, styles){
4349 if(typeof styles == "string"){
4350 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4352 while ((matches = re.exec(styles)) != null){
4353 el.setStyle(matches[1], matches[2]);
4355 }else if (typeof styles == "object"){
4356 for (var style in styles){
4357 el.setStyle(style, styles[style]);
4359 }else if (typeof styles == "function"){
4360 Roo.DomHelper.applyStyles(el, styles.call());
4366 * Inserts an HTML fragment into the Dom
4367 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368 * @param {HTMLElement} el The context element
4369 * @param {String} html The HTML fragmenet
4370 * @return {HTMLElement} The new node
4372 insertHtml : function(where, el, html){
4373 where = where.toLowerCase();
4374 if(el.insertAdjacentHTML){
4375 if(tableRe.test(el.tagName)){
4377 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4383 el.insertAdjacentHTML('BeforeBegin', html);
4384 return el.previousSibling;
4386 el.insertAdjacentHTML('AfterBegin', html);
4387 return el.firstChild;
4389 el.insertAdjacentHTML('BeforeEnd', html);
4390 return el.lastChild;
4392 el.insertAdjacentHTML('AfterEnd', html);
4393 return el.nextSibling;
4395 throw 'Illegal insertion point -> "' + where + '"';
4397 var range = el.ownerDocument.createRange();
4401 range.setStartBefore(el);
4402 frag = range.createContextualFragment(html);
4403 el.parentNode.insertBefore(frag, el);
4404 return el.previousSibling;
4407 range.setStartBefore(el.firstChild);
4408 frag = range.createContextualFragment(html);
4409 el.insertBefore(frag, el.firstChild);
4410 return el.firstChild;
4412 el.innerHTML = html;
4413 return el.firstChild;
4417 range.setStartAfter(el.lastChild);
4418 frag = range.createContextualFragment(html);
4419 el.appendChild(frag);
4420 return el.lastChild;
4422 el.innerHTML = html;
4423 return el.lastChild;
4426 range.setStartAfter(el);
4427 frag = range.createContextualFragment(html);
4428 el.parentNode.insertBefore(frag, el.nextSibling);
4429 return el.nextSibling;
4431 throw 'Illegal insertion point -> "' + where + '"';
4435 * Creates new Dom element(s) and inserts them before el
4436 * @param {String/HTMLElement/Element} el The context element
4437 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439 * @return {HTMLElement/Roo.Element} The new node
4441 insertBefore : function(el, o, returnElement){
4442 return this.doInsert(el, o, returnElement, "beforeBegin");
4446 * Creates new Dom element(s) and inserts them after el
4447 * @param {String/HTMLElement/Element} el The context element
4448 * @param {Object} o The Dom object spec (and children)
4449 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450 * @return {HTMLElement/Roo.Element} The new node
4452 insertAfter : function(el, o, returnElement){
4453 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4457 * Creates new Dom element(s) and inserts them as the first child of el
4458 * @param {String/HTMLElement/Element} el The context element
4459 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461 * @return {HTMLElement/Roo.Element} The new node
4463 insertFirst : function(el, o, returnElement){
4464 return this.doInsert(el, o, returnElement, "afterBegin");
4468 doInsert : function(el, o, returnElement, pos, sibling){
4469 el = Roo.getDom(el);
4471 if(this.useDom || o.ns){
4472 newNode = createDom(o, null);
4473 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4475 var html = createHtml(o);
4476 newNode = this.insertHtml(pos, el, html);
4478 return returnElement ? Roo.get(newNode, true) : newNode;
4482 * Creates new Dom element(s) and appends them to el
4483 * @param {String/HTMLElement/Element} el The context element
4484 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486 * @return {HTMLElement/Roo.Element} The new node
4488 append : function(el, o, returnElement){
4489 el = Roo.getDom(el);
4491 if(this.useDom || o.ns){
4492 newNode = createDom(o, null);
4493 el.appendChild(newNode);
4495 var html = createHtml(o);
4496 newNode = this.insertHtml("beforeEnd", el, html);
4498 return returnElement ? Roo.get(newNode, true) : newNode;
4502 * Creates new Dom element(s) and overwrites the contents of el with them
4503 * @param {String/HTMLElement/Element} el The context element
4504 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506 * @return {HTMLElement/Roo.Element} The new node
4508 overwrite : function(el, o, returnElement){
4509 el = Roo.getDom(el);
4512 while (el.childNodes.length) {
4513 el.removeChild(el.firstChild);
4517 el.innerHTML = createHtml(o);
4520 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4524 * Creates a new Roo.DomHelper.Template from the Dom object spec
4525 * @param {Object} o The Dom object spec (and children)
4526 * @return {Roo.DomHelper.Template} The new template
4528 createTemplate : function(o){
4529 var html = createHtml(o);
4530 return new Roo.Template(html);
4536 * Ext JS Library 1.1.1
4537 * Copyright(c) 2006-2007, Ext JS, LLC.
4539 * Originally Released Under LGPL - original licence link has changed is not relivant.
4542 * <script type="text/javascript">
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4551 var t = new Roo.Template({
4552 html : '<div name="{id}">' +
4553 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4555 myformat: function (value, allValues) {
4556 return 'XX' + value;
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4561 * For more information see this blog post with examples:
4562 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563 - Create Elements using DOM, HTML fragments and Templates</a>.
4565 * @param {Object} cfg - Configuration object.
4567 Roo.Template = function(cfg){
4569 if(cfg instanceof Array){
4571 }else if(arguments.length > 1){
4572 cfg = Array.prototype.join.call(arguments, "");
4576 if (typeof(cfg) == 'object') {
4587 Roo.Template.prototype = {
4590 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4591 * it should be fixed so that template is observable...
4595 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4599 * Returns an HTML fragment of this template with the specified values applied.
4600 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4601 * @return {String} The HTML fragment
4603 applyTemplate : function(values){
4607 return this.compiled(values);
4609 var useF = this.disableFormats !== true;
4610 var fm = Roo.util.Format, tpl = this;
4611 var fn = function(m, name, format, args){
4613 if(format.substr(0, 5) == "this."){
4614 return tpl.call(format.substr(5), values[name], values);
4617 // quoted values are required for strings in compiled templates,
4618 // but for non compiled we need to strip them
4619 // quoted reversed for jsmin
4620 var re = /^\s*['"](.*)["']\s*$/;
4621 args = args.split(',');
4622 for(var i = 0, len = args.length; i < len; i++){
4623 args[i] = args[i].replace(re, "$1");
4625 args = [values[name]].concat(args);
4627 args = [values[name]];
4629 return fm[format].apply(fm, args);
4632 return values[name] !== undefined ? values[name] : "";
4635 return this.html.replace(this.re, fn);
4653 this.loading = true;
4654 this.compiled = false;
4656 var cx = new Roo.data.Connection();
4660 success : function (response) {
4662 _t.html = response.responseText;
4666 failure : function(response) {
4667 Roo.log("Template failed to load from " + _t.url);
4674 * Sets the HTML used as the template and optionally compiles it.
4675 * @param {String} html
4676 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677 * @return {Roo.Template} this
4679 set : function(html, compile){
4681 this.compiled = null;
4689 * True to disable format functions (defaults to false)
4692 disableFormats : false,
4695 * The regular expression used to match template variables
4699 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4702 * Compiles the template into an internal function, eliminating the RegEx overhead.
4703 * @return {Roo.Template} this
4705 compile : function(){
4706 var fm = Roo.util.Format;
4707 var useF = this.disableFormats !== true;
4708 var sep = Roo.isGecko ? "+" : ",";
4709 var fn = function(m, name, format, args){
4711 args = args ? ',' + args : "";
4712 if(format.substr(0, 5) != "this."){
4713 format = "fm." + format + '(';
4715 format = 'this.call("'+ format.substr(5) + '", ';
4719 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4721 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4724 // branched to use + in gecko and [].join() in others
4726 body = "this.compiled = function(values){ return '" +
4727 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4730 body = ["this.compiled = function(values){ return ['"];
4731 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732 body.push("'].join('');};");
4733 body = body.join('');
4743 // private function used to call members
4744 call : function(fnName, value, allValues){
4745 return this[fnName](value, allValues);
4749 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750 * @param {String/HTMLElement/Roo.Element} el The context element
4751 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753 * @return {HTMLElement/Roo.Element} The new node or Element
4755 insertFirst: function(el, values, returnElement){
4756 return this.doInsert('afterBegin', el, values, returnElement);
4760 * Applies the supplied values to the template and inserts the new node(s) before el.
4761 * @param {String/HTMLElement/Roo.Element} el The context element
4762 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764 * @return {HTMLElement/Roo.Element} The new node or Element
4766 insertBefore: function(el, values, returnElement){
4767 return this.doInsert('beforeBegin', el, values, returnElement);
4771 * Applies the supplied values to the template and inserts the new node(s) after el.
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 insertAfter : function(el, values, returnElement){
4778 return this.doInsert('afterEnd', el, values, returnElement);
4782 * Applies the supplied values to the template and appends the new node(s) to el.
4783 * @param {String/HTMLElement/Roo.Element} el The context element
4784 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4785 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786 * @return {HTMLElement/Roo.Element} The new node or Element
4788 append : function(el, values, returnElement){
4789 return this.doInsert('beforeEnd', el, values, returnElement);
4792 doInsert : function(where, el, values, returnEl){
4793 el = Roo.getDom(el);
4794 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795 return returnEl ? Roo.get(newNode, true) : newNode;
4799 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800 * @param {String/HTMLElement/Roo.Element} el The context element
4801 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4802 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803 * @return {HTMLElement/Roo.Element} The new node or Element
4805 overwrite : function(el, values, returnElement){
4806 el = Roo.getDom(el);
4807 el.innerHTML = this.applyTemplate(values);
4808 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4812 * Alias for {@link #applyTemplate}
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4818 Roo.DomHelper.Template = Roo.Template;
4821 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822 * @param {String/HTMLElement} el A DOM element or its id
4823 * @returns {Roo.Template} The created template
4826 Roo.Template.from = function(el){
4827 el = Roo.getDom(el);
4828 return new Roo.Template(el.value || el.innerHTML);
4831 * Ext JS Library 1.1.1
4832 * Copyright(c) 2006-2007, Ext JS, LLC.
4834 * Originally Released Under LGPL - original licence link has changed is not relivant.
4837 * <script type="text/javascript">
4842 * This is code is also distributed under MIT license for use
4843 * with jQuery and prototype JavaScript libraries.
4846 * @class Roo.DomQuery
4847 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4849 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4852 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4854 <h4>Element Selectors:</h4>
4856 <li> <b>*</b> any element</li>
4857 <li> <b>E</b> an element with the tag E</li>
4858 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4866 <li> <b>E[foo]</b> has an attribute "foo"</li>
4867 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4874 <h4>Pseudo Classes:</h4>
4876 <li> <b>E:first-child</b> E is the first child of its parent</li>
4877 <li> <b>E:last-child</b> E is the last child of its parent</li>
4878 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4879 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881 <li> <b>E:only-child</b> E is the only child of its parent</li>
4882 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4883 <li> <b>E:first</b> the first E in the resultset</li>
4884 <li> <b>E:last</b> the last E in the resultset</li>
4885 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4895 <h4>CSS Value Selectors:</h4>
4897 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4906 Roo.DomQuery = function(){
4907 var cache = {}, simpleCache = {}, valueCache = {};
4908 var nonSpace = /\S/;
4909 var trimRe = /^\s+|\s+$/g;
4910 var tplRe = /\{(\d+)\}/g;
4911 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912 var tagTokenRe = /^(#)?([\w-\*]+)/;
4913 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4915 function child(p, index){
4917 var n = p.firstChild;
4919 if(n.nodeType == 1){
4930 while((n = n.nextSibling) && n.nodeType != 1);
4935 while((n = n.previousSibling) && n.nodeType != 1);
4939 function children(d){
4940 var n = d.firstChild, ni = -1;
4942 var nx = n.nextSibling;
4943 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4953 function byClassName(c, a, v){
4957 var r = [], ri = -1, cn;
4958 for(var i = 0, ci; ci = c[i]; i++){
4959 if((' '+ci.className+' ').indexOf(v) != -1){
4966 function attrValue(n, attr){
4967 if(!n.tagName && typeof n.length != "undefined"){
4976 if(attr == "class" || attr == "className"){
4979 return n.getAttribute(attr) || n[attr];
4983 function getNodes(ns, mode, tagName){
4984 var result = [], ri = -1, cs;
4988 tagName = tagName || "*";
4989 if(typeof ns.getElementsByTagName != "undefined"){
4993 for(var i = 0, ni; ni = ns[i]; i++){
4994 cs = ni.getElementsByTagName(tagName);
4995 for(var j = 0, ci; ci = cs[j]; j++){
4999 }else if(mode == "/" || mode == ">"){
5000 var utag = tagName.toUpperCase();
5001 for(var i = 0, ni, cn; ni = ns[i]; i++){
5002 cn = ni.children || ni.childNodes;
5003 for(var j = 0, cj; cj = cn[j]; j++){
5004 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5009 }else if(mode == "+"){
5010 var utag = tagName.toUpperCase();
5011 for(var i = 0, n; n = ns[i]; i++){
5012 while((n = n.nextSibling) && n.nodeType != 1);
5013 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5017 }else if(mode == "~"){
5018 for(var i = 0, n; n = ns[i]; i++){
5019 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5028 function concat(a, b){
5032 for(var i = 0, l = b.length; i < l; i++){
5038 function byTag(cs, tagName){
5039 if(cs.tagName || cs == document){
5045 var r = [], ri = -1;
5046 tagName = tagName.toLowerCase();
5047 for(var i = 0, ci; ci = cs[i]; i++){
5048 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5055 function byId(cs, attr, id){
5056 if(cs.tagName || cs == document){
5062 var r = [], ri = -1;
5063 for(var i = 0,ci; ci = cs[i]; i++){
5064 if(ci && ci.id == id){
5072 function byAttribute(cs, attr, value, op, custom){
5073 var r = [], ri = -1, st = custom=="{";
5074 var f = Roo.DomQuery.operators[op];
5075 for(var i = 0, ci; ci = cs[i]; i++){
5078 a = Roo.DomQuery.getStyle(ci, attr);
5080 else if(attr == "class" || attr == "className"){
5082 }else if(attr == "for"){
5084 }else if(attr == "href"){
5085 a = ci.getAttribute("href", 2);
5087 a = ci.getAttribute(attr);
5089 if((f && f(a, value)) || (!f && a)){
5096 function byPseudo(cs, name, value){
5097 return Roo.DomQuery.pseudos[name](cs, value);
5100 // This is for IE MSXML which does not support expandos.
5101 // IE runs the same speed using setAttribute, however FF slows way down
5102 // and Safari completely fails so they need to continue to use expandos.
5103 var isIE = window.ActiveXObject ? true : false;
5105 // this eval is stop the compressor from
5106 // renaming the variable to something shorter
5108 /** eval:var:batch */
5113 function nodupIEXml(cs){
5115 cs[0].setAttribute("_nodup", d);
5117 for(var i = 1, len = cs.length; i < len; i++){
5119 if(!c.getAttribute("_nodup") != d){
5120 c.setAttribute("_nodup", d);
5124 for(var i = 0, len = cs.length; i < len; i++){
5125 cs[i].removeAttribute("_nodup");
5134 var len = cs.length, c, i, r = cs, cj, ri = -1;
5135 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5138 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139 return nodupIEXml(cs);
5143 for(i = 1; c = cs[i]; i++){
5148 for(var j = 0; j < i; j++){
5151 for(j = i+1; cj = cs[j]; j++){
5163 function quickDiffIEXml(c1, c2){
5165 for(var i = 0, len = c1.length; i < len; i++){
5166 c1[i].setAttribute("_qdiff", d);
5169 for(var i = 0, len = c2.length; i < len; i++){
5170 if(c2[i].getAttribute("_qdiff") != d){
5171 r[r.length] = c2[i];
5174 for(var i = 0, len = c1.length; i < len; i++){
5175 c1[i].removeAttribute("_qdiff");
5180 function quickDiff(c1, c2){
5181 var len1 = c1.length;
5185 if(isIE && c1[0].selectSingleNode){
5186 return quickDiffIEXml(c1, c2);
5189 for(var i = 0; i < len1; i++){
5193 for(var i = 0, len = c2.length; i < len; i++){
5194 if(c2[i]._qdiff != d){
5195 r[r.length] = c2[i];
5201 function quickId(ns, mode, root, id){
5203 var d = root.ownerDocument || root;
5204 return d.getElementById(id);
5206 ns = getNodes(ns, mode, "*");
5207 return byId(ns, null, id);
5211 getStyle : function(el, name){
5212 return Roo.fly(el).getStyle(name);
5215 * Compiles a selector/xpath query into a reusable function. The returned function
5216 * takes one parameter "root" (optional), which is the context node from where the query should start.
5217 * @param {String} selector The selector/xpath query
5218 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219 * @return {Function}
5221 compile : function(path, type){
5222 type = type || "select";
5224 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225 var q = path, mode, lq;
5226 var tk = Roo.DomQuery.matchers;
5227 var tklen = tk.length;
5230 // accept leading mode switch
5231 var lmode = q.match(modeRe);
5232 if(lmode && lmode[1]){
5233 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5234 q = q.replace(lmode[1], "");
5236 // strip leading slashes
5237 while(path.substr(0, 1)=="/"){
5238 path = path.substr(1);
5241 while(q && lq != q){
5243 var tm = q.match(tagTokenRe);
5244 if(type == "select"){
5247 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5249 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5251 q = q.replace(tm[0], "");
5252 }else if(q.substr(0, 1) != '@'){
5253 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5258 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5260 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5262 q = q.replace(tm[0], "");
5265 while(!(mm = q.match(modeRe))){
5266 var matched = false;
5267 for(var j = 0; j < tklen; j++){
5269 var m = q.match(t.re);
5271 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5274 q = q.replace(m[0], "");
5279 // prevent infinite loop on bad selector
5281 throw 'Error parsing selector, parsing failed at "' + q + '"';
5285 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5286 q = q.replace(mm[1], "");
5289 fn[fn.length] = "return nodup(n);\n}";
5292 * list of variables that need from compression as they are used by eval.
5302 * eval:var:byClassName
5304 * eval:var:byAttribute
5305 * eval:var:attrValue
5313 * Selects a group of elements.
5314 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5315 * @param {Node} root (optional) The start of the query (defaults to document).
5318 select : function(path, root, type){
5319 if(!root || root == document){
5322 if(typeof root == "string"){
5323 root = document.getElementById(root);
5325 var paths = path.split(",");
5327 for(var i = 0, len = paths.length; i < len; i++){
5328 var p = paths[i].replace(trimRe, "");
5330 cache[p] = Roo.DomQuery.compile(p);
5332 throw p + " is not a valid selector";
5335 var result = cache[p](root);
5336 if(result && result != document){
5337 results = results.concat(result);
5340 if(paths.length > 1){
5341 return nodup(results);
5347 * Selects a single element.
5348 * @param {String} selector The selector/xpath query
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 selectNode : function(path, root){
5353 return Roo.DomQuery.select(path, root)[0];
5357 * Selects the value of a node, optionally replacing null with the defaultValue.
5358 * @param {String} selector The selector/xpath query
5359 * @param {Node} root (optional) The start of the query (defaults to document).
5360 * @param {String} defaultValue
5362 selectValue : function(path, root, defaultValue){
5363 path = path.replace(trimRe, "");
5364 if(!valueCache[path]){
5365 valueCache[path] = Roo.DomQuery.compile(path, "select");
5367 var n = valueCache[path](root);
5368 n = n[0] ? n[0] : n;
5369 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5370 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5374 * Selects the value of a node, parsing integers and floats.
5375 * @param {String} selector The selector/xpath query
5376 * @param {Node} root (optional) The start of the query (defaults to document).
5377 * @param {Number} defaultValue
5380 selectNumber : function(path, root, defaultValue){
5381 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5382 return parseFloat(v);
5386 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5387 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5388 * @param {String} selector The simple selector to test
5391 is : function(el, ss){
5392 if(typeof el == "string"){
5393 el = document.getElementById(el);
5395 var isArray = (el instanceof Array);
5396 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5397 return isArray ? (result.length == el.length) : (result.length > 0);
5401 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5402 * @param {Array} el An array of elements to filter
5403 * @param {String} selector The simple selector to test
5404 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5405 * the selector instead of the ones that match
5408 filter : function(els, ss, nonMatches){
5409 ss = ss.replace(trimRe, "");
5410 if(!simpleCache[ss]){
5411 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5413 var result = simpleCache[ss](els);
5414 return nonMatches ? quickDiff(result, els) : result;
5418 * Collection of matching regular expressions and code snippets.
5422 select: 'n = byClassName(n, null, " {1} ");'
5424 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5425 select: 'n = byPseudo(n, "{1}", "{2}");'
5427 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5428 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5431 select: 'n = byId(n, null, "{1}");'
5434 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5439 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5440 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5443 "=" : function(a, v){
5446 "!=" : function(a, v){
5449 "^=" : function(a, v){
5450 return a && a.substr(0, v.length) == v;
5452 "$=" : function(a, v){
5453 return a && a.substr(a.length-v.length) == v;
5455 "*=" : function(a, v){
5456 return a && a.indexOf(v) !== -1;
5458 "%=" : function(a, v){
5459 return (a % v) == 0;
5461 "|=" : function(a, v){
5462 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5464 "~=" : function(a, v){
5465 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5470 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5471 * and the argument (if any) supplied in the selector.
5474 "first-child" : function(c){
5475 var r = [], ri = -1, n;
5476 for(var i = 0, ci; ci = n = c[i]; i++){
5477 while((n = n.previousSibling) && n.nodeType != 1);
5485 "last-child" : function(c){
5486 var r = [], ri = -1, n;
5487 for(var i = 0, ci; ci = n = c[i]; i++){
5488 while((n = n.nextSibling) && n.nodeType != 1);
5496 "nth-child" : function(c, a) {
5497 var r = [], ri = -1;
5498 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5499 var f = (m[1] || 1) - 0, l = m[2] - 0;
5500 for(var i = 0, n; n = c[i]; i++){
5501 var pn = n.parentNode;
5502 if (batch != pn._batch) {
5504 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5505 if(cn.nodeType == 1){
5512 if (l == 0 || n.nodeIndex == l){
5515 } else if ((n.nodeIndex + l) % f == 0){
5523 "only-child" : function(c){
5524 var r = [], ri = -1;;
5525 for(var i = 0, ci; ci = c[i]; i++){
5526 if(!prev(ci) && !next(ci)){
5533 "empty" : function(c){
5534 var r = [], ri = -1;
5535 for(var i = 0, ci; ci = c[i]; i++){
5536 var cns = ci.childNodes, j = 0, cn, empty = true;
5539 if(cn.nodeType == 1 || cn.nodeType == 3){
5551 "contains" : function(c, v){
5552 var r = [], ri = -1;
5553 for(var i = 0, ci; ci = c[i]; i++){
5554 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5561 "nodeValue" : function(c, v){
5562 var r = [], ri = -1;
5563 for(var i = 0, ci; ci = c[i]; i++){
5564 if(ci.firstChild && ci.firstChild.nodeValue == v){
5571 "checked" : function(c){
5572 var r = [], ri = -1;
5573 for(var i = 0, ci; ci = c[i]; i++){
5574 if(ci.checked == true){
5581 "not" : function(c, ss){
5582 return Roo.DomQuery.filter(c, ss, true);
5585 "odd" : function(c){
5586 return this["nth-child"](c, "odd");
5589 "even" : function(c){
5590 return this["nth-child"](c, "even");
5593 "nth" : function(c, a){
5594 return c[a-1] || [];
5597 "first" : function(c){
5601 "last" : function(c){
5602 return c[c.length-1] || [];
5605 "has" : function(c, ss){
5606 var s = Roo.DomQuery.select;
5607 var r = [], ri = -1;
5608 for(var i = 0, ci; ci = c[i]; i++){
5609 if(s(ss, ci).length > 0){
5616 "next" : function(c, ss){
5617 var is = Roo.DomQuery.is;
5618 var r = [], ri = -1;
5619 for(var i = 0, ci; ci = c[i]; i++){
5628 "prev" : function(c, ss){
5629 var is = Roo.DomQuery.is;
5630 var r = [], ri = -1;
5631 for(var i = 0, ci; ci = c[i]; i++){
5644 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5645 * @param {String} path The selector/xpath query
5646 * @param {Node} root (optional) The start of the query (defaults to document).
5651 Roo.query = Roo.DomQuery.select;
5654 * Ext JS Library 1.1.1
5655 * Copyright(c) 2006-2007, Ext JS, LLC.
5657 * Originally Released Under LGPL - original licence link has changed is not relivant.
5660 * <script type="text/javascript">
5664 * @class Roo.util.Observable
5665 * Base class that provides a common interface for publishing events. Subclasses are expected to
5666 * to have a property "events" with all the events defined.<br>
5669 Employee = function(name){
5676 Roo.extend(Employee, Roo.util.Observable);
5678 * @param {Object} config properties to use (incuding events / listeners)
5681 Roo.util.Observable = function(cfg){
5684 this.addEvents(cfg.events || {});
5686 delete cfg.events; // make sure
5689 Roo.apply(this, cfg);
5692 this.on(this.listeners);
5693 delete this.listeners;
5696 Roo.util.Observable.prototype = {
5698 * @cfg {Object} listeners list of events and functions to call for this object,
5702 'click' : function(e) {
5712 * Fires the specified event with the passed parameters (minus the event name).
5713 * @param {String} eventName
5714 * @param {Object...} args Variable number of parameters are passed to handlers
5715 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5717 fireEvent : function(){
5718 var ce = this.events[arguments[0].toLowerCase()];
5719 if(typeof ce == "object"){
5720 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5727 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5730 * Appends an event handler to this component
5731 * @param {String} eventName The type of event to listen for
5732 * @param {Function} handler The method the event invokes
5733 * @param {Object} scope (optional) The scope in which to execute the handler
5734 * function. The handler function's "this" context.
5735 * @param {Object} options (optional) An object containing handler configuration
5736 * properties. This may contain any of the following properties:<ul>
5737 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5738 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5739 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5740 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5741 * by the specified number of milliseconds. If the event fires again within that time, the original
5742 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5745 * <b>Combining Options</b><br>
5746 * Using the options argument, it is possible to combine different types of listeners:<br>
5748 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5750 el.on('click', this.onClick, this, {
5757 * <b>Attaching multiple handlers in 1 call</b><br>
5758 * The method also allows for a single argument to be passed which is a config object containing properties
5759 * which specify multiple handlers.
5768 fn: this.onMouseOver,
5772 fn: this.onMouseOut,
5778 * Or a shorthand syntax which passes the same scope object to all handlers:
5781 'click': this.onClick,
5782 'mouseover': this.onMouseOver,
5783 'mouseout': this.onMouseOut,
5788 addListener : function(eventName, fn, scope, o){
5789 if(typeof eventName == "object"){
5792 if(this.filterOptRe.test(e)){
5795 if(typeof o[e] == "function"){
5797 this.addListener(e, o[e], o.scope, o);
5799 // individual options
5800 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5805 o = (!o || typeof o == "boolean") ? {} : o;
5806 eventName = eventName.toLowerCase();
5807 var ce = this.events[eventName] || true;
5808 if(typeof ce == "boolean"){
5809 ce = new Roo.util.Event(this, eventName);
5810 this.events[eventName] = ce;
5812 ce.addListener(fn, scope, o);
5816 * Removes a listener
5817 * @param {String} eventName The type of event to listen for
5818 * @param {Function} handler The handler to remove
5819 * @param {Object} scope (optional) The scope (this object) for the handler
5821 removeListener : function(eventName, fn, scope){
5822 var ce = this.events[eventName.toLowerCase()];
5823 if(typeof ce == "object"){
5824 ce.removeListener(fn, scope);
5829 * Removes all listeners for this object
5831 purgeListeners : function(){
5832 for(var evt in this.events){
5833 if(typeof this.events[evt] == "object"){
5834 this.events[evt].clearListeners();
5839 relayEvents : function(o, events){
5840 var createHandler = function(ename){
5842 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5845 for(var i = 0, len = events.length; i < len; i++){
5846 var ename = events[i];
5847 if(!this.events[ename]){ this.events[ename] = true; };
5848 o.on(ename, createHandler(ename), this);
5853 * Used to define events on this Observable
5854 * @param {Object} object The object with the events defined
5856 addEvents : function(o){
5860 Roo.applyIf(this.events, o);
5864 * Checks to see if this object has any listeners for a specified event
5865 * @param {String} eventName The name of the event to check for
5866 * @return {Boolean} True if the event is being listened for, else false
5868 hasListener : function(eventName){
5869 var e = this.events[eventName];
5870 return typeof e == "object" && e.listeners.length > 0;
5874 * Appends an event handler to this element (shorthand for addListener)
5875 * @param {String} eventName The type of event to listen for
5876 * @param {Function} handler The method the event invokes
5877 * @param {Object} scope (optional) The scope in which to execute the handler
5878 * function. The handler function's "this" context.
5879 * @param {Object} options (optional)
5882 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5884 * Removes a listener (shorthand for removeListener)
5885 * @param {String} eventName The type of event to listen for
5886 * @param {Function} handler The handler to remove
5887 * @param {Object} scope (optional) The scope (this object) for the handler
5890 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5893 * Starts capture on the specified Observable. All events will be passed
5894 * to the supplied function with the event name + standard signature of the event
5895 * <b>before</b> the event is fired. If the supplied function returns false,
5896 * the event will not fire.
5897 * @param {Observable} o The Observable to capture
5898 * @param {Function} fn The function to call
5899 * @param {Object} scope (optional) The scope (this object) for the fn
5902 Roo.util.Observable.capture = function(o, fn, scope){
5903 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5907 * Removes <b>all</b> added captures from the Observable.
5908 * @param {Observable} o The Observable to release
5911 Roo.util.Observable.releaseCapture = function(o){
5912 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5917 var createBuffered = function(h, o, scope){
5918 var task = new Roo.util.DelayedTask();
5920 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5924 var createSingle = function(h, e, fn, scope){
5926 e.removeListener(fn, scope);
5927 return h.apply(scope, arguments);
5931 var createDelayed = function(h, o, scope){
5933 var args = Array.prototype.slice.call(arguments, 0);
5934 setTimeout(function(){
5935 h.apply(scope, args);
5940 Roo.util.Event = function(obj, name){
5943 this.listeners = [];
5946 Roo.util.Event.prototype = {
5947 addListener : function(fn, scope, options){
5948 var o = options || {};
5949 scope = scope || this.obj;
5950 if(!this.isListening(fn, scope)){
5951 var l = {fn: fn, scope: scope, options: o};
5954 h = createDelayed(h, o, scope);
5957 h = createSingle(h, this, fn, scope);
5960 h = createBuffered(h, o, scope);
5963 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5964 this.listeners.push(l);
5966 this.listeners = this.listeners.slice(0);
5967 this.listeners.push(l);
5972 findListener : function(fn, scope){
5973 scope = scope || this.obj;
5974 var ls = this.listeners;
5975 for(var i = 0, len = ls.length; i < len; i++){
5977 if(l.fn == fn && l.scope == scope){
5984 isListening : function(fn, scope){
5985 return this.findListener(fn, scope) != -1;
5988 removeListener : function(fn, scope){
5990 if((index = this.findListener(fn, scope)) != -1){
5992 this.listeners.splice(index, 1);
5994 this.listeners = this.listeners.slice(0);
5995 this.listeners.splice(index, 1);
6002 clearListeners : function(){
6003 this.listeners = [];
6007 var ls = this.listeners, scope, len = ls.length;
6010 var args = Array.prototype.slice.call(arguments, 0);
6011 for(var i = 0; i < len; i++){
6013 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6014 this.firing = false;
6018 this.firing = false;
6025 * Ext JS Library 1.1.1
6026 * Copyright(c) 2006-2007, Ext JS, LLC.
6028 * Originally Released Under LGPL - original licence link has changed is not relivant.
6031 * <script type="text/javascript">
6035 * @class Roo.EventManager
6036 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6037 * several useful events directly.
6038 * See {@link Roo.EventObject} for more details on normalized event objects.
6041 Roo.EventManager = function(){
6042 var docReadyEvent, docReadyProcId, docReadyState = false;
6043 var resizeEvent, resizeTask, textEvent, textSize;
6044 var E = Roo.lib.Event;
6045 var D = Roo.lib.Dom;
6048 var fireDocReady = function(){
6050 docReadyState = true;
6053 clearInterval(docReadyProcId);
6055 if(Roo.isGecko || Roo.isOpera) {
6056 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6059 var defer = document.getElementById("ie-deferred-loader");
6061 defer.onreadystatechange = null;
6062 defer.parentNode.removeChild(defer);
6066 docReadyEvent.fire();
6067 docReadyEvent.clearListeners();
6072 var initDocReady = function(){
6073 docReadyEvent = new Roo.util.Event();
6074 if(Roo.isGecko || Roo.isOpera) {
6075 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6077 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6078 var defer = document.getElementById("ie-deferred-loader");
6079 defer.onreadystatechange = function(){
6080 if(this.readyState == "complete"){
6084 }else if(Roo.isSafari){
6085 docReadyProcId = setInterval(function(){
6086 var rs = document.readyState;
6087 if(rs == "complete") {
6092 // no matter what, make sure it fires on load
6093 E.on(window, "load", fireDocReady);
6096 var createBuffered = function(h, o){
6097 var task = new Roo.util.DelayedTask(h);
6099 // create new event object impl so new events don't wipe out properties
6100 e = new Roo.EventObjectImpl(e);
6101 task.delay(o.buffer, h, null, [e]);
6105 var createSingle = function(h, el, ename, fn){
6107 Roo.EventManager.removeListener(el, ename, fn);
6112 var createDelayed = function(h, o){
6114 // create new event object impl so new events don't wipe out properties
6115 e = new Roo.EventObjectImpl(e);
6116 setTimeout(function(){
6122 var listen = function(element, ename, opt, fn, scope){
6123 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6124 fn = fn || o.fn; scope = scope || o.scope;
6125 var el = Roo.getDom(element);
6127 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6129 var h = function(e){
6130 e = Roo.EventObject.setEvent(e);
6133 t = e.getTarget(o.delegate, el);
6140 if(o.stopEvent === true){
6143 if(o.preventDefault === true){
6146 if(o.stopPropagation === true){
6147 e.stopPropagation();
6150 if(o.normalized === false){
6154 fn.call(scope || el, e, t, o);
6157 h = createDelayed(h, o);
6160 h = createSingle(h, el, ename, fn);
6163 h = createBuffered(h, o);
6165 fn._handlers = fn._handlers || [];
6166 fn._handlers.push([Roo.id(el), ename, h]);
6169 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6170 el.addEventListener("DOMMouseScroll", h, false);
6171 E.on(window, 'unload', function(){
6172 el.removeEventListener("DOMMouseScroll", h, false);
6175 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6176 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6181 var stopListening = function(el, ename, fn){
6182 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6184 for(var i = 0, len = hds.length; i < len; i++){
6186 if(h[0] == id && h[1] == ename){
6193 E.un(el, ename, hd);
6194 el = Roo.getDom(el);
6195 if(ename == "mousewheel" && el.addEventListener){
6196 el.removeEventListener("DOMMouseScroll", hd, false);
6198 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6199 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6203 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6210 * @scope Roo.EventManager
6215 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6216 * object with a Roo.EventObject
6217 * @param {Function} fn The method the event invokes
6218 * @param {Object} scope An object that becomes the scope of the handler
6219 * @param {boolean} override If true, the obj passed in becomes
6220 * the execution scope of the listener
6221 * @return {Function} The wrapped function
6224 wrap : function(fn, scope, override){
6226 Roo.EventObject.setEvent(e);
6227 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6232 * Appends an event handler to an element (shorthand for addListener)
6233 * @param {String/HTMLElement} element The html element or id to assign the
6234 * @param {String} eventName The type of event to listen for
6235 * @param {Function} handler The method the event invokes
6236 * @param {Object} scope (optional) The scope in which to execute the handler
6237 * function. The handler function's "this" context.
6238 * @param {Object} options (optional) An object containing handler configuration
6239 * properties. This may contain any of the following properties:<ul>
6240 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6241 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6242 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6243 * <li>preventDefault {Boolean} True to prevent the default action</li>
6244 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6245 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6246 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6247 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6248 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6249 * by the specified number of milliseconds. If the event fires again within that time, the original
6250 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6253 * <b>Combining Options</b><br>
6254 * Using the options argument, it is possible to combine different types of listeners:<br>
6256 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6258 el.on('click', this.onClick, this, {
6265 * <b>Attaching multiple handlers in 1 call</b><br>
6266 * The method also allows for a single argument to be passed which is a config object containing properties
6267 * which specify multiple handlers.
6277 fn: this.onMouseOver
6286 * Or a shorthand syntax:<br>
6289 'click' : this.onClick,
6290 'mouseover' : this.onMouseOver,
6291 'mouseout' : this.onMouseOut
6295 addListener : function(element, eventName, fn, scope, options){
6296 if(typeof eventName == "object"){
6302 if(typeof o[e] == "function"){
6304 listen(element, e, o, o[e], o.scope);
6306 // individual options
6307 listen(element, e, o[e]);
6312 return listen(element, eventName, options, fn, scope);
6316 * Removes an event handler
6318 * @param {String/HTMLElement} element The id or html element to remove the
6320 * @param {String} eventName The type of event
6321 * @param {Function} fn
6322 * @return {Boolean} True if a listener was actually removed
6324 removeListener : function(element, eventName, fn){
6325 return stopListening(element, eventName, fn);
6329 * Fires when the document is ready (before onload and before images are loaded). Can be
6330 * accessed shorthanded Roo.onReady().
6331 * @param {Function} fn The method the event invokes
6332 * @param {Object} scope An object that becomes the scope of the handler
6333 * @param {boolean} options
6335 onDocumentReady : function(fn, scope, options){
6336 if(docReadyState){ // if it already fired
6337 docReadyEvent.addListener(fn, scope, options);
6338 docReadyEvent.fire();
6339 docReadyEvent.clearListeners();
6345 docReadyEvent.addListener(fn, scope, options);
6349 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6350 * @param {Function} fn The method the event invokes
6351 * @param {Object} scope An object that becomes the scope of the handler
6352 * @param {boolean} options
6354 onWindowResize : function(fn, scope, options){
6356 resizeEvent = new Roo.util.Event();
6357 resizeTask = new Roo.util.DelayedTask(function(){
6358 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6360 E.on(window, "resize", function(){
6362 resizeTask.delay(50);
6364 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6368 resizeEvent.addListener(fn, scope, options);
6372 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6373 * @param {Function} fn The method the event invokes
6374 * @param {Object} scope An object that becomes the scope of the handler
6375 * @param {boolean} options
6377 onTextResize : function(fn, scope, options){
6379 textEvent = new Roo.util.Event();
6380 var textEl = new Roo.Element(document.createElement('div'));
6381 textEl.dom.className = 'x-text-resize';
6382 textEl.dom.innerHTML = 'X';
6383 textEl.appendTo(document.body);
6384 textSize = textEl.dom.offsetHeight;
6385 setInterval(function(){
6386 if(textEl.dom.offsetHeight != textSize){
6387 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6389 }, this.textResizeInterval);
6391 textEvent.addListener(fn, scope, options);
6395 * Removes the passed window resize listener.
6396 * @param {Function} fn The method the event invokes
6397 * @param {Object} scope The scope of handler
6399 removeResizeListener : function(fn, scope){
6401 resizeEvent.removeListener(fn, scope);
6406 fireResize : function(){
6408 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6412 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6416 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6418 textResizeInterval : 50
6423 * @scopeAlias pub=Roo.EventManager
6427 * Appends an event handler to an element (shorthand for addListener)
6428 * @param {String/HTMLElement} element The html element or id to assign the
6429 * @param {String} eventName The type of event to listen for
6430 * @param {Function} handler The method the event invokes
6431 * @param {Object} scope (optional) The scope in which to execute the handler
6432 * function. The handler function's "this" context.
6433 * @param {Object} options (optional) An object containing handler configuration
6434 * properties. This may contain any of the following properties:<ul>
6435 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6436 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6437 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6438 * <li>preventDefault {Boolean} True to prevent the default action</li>
6439 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6440 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6441 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6442 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6443 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6444 * by the specified number of milliseconds. If the event fires again within that time, the original
6445 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6448 * <b>Combining Options</b><br>
6449 * Using the options argument, it is possible to combine different types of listeners:<br>
6451 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6453 el.on('click', this.onClick, this, {
6460 * <b>Attaching multiple handlers in 1 call</b><br>
6461 * The method also allows for a single argument to be passed which is a config object containing properties
6462 * which specify multiple handlers.
6472 fn: this.onMouseOver
6481 * Or a shorthand syntax:<br>
6484 'click' : this.onClick,
6485 'mouseover' : this.onMouseOver,
6486 'mouseout' : this.onMouseOut
6490 pub.on = pub.addListener;
6491 pub.un = pub.removeListener;
6493 pub.stoppedMouseDownEvent = new Roo.util.Event();
6497 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6498 * @param {Function} fn The method the event invokes
6499 * @param {Object} scope An object that becomes the scope of the handler
6500 * @param {boolean} override If true, the obj passed in becomes
6501 * the execution scope of the listener
6505 Roo.onReady = Roo.EventManager.onDocumentReady;
6507 Roo.onReady(function(){
6508 var bd = Roo.get(document.body);
6513 : Roo.isGecko ? "roo-gecko"
6514 : Roo.isOpera ? "roo-opera"
6515 : Roo.isSafari ? "roo-safari" : ""];
6518 cls.push("roo-mac");
6521 cls.push("roo-linux");
6523 if(Roo.isBorderBox){
6524 cls.push('roo-border-box');
6526 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6527 var p = bd.dom.parentNode;
6529 p.className += ' roo-strict';
6532 bd.addClass(cls.join(' '));
6536 * @class Roo.EventObject
6537 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6538 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6541 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6543 var target = e.getTarget();
6546 var myDiv = Roo.get("myDiv");
6547 myDiv.on("click", handleClick);
6549 Roo.EventManager.on("myDiv", 'click', handleClick);
6550 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6554 Roo.EventObject = function(){
6556 var E = Roo.lib.Event;
6558 // safari keypress events for special keys return bad keycodes
6561 63235 : 39, // right
6564 63276 : 33, // page up
6565 63277 : 34, // page down
6566 63272 : 46, // delete
6571 // normalize button clicks
6572 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6573 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6575 Roo.EventObjectImpl = function(e){
6577 this.setEvent(e.browserEvent || e);
6580 Roo.EventObjectImpl.prototype = {
6582 * Used to fix doc tools.
6583 * @scope Roo.EventObject.prototype
6589 /** The normal browser event */
6590 browserEvent : null,
6591 /** The button pressed in a mouse event */
6593 /** True if the shift key was down during the event */
6595 /** True if the control key was down during the event */
6597 /** True if the alt key was down during the event */
6656 setEvent : function(e){
6657 if(e == this || (e && e.browserEvent)){ // already wrapped
6660 this.browserEvent = e;
6662 // normalize buttons
6663 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6664 if(e.type == 'click' && this.button == -1){
6668 this.shiftKey = e.shiftKey;
6669 // mac metaKey behaves like ctrlKey
6670 this.ctrlKey = e.ctrlKey || e.metaKey;
6671 this.altKey = e.altKey;
6672 // in getKey these will be normalized for the mac
6673 this.keyCode = e.keyCode;
6674 // keyup warnings on firefox.
6675 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6676 // cache the target for the delayed and or buffered events
6677 this.target = E.getTarget(e);
6679 this.xy = E.getXY(e);
6682 this.shiftKey = false;
6683 this.ctrlKey = false;
6684 this.altKey = false;
6694 * Stop the event (preventDefault and stopPropagation)
6696 stopEvent : function(){
6697 if(this.browserEvent){
6698 if(this.browserEvent.type == 'mousedown'){
6699 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6701 E.stopEvent(this.browserEvent);
6706 * Prevents the browsers default handling of the event.
6708 preventDefault : function(){
6709 if(this.browserEvent){
6710 E.preventDefault(this.browserEvent);
6715 isNavKeyPress : function(){
6716 var k = this.keyCode;
6717 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6718 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6721 isSpecialKey : function(){
6722 var k = this.keyCode;
6723 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6724 (k == 16) || (k == 17) ||
6725 (k >= 18 && k <= 20) ||
6726 (k >= 33 && k <= 35) ||
6727 (k >= 36 && k <= 39) ||
6728 (k >= 44 && k <= 45);
6731 * Cancels bubbling of the event.
6733 stopPropagation : function(){
6734 if(this.browserEvent){
6735 if(this.type == 'mousedown'){
6736 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6738 E.stopPropagation(this.browserEvent);
6743 * Gets the key code for the event.
6746 getCharCode : function(){
6747 return this.charCode || this.keyCode;
6751 * Returns a normalized keyCode for the event.
6752 * @return {Number} The key code
6754 getKey : function(){
6755 var k = this.keyCode || this.charCode;
6756 return Roo.isSafari ? (safariKeys[k] || k) : k;
6760 * Gets the x coordinate of the event.
6763 getPageX : function(){
6768 * Gets the y coordinate of the event.
6771 getPageY : function(){
6776 * Gets the time of the event.
6779 getTime : function(){
6780 if(this.browserEvent){
6781 return E.getTime(this.browserEvent);
6787 * Gets the page coordinates of the event.
6788 * @return {Array} The xy values like [x, y]
6795 * Gets the target for the event.
6796 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6797 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6798 search as a number or element (defaults to 10 || document.body)
6799 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6800 * @return {HTMLelement}
6802 getTarget : function(selector, maxDepth, returnEl){
6803 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6806 * Gets the related target.
6807 * @return {HTMLElement}
6809 getRelatedTarget : function(){
6810 if(this.browserEvent){
6811 return E.getRelatedTarget(this.browserEvent);
6817 * Normalizes mouse wheel delta across browsers
6818 * @return {Number} The delta
6820 getWheelDelta : function(){
6821 var e = this.browserEvent;
6823 if(e.wheelDelta){ /* IE/Opera. */
6824 delta = e.wheelDelta/120;
6825 }else if(e.detail){ /* Mozilla case. */
6826 delta = -e.detail/3;
6832 * Returns true if the control, meta, shift or alt key was pressed during this event.
6835 hasModifier : function(){
6836 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6840 * Returns true if the target of this event equals el or is a child of el
6841 * @param {String/HTMLElement/Element} el
6842 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6845 within : function(el, related){
6846 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6847 return t && Roo.fly(el).contains(t);
6850 getPoint : function(){
6851 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6855 return new Roo.EventObjectImpl();
6860 * Ext JS Library 1.1.1
6861 * Copyright(c) 2006-2007, Ext JS, LLC.
6863 * Originally Released Under LGPL - original licence link has changed is not relivant.
6866 * <script type="text/javascript">
6870 // was in Composite Element!??!?!
6873 var D = Roo.lib.Dom;
6874 var E = Roo.lib.Event;
6875 var A = Roo.lib.Anim;
6877 // local style camelizing for speed
6879 var camelRe = /(-[a-z])/gi;
6880 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6881 var view = document.defaultView;
6884 * @class Roo.Element
6885 * Represents an Element in the DOM.<br><br>
6888 var el = Roo.get("my-div");
6891 var el = getEl("my-div");
6893 // or with a DOM element
6894 var el = Roo.get(myDivElement);
6896 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6897 * each call instead of constructing a new one.<br><br>
6898 * <b>Animations</b><br />
6899 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6900 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6902 Option Default Description
6903 --------- -------- ---------------------------------------------
6904 duration .35 The duration of the animation in seconds
6905 easing easeOut The YUI easing method
6906 callback none A function to execute when the anim completes
6907 scope this The scope (this) of the callback function
6909 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6910 * manipulate the animation. Here's an example:
6912 var el = Roo.get("my-div");
6917 // default animation
6918 el.setWidth(100, true);
6920 // animation with some options set
6927 // using the "anim" property to get the Anim object
6933 el.setWidth(100, opt);
6935 if(opt.anim.isAnimated()){
6939 * <b> Composite (Collections of) Elements</b><br />
6940 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6941 * @constructor Create a new Element directly.
6942 * @param {String/HTMLElement} element
6943 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6945 Roo.Element = function(element, forceNew){
6946 var dom = typeof element == "string" ?
6947 document.getElementById(element) : element;
6948 if(!dom){ // invalid id/element
6952 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6953 return Roo.Element.cache[id];
6963 * The DOM element ID
6966 this.id = id || Roo.id(dom);
6969 var El = Roo.Element;
6973 * The element's default display mode (defaults to "")
6976 originalDisplay : "",
6980 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6985 * Sets the element's visibility mode. When setVisible() is called it
6986 * will use this to determine whether to set the visibility or the display property.
6987 * @param visMode Element.VISIBILITY or Element.DISPLAY
6988 * @return {Roo.Element} this
6990 setVisibilityMode : function(visMode){
6991 this.visibilityMode = visMode;
6995 * Convenience method for setVisibilityMode(Element.DISPLAY)
6996 * @param {String} display (optional) What to set display to when visible
6997 * @return {Roo.Element} this
6999 enableDisplayMode : function(display){
7000 this.setVisibilityMode(El.DISPLAY);
7001 if(typeof display != "undefined") this.originalDisplay = display;
7006 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7007 * @param {String} selector The simple selector to test
7008 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7009 search as a number or element (defaults to 10 || document.body)
7010 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7011 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7013 findParent : function(simpleSelector, maxDepth, returnEl){
7014 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7015 maxDepth = maxDepth || 50;
7016 if(typeof maxDepth != "number"){
7017 stopEl = Roo.getDom(maxDepth);
7020 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7021 if(dq.is(p, simpleSelector)){
7022 return returnEl ? Roo.get(p) : p;
7032 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7033 * @param {String} selector The simple selector to test
7034 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7035 search as a number or element (defaults to 10 || document.body)
7036 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7037 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7039 findParentNode : function(simpleSelector, maxDepth, returnEl){
7040 var p = Roo.fly(this.dom.parentNode, '_internal');
7041 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7045 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7046 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7047 * @param {String} selector The simple selector to test
7048 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7049 search as a number or element (defaults to 10 || document.body)
7050 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7052 up : function(simpleSelector, maxDepth){
7053 return this.findParentNode(simpleSelector, maxDepth, true);
7059 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7060 * @param {String} selector The simple selector to test
7061 * @return {Boolean} True if this element matches the selector, else false
7063 is : function(simpleSelector){
7064 return Roo.DomQuery.is(this.dom, simpleSelector);
7068 * Perform animation on this element.
7069 * @param {Object} args The YUI animation control args
7070 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7071 * @param {Function} onComplete (optional) Function to call when animation completes
7072 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7073 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7074 * @return {Roo.Element} this
7076 animate : function(args, duration, onComplete, easing, animType){
7077 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7082 * @private Internal animation call
7084 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7085 animType = animType || 'run';
7087 var anim = Roo.lib.Anim[animType](
7089 (opt.duration || defaultDur) || .35,
7090 (opt.easing || defaultEase) || 'easeOut',
7092 Roo.callback(cb, this);
7093 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7101 // private legacy anim prep
7102 preanim : function(a, i){
7103 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7107 * Removes worthless text nodes
7108 * @param {Boolean} forceReclean (optional) By default the element
7109 * keeps track if it has been cleaned already so
7110 * you can call this over and over. However, if you update the element and
7111 * need to force a reclean, you can pass true.
7113 clean : function(forceReclean){
7114 if(this.isCleaned && forceReclean !== true){
7118 var d = this.dom, n = d.firstChild, ni = -1;
7120 var nx = n.nextSibling;
7121 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7128 this.isCleaned = true;
7133 calcOffsetsTo : function(el){
7136 var restorePos = false;
7137 if(el.getStyle('position') == 'static'){
7138 el.position('relative');
7143 while(op && op != d && op.tagName != 'HTML'){
7146 op = op.offsetParent;
7149 el.position('static');
7155 * Scrolls this element into view within the passed container.
7156 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7157 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7158 * @return {Roo.Element} this
7160 scrollIntoView : function(container, hscroll){
7161 var c = Roo.getDom(container) || document.body;
7164 var o = this.calcOffsetsTo(c),
7167 b = t+el.offsetHeight,
7168 r = l+el.offsetWidth;
7170 var ch = c.clientHeight;
7171 var ct = parseInt(c.scrollTop, 10);
7172 var cl = parseInt(c.scrollLeft, 10);
7174 var cr = cl + c.clientWidth;
7182 if(hscroll !== false){
7186 c.scrollLeft = r-c.clientWidth;
7193 scrollChildIntoView : function(child, hscroll){
7194 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7198 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7199 * the new height may not be available immediately.
7200 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7201 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7202 * @param {Function} onComplete (optional) Function to call when animation completes
7203 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7204 * @return {Roo.Element} this
7206 autoHeight : function(animate, duration, onComplete, easing){
7207 var oldHeight = this.getHeight();
7209 this.setHeight(1); // force clipping
7210 setTimeout(function(){
7211 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7213 this.setHeight(height);
7215 if(typeof onComplete == "function"){
7219 this.setHeight(oldHeight); // restore original height
7220 this.setHeight(height, animate, duration, function(){
7222 if(typeof onComplete == "function") onComplete();
7223 }.createDelegate(this), easing);
7225 }.createDelegate(this), 0);
7230 * Returns true if this element is an ancestor of the passed element
7231 * @param {HTMLElement/String} el The element to check
7232 * @return {Boolean} True if this element is an ancestor of el, else false
7234 contains : function(el){
7235 if(!el){return false;}
7236 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7240 * Checks whether the element is currently visible using both visibility and display properties.
7241 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7242 * @return {Boolean} True if the element is currently visible, else false
7244 isVisible : function(deep) {
7245 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7246 if(deep !== true || !vis){
7249 var p = this.dom.parentNode;
7250 while(p && p.tagName.toLowerCase() != "body"){
7251 if(!Roo.fly(p, '_isVisible').isVisible()){
7260 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7261 * @param {String} selector The CSS selector
7262 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7263 * @return {CompositeElement/CompositeElementLite} The composite element
7265 select : function(selector, unique){
7266 return El.select(selector, unique, this.dom);
7270 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7271 * @param {String} selector The CSS selector
7272 * @return {Array} An array of the matched nodes
7274 query : function(selector, unique){
7275 return Roo.DomQuery.select(selector, this.dom);
7279 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7280 * @param {String} selector The CSS selector
7281 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7282 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284 child : function(selector, returnDom){
7285 var n = Roo.DomQuery.selectNode(selector, this.dom);
7286 return returnDom ? n : Roo.get(n);
7290 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7291 * @param {String} selector The CSS selector
7292 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7293 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7295 down : function(selector, returnDom){
7296 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7297 return returnDom ? n : Roo.get(n);
7301 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7302 * @param {String} group The group the DD object is member of
7303 * @param {Object} config The DD config object
7304 * @param {Object} overrides An object containing methods to override/implement on the DD object
7305 * @return {Roo.dd.DD} The DD object
7307 initDD : function(group, config, overrides){
7308 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7309 return Roo.apply(dd, overrides);
7313 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7314 * @param {String} group The group the DDProxy object is member of
7315 * @param {Object} config The DDProxy config object
7316 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7317 * @return {Roo.dd.DDProxy} The DDProxy object
7319 initDDProxy : function(group, config, overrides){
7320 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7321 return Roo.apply(dd, overrides);
7325 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7326 * @param {String} group The group the DDTarget object is member of
7327 * @param {Object} config The DDTarget config object
7328 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7329 * @return {Roo.dd.DDTarget} The DDTarget object
7331 initDDTarget : function(group, config, overrides){
7332 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7333 return Roo.apply(dd, overrides);
7337 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7338 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7339 * @param {Boolean} visible Whether the element is visible
7340 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7341 * @return {Roo.Element} this
7343 setVisible : function(visible, animate){
7345 if(this.visibilityMode == El.DISPLAY){
7346 this.setDisplayed(visible);
7349 this.dom.style.visibility = visible ? "visible" : "hidden";
7352 // closure for composites
7354 var visMode = this.visibilityMode;
7356 this.setOpacity(.01);
7357 this.setVisible(true);
7359 this.anim({opacity: { to: (visible?1:0) }},
7360 this.preanim(arguments, 1),
7361 null, .35, 'easeIn', function(){
7363 if(visMode == El.DISPLAY){
7364 dom.style.display = "none";
7366 dom.style.visibility = "hidden";
7368 Roo.get(dom).setOpacity(1);
7376 * Returns true if display is not "none"
7379 isDisplayed : function() {
7380 return this.getStyle("display") != "none";
7384 * Toggles the element's visibility or display, depending on visibility mode.
7385 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7386 * @return {Roo.Element} this
7388 toggle : function(animate){
7389 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7394 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7395 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7396 * @return {Roo.Element} this
7398 setDisplayed : function(value) {
7399 if(typeof value == "boolean"){
7400 value = value ? this.originalDisplay : "none";
7402 this.setStyle("display", value);
7407 * Tries to focus the element. Any exceptions are caught and ignored.
7408 * @return {Roo.Element} this
7410 focus : function() {
7418 * Tries to blur the element. Any exceptions are caught and ignored.
7419 * @return {Roo.Element} this
7429 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7430 * @param {String/Array} className The CSS class to add, or an array of classes
7431 * @return {Roo.Element} this
7433 addClass : function(className){
7434 if(className instanceof Array){
7435 for(var i = 0, len = className.length; i < len; i++) {
7436 this.addClass(className[i]);
7439 if(className && !this.hasClass(className)){
7440 this.dom.className = this.dom.className + " " + className;
7447 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7448 * @param {String/Array} className The CSS class to add, or an array of classes
7449 * @return {Roo.Element} this
7451 radioClass : function(className){
7452 var siblings = this.dom.parentNode.childNodes;
7453 for(var i = 0; i < siblings.length; i++) {
7454 var s = siblings[i];
7455 if(s.nodeType == 1){
7456 Roo.get(s).removeClass(className);
7459 this.addClass(className);
7464 * Removes one or more CSS classes from the element.
7465 * @param {String/Array} className The CSS class to remove, or an array of classes
7466 * @return {Roo.Element} this
7468 removeClass : function(className){
7469 if(!className || !this.dom.className){
7472 if(className instanceof Array){
7473 for(var i = 0, len = className.length; i < len; i++) {
7474 this.removeClass(className[i]);
7477 if(this.hasClass(className)){
7478 var re = this.classReCache[className];
7480 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7481 this.classReCache[className] = re;
7483 this.dom.className =
7484 this.dom.className.replace(re, " ");
7494 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7495 * @param {String} className The CSS class to toggle
7496 * @return {Roo.Element} this
7498 toggleClass : function(className){
7499 if(this.hasClass(className)){
7500 this.removeClass(className);
7502 this.addClass(className);
7508 * Checks if the specified CSS class exists on this element's DOM node.
7509 * @param {String} className The CSS class to check for
7510 * @return {Boolean} True if the class exists, else false
7512 hasClass : function(className){
7513 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7517 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7518 * @param {String} oldClassName The CSS class to replace
7519 * @param {String} newClassName The replacement CSS class
7520 * @return {Roo.Element} this
7522 replaceClass : function(oldClassName, newClassName){
7523 this.removeClass(oldClassName);
7524 this.addClass(newClassName);
7529 * Returns an object with properties matching the styles requested.
7530 * For example, el.getStyles('color', 'font-size', 'width') might return
7531 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7532 * @param {String} style1 A style name
7533 * @param {String} style2 A style name
7534 * @param {String} etc.
7535 * @return {Object} The style object
7537 getStyles : function(){
7538 var a = arguments, len = a.length, r = {};
7539 for(var i = 0; i < len; i++){
7540 r[a[i]] = this.getStyle(a[i]);
7546 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7547 * @param {String} property The style property whose value is returned.
7548 * @return {String} The current value of the style property for this element.
7550 getStyle : function(){
7551 return view && view.getComputedStyle ?
7553 var el = this.dom, v, cs, camel;
7554 if(prop == 'float'){
7557 if(el.style && (v = el.style[prop])){
7560 if(cs = view.getComputedStyle(el, "")){
7561 if(!(camel = propCache[prop])){
7562 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7569 var el = this.dom, v, cs, camel;
7570 if(prop == 'opacity'){
7571 if(typeof el.style.filter == 'string'){
7572 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7574 var fv = parseFloat(m[1]);
7576 return fv ? fv / 100 : 0;
7581 }else if(prop == 'float'){
7582 prop = "styleFloat";
7584 if(!(camel = propCache[prop])){
7585 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7587 if(v = el.style[camel]){
7590 if(cs = el.currentStyle){
7598 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7599 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7600 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7601 * @return {Roo.Element} this
7603 setStyle : function(prop, value){
7604 if(typeof prop == "string"){
7606 if (prop == 'float') {
7607 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7612 if(!(camel = propCache[prop])){
7613 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7616 if(camel == 'opacity') {
7617 this.setOpacity(value);
7619 this.dom.style[camel] = value;
7622 for(var style in prop){
7623 if(typeof prop[style] != "function"){
7624 this.setStyle(style, prop[style]);
7632 * More flexible version of {@link #setStyle} for setting style properties.
7633 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7634 * a function which returns such a specification.
7635 * @return {Roo.Element} this
7637 applyStyles : function(style){
7638 Roo.DomHelper.applyStyles(this.dom, style);
7643 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7644 * @return {Number} The X position of the element
7647 return D.getX(this.dom);
7651 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7652 * @return {Number} The Y position of the element
7655 return D.getY(this.dom);
7659 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7660 * @return {Array} The XY position of the element
7663 return D.getXY(this.dom);
7667 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7668 * @param {Number} The X position of the element
7669 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7670 * @return {Roo.Element} this
7672 setX : function(x, animate){
7674 D.setX(this.dom, x);
7676 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7682 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7683 * @param {Number} The Y position of the element
7684 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7685 * @return {Roo.Element} this
7687 setY : function(y, animate){
7689 D.setY(this.dom, y);
7691 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7697 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7698 * @param {String} left The left CSS property value
7699 * @return {Roo.Element} this
7701 setLeft : function(left){
7702 this.setStyle("left", this.addUnits(left));
7707 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7708 * @param {String} top The top CSS property value
7709 * @return {Roo.Element} this
7711 setTop : function(top){
7712 this.setStyle("top", this.addUnits(top));
7717 * Sets the element's CSS right style.
7718 * @param {String} right The right CSS property value
7719 * @return {Roo.Element} this
7721 setRight : function(right){
7722 this.setStyle("right", this.addUnits(right));
7727 * Sets the element's CSS bottom style.
7728 * @param {String} bottom The bottom CSS property value
7729 * @return {Roo.Element} this
7731 setBottom : function(bottom){
7732 this.setStyle("bottom", this.addUnits(bottom));
7737 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7738 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7739 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7740 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7741 * @return {Roo.Element} this
7743 setXY : function(pos, animate){
7745 D.setXY(this.dom, pos);
7747 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7753 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7754 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7755 * @param {Number} x X value for new position (coordinates are page-based)
7756 * @param {Number} y Y value for new position (coordinates are page-based)
7757 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7758 * @return {Roo.Element} this
7760 setLocation : function(x, y, animate){
7761 this.setXY([x, y], this.preanim(arguments, 2));
7766 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7767 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7768 * @param {Number} x X value for new position (coordinates are page-based)
7769 * @param {Number} y Y value for new position (coordinates are page-based)
7770 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7771 * @return {Roo.Element} this
7773 moveTo : function(x, y, animate){
7774 this.setXY([x, y], this.preanim(arguments, 2));
7779 * Returns the region of the given element.
7780 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7781 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7783 getRegion : function(){
7784 return D.getRegion(this.dom);
7788 * Returns the offset height of the element
7789 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7790 * @return {Number} The element's height
7792 getHeight : function(contentHeight){
7793 var h = this.dom.offsetHeight || 0;
7794 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7798 * Returns the offset width of the element
7799 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7800 * @return {Number} The element's width
7802 getWidth : function(contentWidth){
7803 var w = this.dom.offsetWidth || 0;
7804 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7808 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7809 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7810 * if a height has not been set using CSS.
7813 getComputedHeight : function(){
7814 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7816 h = parseInt(this.getStyle('height'), 10) || 0;
7817 if(!this.isBorderBox()){
7818 h += this.getFrameWidth('tb');
7825 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7826 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7827 * if a width has not been set using CSS.
7830 getComputedWidth : function(){
7831 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7833 w = parseInt(this.getStyle('width'), 10) || 0;
7834 if(!this.isBorderBox()){
7835 w += this.getFrameWidth('lr');
7842 * Returns the size of the element.
7843 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7844 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7846 getSize : function(contentSize){
7847 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7851 * Returns the width and height of the viewport.
7852 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7854 getViewSize : function(){
7855 var d = this.dom, doc = document, aw = 0, ah = 0;
7856 if(d == doc || d == doc.body){
7857 return {width : D.getViewWidth(), height: D.getViewHeight()};
7860 width : d.clientWidth,
7861 height: d.clientHeight
7867 * Returns the value of the "value" attribute
7868 * @param {Boolean} asNumber true to parse the value as a number
7869 * @return {String/Number}
7871 getValue : function(asNumber){
7872 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7876 adjustWidth : function(width){
7877 if(typeof width == "number"){
7878 if(this.autoBoxAdjust && !this.isBorderBox()){
7879 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7889 adjustHeight : function(height){
7890 if(typeof height == "number"){
7891 if(this.autoBoxAdjust && !this.isBorderBox()){
7892 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7902 * Set the width of the element
7903 * @param {Number} width The new width
7904 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7905 * @return {Roo.Element} this
7907 setWidth : function(width, animate){
7908 width = this.adjustWidth(width);
7910 this.dom.style.width = this.addUnits(width);
7912 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7918 * Set the height of the element
7919 * @param {Number} height The new height
7920 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7921 * @return {Roo.Element} this
7923 setHeight : function(height, animate){
7924 height = this.adjustHeight(height);
7926 this.dom.style.height = this.addUnits(height);
7928 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7934 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7935 * @param {Number} width The new width
7936 * @param {Number} height The new height
7937 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7938 * @return {Roo.Element} this
7940 setSize : function(width, height, animate){
7941 if(typeof width == "object"){ // in case of object from getSize()
7942 height = width.height; width = width.width;
7944 width = this.adjustWidth(width); height = this.adjustHeight(height);
7946 this.dom.style.width = this.addUnits(width);
7947 this.dom.style.height = this.addUnits(height);
7949 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7955 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7956 * @param {Number} x X value for new position (coordinates are page-based)
7957 * @param {Number} y Y value for new position (coordinates are page-based)
7958 * @param {Number} width The new width
7959 * @param {Number} height The new height
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setBounds : function(x, y, width, height, animate){
7965 this.setSize(width, height);
7966 this.setLocation(x, y);
7968 width = this.adjustWidth(width); height = this.adjustHeight(height);
7969 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7970 this.preanim(arguments, 4), 'motion');
7976 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7977 * @param {Roo.lib.Region} region The region to fill
7978 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7979 * @return {Roo.Element} this
7981 setRegion : function(region, animate){
7982 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7987 * Appends an event handler
7989 * @param {String} eventName The type of event to append
7990 * @param {Function} fn The method the event invokes
7991 * @param {Object} scope (optional) The scope (this object) of the fn
7992 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7994 addListener : function(eventName, fn, scope, options){
7996 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8001 * Removes an event handler from this element
8002 * @param {String} eventName the type of event to remove
8003 * @param {Function} fn the method the event invokes
8004 * @return {Roo.Element} this
8006 removeListener : function(eventName, fn){
8007 Roo.EventManager.removeListener(this.dom, eventName, fn);
8012 * Removes all previous added listeners from this element
8013 * @return {Roo.Element} this
8015 removeAllListeners : function(){
8016 E.purgeElement(this.dom);
8020 relayEvent : function(eventName, observable){
8021 this.on(eventName, function(e){
8022 observable.fireEvent(eventName, e);
8027 * Set the opacity of the element
8028 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8029 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8030 * @return {Roo.Element} this
8032 setOpacity : function(opacity, animate){
8034 var s = this.dom.style;
8037 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8038 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8040 s.opacity = opacity;
8043 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8049 * Gets the left X coordinate
8050 * @param {Boolean} local True to get the local css position instead of page coordinate
8053 getLeft : function(local){
8057 return parseInt(this.getStyle("left"), 10) || 0;
8062 * Gets the right X coordinate of the element (element X position + element width)
8063 * @param {Boolean} local True to get the local css position instead of page coordinate
8066 getRight : function(local){
8068 return this.getX() + this.getWidth();
8070 return (this.getLeft(true) + this.getWidth()) || 0;
8075 * Gets the top Y coordinate
8076 * @param {Boolean} local True to get the local css position instead of page coordinate
8079 getTop : function(local) {
8083 return parseInt(this.getStyle("top"), 10) || 0;
8088 * Gets the bottom Y coordinate of the element (element Y position + element height)
8089 * @param {Boolean} local True to get the local css position instead of page coordinate
8092 getBottom : function(local){
8094 return this.getY() + this.getHeight();
8096 return (this.getTop(true) + this.getHeight()) || 0;
8101 * Initializes positioning on this element. If a desired position is not passed, it will make the
8102 * the element positioned relative IF it is not already positioned.
8103 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8104 * @param {Number} zIndex (optional) The zIndex to apply
8105 * @param {Number} x (optional) Set the page X position
8106 * @param {Number} y (optional) Set the page Y position
8108 position : function(pos, zIndex, x, y){
8110 if(this.getStyle('position') == 'static'){
8111 this.setStyle('position', 'relative');
8114 this.setStyle("position", pos);
8117 this.setStyle("z-index", zIndex);
8119 if(x !== undefined && y !== undefined){
8121 }else if(x !== undefined){
8123 }else if(y !== undefined){
8129 * Clear positioning back to the default when the document was loaded
8130 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8131 * @return {Roo.Element} this
8133 clearPositioning : function(value){
8141 "position" : "static"
8147 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8148 * snapshot before performing an update and then restoring the element.
8151 getPositioning : function(){
8152 var l = this.getStyle("left");
8153 var t = this.getStyle("top");
8155 "position" : this.getStyle("position"),
8157 "right" : l ? "" : this.getStyle("right"),
8159 "bottom" : t ? "" : this.getStyle("bottom"),
8160 "z-index" : this.getStyle("z-index")
8165 * Gets the width of the border(s) for the specified side(s)
8166 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8167 * passing lr would get the border (l)eft width + the border (r)ight width.
8168 * @return {Number} The width of the sides passed added together
8170 getBorderWidth : function(side){
8171 return this.addStyles(side, El.borders);
8175 * Gets the width of the padding(s) for the specified side(s)
8176 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8177 * passing lr would get the padding (l)eft + the padding (r)ight.
8178 * @return {Number} The padding of the sides passed added together
8180 getPadding : function(side){
8181 return this.addStyles(side, El.paddings);
8185 * Set positioning with an object returned by getPositioning().
8186 * @param {Object} posCfg
8187 * @return {Roo.Element} this
8189 setPositioning : function(pc){
8190 this.applyStyles(pc);
8191 if(pc.right == "auto"){
8192 this.dom.style.right = "";
8194 if(pc.bottom == "auto"){
8195 this.dom.style.bottom = "";
8201 fixDisplay : function(){
8202 if(this.getStyle("display") == "none"){
8203 this.setStyle("visibility", "hidden");
8204 this.setStyle("display", this.originalDisplay); // first try reverting to default
8205 if(this.getStyle("display") == "none"){ // if that fails, default to block
8206 this.setStyle("display", "block");
8212 * Quick set left and top adding default units
8213 * @param {String} left The left CSS property value
8214 * @param {String} top The top CSS property value
8215 * @return {Roo.Element} this
8217 setLeftTop : function(left, top){
8218 this.dom.style.left = this.addUnits(left);
8219 this.dom.style.top = this.addUnits(top);
8224 * Move this element relative to its current position.
8225 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8226 * @param {Number} distance How far to move the element in pixels
8227 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8228 * @return {Roo.Element} this
8230 move : function(direction, distance, animate){
8231 var xy = this.getXY();
8232 direction = direction.toLowerCase();
8236 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8240 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8245 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8250 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8257 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8258 * @return {Roo.Element} this
8261 if(!this.isClipped){
8262 this.isClipped = true;
8263 this.originalClip = {
8264 "o": this.getStyle("overflow"),
8265 "x": this.getStyle("overflow-x"),
8266 "y": this.getStyle("overflow-y")
8268 this.setStyle("overflow", "hidden");
8269 this.setStyle("overflow-x", "hidden");
8270 this.setStyle("overflow-y", "hidden");
8276 * Return clipping (overflow) to original clipping before clip() was called
8277 * @return {Roo.Element} this
8279 unclip : function(){
8281 this.isClipped = false;
8282 var o = this.originalClip;
8283 if(o.o){this.setStyle("overflow", o.o);}
8284 if(o.x){this.setStyle("overflow-x", o.x);}
8285 if(o.y){this.setStyle("overflow-y", o.y);}
8292 * Gets the x,y coordinates specified by the anchor position on the element.
8293 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8294 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8295 * {width: (target width), height: (target height)} (defaults to the element's current size)
8296 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8297 * @return {Array} [x, y] An array containing the element's x and y coordinates
8299 getAnchorXY : function(anchor, local, s){
8300 //Passing a different size is useful for pre-calculating anchors,
8301 //especially for anchored animations that change the el size.
8303 var w, h, vp = false;
8306 if(d == document.body || d == document){
8308 w = D.getViewWidth(); h = D.getViewHeight();
8310 w = this.getWidth(); h = this.getHeight();
8313 w = s.width; h = s.height;
8315 var x = 0, y = 0, r = Math.round;
8316 switch((anchor || "tl").toLowerCase()){
8358 var sc = this.getScroll();
8359 return [x + sc.left, y + sc.top];
8361 //Add the element's offset xy
8362 var o = this.getXY();
8363 return [x+o[0], y+o[1]];
8367 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8368 * supported position values.
8369 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8370 * @param {String} position The position to align to.
8371 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8372 * @return {Array} [x, y]
8374 getAlignToXY : function(el, p, o){
8378 throw "Element.alignTo with an element that doesn't exist";
8380 var c = false; //constrain to viewport
8381 var p1 = "", p2 = "";
8388 }else if(p.indexOf("-") == -1){
8391 p = p.toLowerCase();
8392 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8394 throw "Element.alignTo with an invalid alignment " + p;
8396 p1 = m[1]; p2 = m[2]; c = !!m[3];
8398 //Subtract the aligned el's internal xy from the target's offset xy
8399 //plus custom offset to get the aligned el's new offset xy
8400 var a1 = this.getAnchorXY(p1, true);
8401 var a2 = el.getAnchorXY(p2, false);
8402 var x = a2[0] - a1[0] + o[0];
8403 var y = a2[1] - a1[1] + o[1];
8405 //constrain the aligned el to viewport if necessary
8406 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8407 // 5px of margin for ie
8408 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8410 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8411 //perpendicular to the vp border, allow the aligned el to slide on that border,
8412 //otherwise swap the aligned el to the opposite border of the target.
8413 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8414 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8415 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8416 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8419 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8420 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8422 if((x+w) > dw + scrollX){
8423 x = swapX ? r.left-w : dw+scrollX-w;
8426 x = swapX ? r.right : scrollX;
8428 if((y+h) > dh + scrollY){
8429 y = swapY ? r.top-h : dh+scrollY-h;
8432 y = swapY ? r.bottom : scrollY;
8439 getConstrainToXY : function(){
8440 var os = {top:0, left:0, bottom:0, right: 0};
8442 return function(el, local, offsets, proposedXY){
8444 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8446 var vw, vh, vx = 0, vy = 0;
8447 if(el.dom == document.body || el.dom == document){
8448 vw = Roo.lib.Dom.getViewWidth();
8449 vh = Roo.lib.Dom.getViewHeight();
8451 vw = el.dom.clientWidth;
8452 vh = el.dom.clientHeight;
8454 var vxy = el.getXY();
8460 var s = el.getScroll();
8462 vx += offsets.left + s.left;
8463 vy += offsets.top + s.top;
8465 vw -= offsets.right;
8466 vh -= offsets.bottom;
8471 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8472 var x = xy[0], y = xy[1];
8473 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8475 // only move it if it needs it
8478 // first validate right/bottom
8487 // then make sure top/left isn't negative
8496 return moved ? [x, y] : false;
8501 adjustForConstraints : function(xy, parent, offsets){
8502 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8506 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8507 * document it aligns it to the viewport.
8508 * The position parameter is optional, and can be specified in any one of the following formats:
8510 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8511 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8512 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8513 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8514 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8515 * element's anchor point, and the second value is used as the target's anchor point.</li>
8517 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8518 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8519 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8520 * that specified in order to enforce the viewport constraints.
8521 * Following are all of the supported anchor positions:
8524 ----- -----------------------------
8525 tl The top left corner (default)
8526 t The center of the top edge
8527 tr The top right corner
8528 l The center of the left edge
8529 c In the center of the element
8530 r The center of the right edge
8531 bl The bottom left corner
8532 b The center of the bottom edge
8533 br The bottom right corner
8537 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8538 el.alignTo("other-el");
8540 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8541 el.alignTo("other-el", "tr?");
8543 // align the bottom right corner of el with the center left edge of other-el
8544 el.alignTo("other-el", "br-l?");
8546 // align the center of el with the bottom left corner of other-el and
8547 // adjust the x position by -6 pixels (and the y position by 0)
8548 el.alignTo("other-el", "c-bl", [-6, 0]);
8550 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8551 * @param {String} position The position to align to.
8552 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8553 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8554 * @return {Roo.Element} this
8556 alignTo : function(element, position, offsets, animate){
8557 var xy = this.getAlignToXY(element, position, offsets);
8558 this.setXY(xy, this.preanim(arguments, 3));
8563 * Anchors an element to another element and realigns it when the window is resized.
8564 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8565 * @param {String} position The position to align to.
8566 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8567 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8568 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8569 * is a number, it is used as the buffer delay (defaults to 50ms).
8570 * @param {Function} callback The function to call after the animation finishes
8571 * @return {Roo.Element} this
8573 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8574 var action = function(){
8575 this.alignTo(el, alignment, offsets, animate);
8576 Roo.callback(callback, this);
8578 Roo.EventManager.onWindowResize(action, this);
8579 var tm = typeof monitorScroll;
8580 if(tm != 'undefined'){
8581 Roo.EventManager.on(window, 'scroll', action, this,
8582 {buffer: tm == 'number' ? monitorScroll : 50});
8584 action.call(this); // align immediately
8588 * Clears any opacity settings from this element. Required in some cases for IE.
8589 * @return {Roo.Element} this
8591 clearOpacity : function(){
8592 if (window.ActiveXObject) {
8593 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8594 this.dom.style.filter = "";
8597 this.dom.style.opacity = "";
8598 this.dom.style["-moz-opacity"] = "";
8599 this.dom.style["-khtml-opacity"] = "";
8605 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8606 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8607 * @return {Roo.Element} this
8609 hide : function(animate){
8610 this.setVisible(false, this.preanim(arguments, 0));
8615 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8616 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8617 * @return {Roo.Element} this
8619 show : function(animate){
8620 this.setVisible(true, this.preanim(arguments, 0));
8625 * @private Test if size has a unit, otherwise appends the default
8627 addUnits : function(size){
8628 return Roo.Element.addUnits(size, this.defaultUnit);
8632 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8633 * @return {Roo.Element} this
8635 beginMeasure : function(){
8637 if(el.offsetWidth || el.offsetHeight){
8638 return this; // offsets work already
8641 var p = this.dom, b = document.body; // start with this element
8642 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8643 var pe = Roo.get(p);
8644 if(pe.getStyle('display') == 'none'){
8645 changed.push({el: p, visibility: pe.getStyle("visibility")});
8646 p.style.visibility = "hidden";
8647 p.style.display = "block";
8651 this._measureChanged = changed;
8657 * Restores displays to before beginMeasure was called
8658 * @return {Roo.Element} this
8660 endMeasure : function(){
8661 var changed = this._measureChanged;
8663 for(var i = 0, len = changed.length; i < len; i++) {
8665 r.el.style.visibility = r.visibility;
8666 r.el.style.display = "none";
8668 this._measureChanged = null;
8674 * Update the innerHTML of this element, optionally searching for and processing scripts
8675 * @param {String} html The new HTML
8676 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8677 * @param {Function} callback For async script loading you can be noticed when the update completes
8678 * @return {Roo.Element} this
8680 update : function(html, loadScripts, callback){
8681 if(typeof html == "undefined"){
8684 if(loadScripts !== true){
8685 this.dom.innerHTML = html;
8686 if(typeof callback == "function"){
8694 html += '<span id="' + id + '"></span>';
8696 E.onAvailable(id, function(){
8697 var hd = document.getElementsByTagName("head")[0];
8698 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8699 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8700 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8703 while(match = re.exec(html)){
8704 var attrs = match[1];
8705 var srcMatch = attrs ? attrs.match(srcRe) : false;
8706 if(srcMatch && srcMatch[2]){
8707 var s = document.createElement("script");
8708 s.src = srcMatch[2];
8709 var typeMatch = attrs.match(typeRe);
8710 if(typeMatch && typeMatch[2]){
8711 s.type = typeMatch[2];
8714 }else if(match[2] && match[2].length > 0){
8715 if(window.execScript) {
8716 window.execScript(match[2]);
8724 window.eval(match[2]);
8728 var el = document.getElementById(id);
8729 if(el){el.parentNode.removeChild(el);}
8730 if(typeof callback == "function"){
8734 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8739 * Direct access to the UpdateManager update() method (takes the same parameters).
8740 * @param {String/Function} url The url for this request or a function to call to get the url
8741 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8742 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8743 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8744 * @return {Roo.Element} this
8747 var um = this.getUpdateManager();
8748 um.update.apply(um, arguments);
8753 * Gets this element's UpdateManager
8754 * @return {Roo.UpdateManager} The UpdateManager
8756 getUpdateManager : function(){
8757 if(!this.updateManager){
8758 this.updateManager = new Roo.UpdateManager(this);
8760 return this.updateManager;
8764 * Disables text selection for this element (normalized across browsers)
8765 * @return {Roo.Element} this
8767 unselectable : function(){
8768 this.dom.unselectable = "on";
8769 this.swallowEvent("selectstart", true);
8770 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8771 this.addClass("x-unselectable");
8776 * Calculates the x, y to center this element on the screen
8777 * @return {Array} The x, y values [x, y]
8779 getCenterXY : function(){
8780 return this.getAlignToXY(document, 'c-c');
8784 * Centers the Element in either the viewport, or another Element.
8785 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8787 center : function(centerIn){
8788 this.alignTo(centerIn || document, 'c-c');
8793 * Tests various css rules/browsers to determine if this element uses a border box
8796 isBorderBox : function(){
8797 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8801 * Return a box {x, y, width, height} that can be used to set another elements
8802 * size/location to match this element.
8803 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8804 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8805 * @return {Object} box An object in the format {x, y, width, height}
8807 getBox : function(contentBox, local){
8812 var left = parseInt(this.getStyle("left"), 10) || 0;
8813 var top = parseInt(this.getStyle("top"), 10) || 0;
8816 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8818 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8820 var l = this.getBorderWidth("l")+this.getPadding("l");
8821 var r = this.getBorderWidth("r")+this.getPadding("r");
8822 var t = this.getBorderWidth("t")+this.getPadding("t");
8823 var b = this.getBorderWidth("b")+this.getPadding("b");
8824 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8826 bx.right = bx.x + bx.width;
8827 bx.bottom = bx.y + bx.height;
8832 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8833 for more information about the sides.
8834 * @param {String} sides
8837 getFrameWidth : function(sides, onlyContentBox){
8838 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8842 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8843 * @param {Object} box The box to fill {x, y, width, height}
8844 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8845 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8846 * @return {Roo.Element} this
8848 setBox : function(box, adjust, animate){
8849 var w = box.width, h = box.height;
8850 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8851 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8852 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8854 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8859 * Forces the browser to repaint this element
8860 * @return {Roo.Element} this
8862 repaint : function(){
8864 this.addClass("x-repaint");
8865 setTimeout(function(){
8866 Roo.get(dom).removeClass("x-repaint");
8872 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8873 * then it returns the calculated width of the sides (see getPadding)
8874 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8875 * @return {Object/Number}
8877 getMargins : function(side){
8880 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8881 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8882 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8883 right: parseInt(this.getStyle("margin-right"), 10) || 0
8886 return this.addStyles(side, El.margins);
8891 addStyles : function(sides, styles){
8893 for(var i = 0, len = sides.length; i < len; i++){
8894 v = this.getStyle(styles[sides.charAt(i)]);
8896 w = parseInt(v, 10);
8904 * Creates a proxy element of this element
8905 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8906 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8907 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8908 * @return {Roo.Element} The new proxy element
8910 createProxy : function(config, renderTo, matchBox){
8912 renderTo = Roo.getDom(renderTo);
8914 renderTo = document.body;
8916 config = typeof config == "object" ?
8917 config : {tag : "div", cls: config};
8918 var proxy = Roo.DomHelper.append(renderTo, config, true);
8920 proxy.setBox(this.getBox());
8926 * Puts a mask over this element to disable user interaction. Requires core.css.
8927 * This method can only be applied to elements which accept child nodes.
8928 * @param {String} msg (optional) A message to display in the mask
8929 * @param {String} msgCls (optional) A css class to apply to the msg element
8930 * @return {Element} The mask element
8932 mask : function(msg, msgCls)
8934 if(this.getStyle("position") == "static"){
8935 this.setStyle("position", "relative");
8938 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8940 this.addClass("x-masked");
8941 this._mask.setDisplayed(true);
8946 while (dom && dom.style) {
8947 if (!isNaN(parseInt(dom.style.zIndex))) {
8948 z = Math.max(z, parseInt(dom.style.zIndex));
8950 dom = dom.parentNode;
8952 // if we are masking the body - then it hides everything..
8953 if (this.dom == document.body) {
8955 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8956 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8959 if(typeof msg == 'string'){
8961 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8963 var mm = this._maskMsg;
8964 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8965 mm.dom.firstChild.innerHTML = msg;
8966 mm.setDisplayed(true);
8968 mm.setStyle('z-index', z + 102);
8970 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8971 this._mask.setHeight(this.getHeight());
8973 this._mask.setStyle('z-index', z + 100);
8979 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8980 * it is cached for reuse.
8982 unmask : function(removeEl){
8984 if(removeEl === true){
8985 this._mask.remove();
8988 this._maskMsg.remove();
8989 delete this._maskMsg;
8992 this._mask.setDisplayed(false);
8994 this._maskMsg.setDisplayed(false);
8998 this.removeClass("x-masked");
9002 * Returns true if this element is masked
9005 isMasked : function(){
9006 return this._mask && this._mask.isVisible();
9010 * Creates an iframe shim for this element to keep selects and other windowed objects from
9012 * @return {Roo.Element} The new shim element
9014 createShim : function(){
9015 var el = document.createElement('iframe');
9016 el.frameBorder = 'no';
9017 el.className = 'roo-shim';
9018 if(Roo.isIE && Roo.isSecure){
9019 el.src = Roo.SSL_SECURE_URL;
9021 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9022 shim.autoBoxAdjust = false;
9027 * Removes this element from the DOM and deletes it from the cache
9029 remove : function(){
9030 if(this.dom.parentNode){
9031 this.dom.parentNode.removeChild(this.dom);
9033 delete El.cache[this.dom.id];
9037 * Sets up event handlers to add and remove a css class when the mouse is over this element
9038 * @param {String} className
9039 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9040 * mouseout events for children elements
9041 * @return {Roo.Element} this
9043 addClassOnOver : function(className, preventFlicker){
9044 this.on("mouseover", function(){
9045 Roo.fly(this, '_internal').addClass(className);
9047 var removeFn = function(e){
9048 if(preventFlicker !== true || !e.within(this, true)){
9049 Roo.fly(this, '_internal').removeClass(className);
9052 this.on("mouseout", removeFn, this.dom);
9057 * Sets up event handlers to add and remove a css class when this element has the focus
9058 * @param {String} className
9059 * @return {Roo.Element} this
9061 addClassOnFocus : function(className){
9062 this.on("focus", function(){
9063 Roo.fly(this, '_internal').addClass(className);
9065 this.on("blur", function(){
9066 Roo.fly(this, '_internal').removeClass(className);
9071 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9072 * @param {String} className
9073 * @return {Roo.Element} this
9075 addClassOnClick : function(className){
9077 this.on("mousedown", function(){
9078 Roo.fly(dom, '_internal').addClass(className);
9079 var d = Roo.get(document);
9080 var fn = function(){
9081 Roo.fly(dom, '_internal').removeClass(className);
9082 d.removeListener("mouseup", fn);
9084 d.on("mouseup", fn);
9090 * Stops the specified event from bubbling and optionally prevents the default action
9091 * @param {String} eventName
9092 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9093 * @return {Roo.Element} this
9095 swallowEvent : function(eventName, preventDefault){
9096 var fn = function(e){
9097 e.stopPropagation();
9102 if(eventName instanceof Array){
9103 for(var i = 0, len = eventName.length; i < len; i++){
9104 this.on(eventName[i], fn);
9108 this.on(eventName, fn);
9115 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9118 * Sizes this element to its parent element's dimensions performing
9119 * neccessary box adjustments.
9120 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9121 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9122 * @return {Roo.Element} this
9124 fitToParent : function(monitorResize, targetParent) {
9125 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9126 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9127 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9130 var p = Roo.get(targetParent || this.dom.parentNode);
9131 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9132 if (monitorResize === true) {
9133 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9134 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9140 * Gets the next sibling, skipping text nodes
9141 * @return {HTMLElement} The next sibling or null
9143 getNextSibling : function(){
9144 var n = this.dom.nextSibling;
9145 while(n && n.nodeType != 1){
9152 * Gets the previous sibling, skipping text nodes
9153 * @return {HTMLElement} The previous sibling or null
9155 getPrevSibling : function(){
9156 var n = this.dom.previousSibling;
9157 while(n && n.nodeType != 1){
9158 n = n.previousSibling;
9165 * Appends the passed element(s) to this element
9166 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9167 * @return {Roo.Element} this
9169 appendChild: function(el){
9176 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9177 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9178 * automatically generated with the specified attributes.
9179 * @param {HTMLElement} insertBefore (optional) a child element of this element
9180 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9181 * @return {Roo.Element} The new child element
9183 createChild: function(config, insertBefore, returnDom){
9184 config = config || {tag:'div'};
9186 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9188 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9192 * Appends this element to the passed element
9193 * @param {String/HTMLElement/Element} el The new parent element
9194 * @return {Roo.Element} this
9196 appendTo: function(el){
9197 el = Roo.getDom(el);
9198 el.appendChild(this.dom);
9203 * Inserts this element before the passed element in the DOM
9204 * @param {String/HTMLElement/Element} el The element to insert before
9205 * @return {Roo.Element} this
9207 insertBefore: function(el){
9208 el = Roo.getDom(el);
9209 el.parentNode.insertBefore(this.dom, el);
9214 * Inserts this element after the passed element in the DOM
9215 * @param {String/HTMLElement/Element} el The element to insert after
9216 * @return {Roo.Element} this
9218 insertAfter: function(el){
9219 el = Roo.getDom(el);
9220 el.parentNode.insertBefore(this.dom, el.nextSibling);
9225 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9226 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9227 * @return {Roo.Element} The new child
9229 insertFirst: function(el, returnDom){
9231 if(typeof el == 'object' && !el.nodeType){ // dh config
9232 return this.createChild(el, this.dom.firstChild, returnDom);
9234 el = Roo.getDom(el);
9235 this.dom.insertBefore(el, this.dom.firstChild);
9236 return !returnDom ? Roo.get(el) : el;
9241 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9242 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9243 * @param {String} where (optional) 'before' or 'after' defaults to before
9244 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9245 * @return {Roo.Element} the inserted Element
9247 insertSibling: function(el, where, returnDom){
9248 where = where ? where.toLowerCase() : 'before';
9250 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9252 if(typeof el == 'object' && !el.nodeType){ // dh config
9253 if(where == 'after' && !this.dom.nextSibling){
9254 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9256 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9260 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9261 where == 'before' ? this.dom : this.dom.nextSibling);
9270 * Creates and wraps this element with another element
9271 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9272 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9273 * @return {HTMLElement/Element} The newly created wrapper element
9275 wrap: function(config, returnDom){
9277 config = {tag: "div"};
9279 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9280 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9285 * Replaces the passed element with this element
9286 * @param {String/HTMLElement/Element} el The element to replace
9287 * @return {Roo.Element} this
9289 replace: function(el){
9291 this.insertBefore(el);
9297 * Inserts an html fragment into this element
9298 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9299 * @param {String} html The HTML fragment
9300 * @param {Boolean} returnEl True to return an Roo.Element
9301 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9303 insertHtml : function(where, html, returnEl){
9304 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9305 return returnEl ? Roo.get(el) : el;
9309 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9310 * @param {Object} o The object with the attributes
9311 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9312 * @return {Roo.Element} this
9314 set : function(o, useSet){
9316 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9318 if(attr == "style" || typeof o[attr] == "function") continue;
9320 el.className = o["cls"];
9322 if(useSet) el.setAttribute(attr, o[attr]);
9323 else el[attr] = o[attr];
9327 Roo.DomHelper.applyStyles(el, o.style);
9333 * Convenience method for constructing a KeyMap
9334 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9335 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9336 * @param {Function} fn The function to call
9337 * @param {Object} scope (optional) The scope of the function
9338 * @return {Roo.KeyMap} The KeyMap created
9340 addKeyListener : function(key, fn, scope){
9342 if(typeof key != "object" || key instanceof Array){
9358 return new Roo.KeyMap(this, config);
9362 * Creates a KeyMap for this element
9363 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9364 * @return {Roo.KeyMap} The KeyMap created
9366 addKeyMap : function(config){
9367 return new Roo.KeyMap(this, config);
9371 * Returns true if this element is scrollable.
9374 isScrollable : function(){
9376 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9380 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9381 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9382 * @param {Number} value The new scroll value
9383 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9384 * @return {Element} this
9387 scrollTo : function(side, value, animate){
9388 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9390 this.dom[prop] = value;
9392 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9393 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9399 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9400 * within this element's scrollable range.
9401 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9402 * @param {Number} distance How far to scroll the element in pixels
9403 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9404 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9405 * was scrolled as far as it could go.
9407 scroll : function(direction, distance, animate){
9408 if(!this.isScrollable()){
9412 var l = el.scrollLeft, t = el.scrollTop;
9413 var w = el.scrollWidth, h = el.scrollHeight;
9414 var cw = el.clientWidth, ch = el.clientHeight;
9415 direction = direction.toLowerCase();
9416 var scrolled = false;
9417 var a = this.preanim(arguments, 2);
9422 var v = Math.min(l + distance, w-cw);
9423 this.scrollTo("left", v, a);
9430 var v = Math.max(l - distance, 0);
9431 this.scrollTo("left", v, a);
9439 var v = Math.max(t - distance, 0);
9440 this.scrollTo("top", v, a);
9448 var v = Math.min(t + distance, h-ch);
9449 this.scrollTo("top", v, a);
9458 * Translates the passed page coordinates into left/top css values for this element
9459 * @param {Number/Array} x The page x or an array containing [x, y]
9460 * @param {Number} y The page y
9461 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9463 translatePoints : function(x, y){
9464 if(typeof x == 'object' || x instanceof Array){
9467 var p = this.getStyle('position');
9468 var o = this.getXY();
9470 var l = parseInt(this.getStyle('left'), 10);
9471 var t = parseInt(this.getStyle('top'), 10);
9474 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9477 t = (p == "relative") ? 0 : this.dom.offsetTop;
9480 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9484 * Returns the current scroll position of the element.
9485 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9487 getScroll : function(){
9488 var d = this.dom, doc = document;
9489 if(d == doc || d == doc.body){
9490 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9491 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9492 return {left: l, top: t};
9494 return {left: d.scrollLeft, top: d.scrollTop};
9499 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9500 * are convert to standard 6 digit hex color.
9501 * @param {String} attr The css attribute
9502 * @param {String} defaultValue The default value to use when a valid color isn't found
9503 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9506 getColor : function(attr, defaultValue, prefix){
9507 var v = this.getStyle(attr);
9508 if(!v || v == "transparent" || v == "inherit") {
9509 return defaultValue;
9511 var color = typeof prefix == "undefined" ? "#" : prefix;
9512 if(v.substr(0, 4) == "rgb("){
9513 var rvs = v.slice(4, v.length -1).split(",");
9514 for(var i = 0; i < 3; i++){
9515 var h = parseInt(rvs[i]).toString(16);
9522 if(v.substr(0, 1) == "#"){
9524 for(var i = 1; i < 4; i++){
9525 var c = v.charAt(i);
9528 }else if(v.length == 7){
9529 color += v.substr(1);
9533 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9537 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9538 * gradient background, rounded corners and a 4-way shadow.
9539 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9540 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9541 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9542 * @return {Roo.Element} this
9544 boxWrap : function(cls){
9545 cls = cls || 'x-box';
9546 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9547 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9552 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9553 * @param {String} namespace The namespace in which to look for the attribute
9554 * @param {String} name The attribute name
9555 * @return {String} The attribute value
9557 getAttributeNS : Roo.isIE ? function(ns, name){
9559 var type = typeof d[ns+":"+name];
9560 if(type != 'undefined' && type != 'unknown'){
9561 return d[ns+":"+name];
9564 } : function(ns, name){
9566 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9571 * Sets or Returns the value the dom attribute value
9572 * @param {String} name The attribute name
9573 * @param {String} value (optional) The value to set the attribute to
9574 * @return {String} The attribute value
9576 attr : function(name){
9577 if (arguments.length > 1) {
9578 this.dom.setAttribute(name, arguments[1]);
9579 return arguments[1];
9581 if (!this.dom.hasAttribute(name)) {
9584 return this.dom.getAttribute(name);
9591 var ep = El.prototype;
9594 * Appends an event handler (Shorthand for addListener)
9595 * @param {String} eventName The type of event to append
9596 * @param {Function} fn The method the event invokes
9597 * @param {Object} scope (optional) The scope (this object) of the fn
9598 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9601 ep.on = ep.addListener;
9603 ep.mon = ep.addListener;
9606 * Removes an event handler from this element (shorthand for removeListener)
9607 * @param {String} eventName the type of event to remove
9608 * @param {Function} fn the method the event invokes
9609 * @return {Roo.Element} this
9612 ep.un = ep.removeListener;
9615 * true to automatically adjust width and height settings for box-model issues (default to true)
9617 ep.autoBoxAdjust = true;
9620 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9623 El.addUnits = function(v, defaultUnit){
9624 if(v === "" || v == "auto"){
9627 if(v === undefined){
9630 if(typeof v == "number" || !El.unitPattern.test(v)){
9631 return v + (defaultUnit || 'px');
9636 // special markup used throughout Roo when box wrapping elements
9637 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9639 * Visibility mode constant - Use visibility to hide element
9645 * Visibility mode constant - Use display to hide element
9651 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9652 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9653 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9665 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9666 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9667 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9668 * @return {Element} The Element object
9671 El.get = function(el){
9673 if(!el){ return null; }
9674 if(typeof el == "string"){ // element id
9675 if(!(elm = document.getElementById(el))){
9678 if(ex = El.cache[el]){
9681 ex = El.cache[el] = new El(elm);
9684 }else if(el.tagName){ // dom element
9688 if(ex = El.cache[id]){
9691 ex = El.cache[id] = new El(el);
9694 }else if(el instanceof El){
9696 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9697 // catch case where it hasn't been appended
9698 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9701 }else if(el.isComposite){
9703 }else if(el instanceof Array){
9704 return El.select(el);
9705 }else if(el == document){
9706 // create a bogus element object representing the document object
9708 var f = function(){};
9709 f.prototype = El.prototype;
9711 docEl.dom = document;
9719 El.uncache = function(el){
9720 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9722 delete El.cache[a[i].id || a[i]];
9728 // Garbage collection - uncache elements/purge listeners on orphaned elements
9729 // so we don't hold a reference and cause the browser to retain them
9730 El.garbageCollect = function(){
9731 if(!Roo.enableGarbageCollector){
9732 clearInterval(El.collectorThread);
9735 for(var eid in El.cache){
9736 var el = El.cache[eid], d = el.dom;
9737 // -------------------------------------------------------
9738 // Determining what is garbage:
9739 // -------------------------------------------------------
9741 // dom node is null, definitely garbage
9742 // -------------------------------------------------------
9744 // no parentNode == direct orphan, definitely garbage
9745 // -------------------------------------------------------
9746 // !d.offsetParent && !document.getElementById(eid)
9747 // display none elements have no offsetParent so we will
9748 // also try to look it up by it's id. However, check
9749 // offsetParent first so we don't do unneeded lookups.
9750 // This enables collection of elements that are not orphans
9751 // directly, but somewhere up the line they have an orphan
9753 // -------------------------------------------------------
9754 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9755 delete El.cache[eid];
9756 if(d && Roo.enableListenerCollection){
9762 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9766 El.Flyweight = function(dom){
9769 El.Flyweight.prototype = El.prototype;
9771 El._flyweights = {};
9773 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9774 * the dom node can be overwritten by other code.
9775 * @param {String/HTMLElement} el The dom node or id
9776 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9777 * prevent conflicts (e.g. internally Roo uses "_internal")
9779 * @return {Element} The shared Element object
9781 El.fly = function(el, named){
9782 named = named || '_global';
9783 el = Roo.getDom(el);
9787 if(!El._flyweights[named]){
9788 El._flyweights[named] = new El.Flyweight();
9790 El._flyweights[named].dom = el;
9791 return El._flyweights[named];
9795 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9796 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9797 * Shorthand of {@link Roo.Element#get}
9798 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9799 * @return {Element} The Element object
9805 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9806 * the dom node can be overwritten by other code.
9807 * Shorthand of {@link Roo.Element#fly}
9808 * @param {String/HTMLElement} el The dom node or id
9809 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9810 * prevent conflicts (e.g. internally Roo uses "_internal")
9812 * @return {Element} The shared Element object
9818 // speedy lookup for elements never to box adjust
9819 var noBoxAdjust = Roo.isStrict ? {
9822 input:1, select:1, textarea:1
9824 if(Roo.isIE || Roo.isGecko){
9825 noBoxAdjust['button'] = 1;
9829 Roo.EventManager.on(window, 'unload', function(){
9831 delete El._flyweights;
9839 Roo.Element.selectorFunction = Roo.DomQuery.select;
9842 Roo.Element.select = function(selector, unique, root){
9844 if(typeof selector == "string"){
9845 els = Roo.Element.selectorFunction(selector, root);
9846 }else if(selector.length !== undefined){
9849 throw "Invalid selector";
9851 if(unique === true){
9852 return new Roo.CompositeElement(els);
9854 return new Roo.CompositeElementLite(els);
9858 * Selects elements based on the passed CSS selector to enable working on them as 1.
9859 * @param {String/Array} selector The CSS selector or an array of elements
9860 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9861 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9862 * @return {CompositeElementLite/CompositeElement}
9866 Roo.select = Roo.Element.select;
9883 * Ext JS Library 1.1.1
9884 * Copyright(c) 2006-2007, Ext JS, LLC.
9886 * Originally Released Under LGPL - original licence link has changed is not relivant.
9889 * <script type="text/javascript">
9894 //Notifies Element that fx methods are available
9895 Roo.enableFx = true;
9899 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9900 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9901 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9902 * Element effects to work.</p><br/>
9904 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9905 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9906 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9907 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9908 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9909 * expected results and should be done with care.</p><br/>
9911 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9912 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9915 ----- -----------------------------
9916 tl The top left corner
9917 t The center of the top edge
9918 tr The top right corner
9919 l The center of the left edge
9920 r The center of the right edge
9921 bl The bottom left corner
9922 b The center of the bottom edge
9923 br The bottom right corner
9925 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9926 * below are common options that can be passed to any Fx method.</b>
9927 * @cfg {Function} callback A function called when the effect is finished
9928 * @cfg {Object} scope The scope of the effect function
9929 * @cfg {String} easing A valid Easing value for the effect
9930 * @cfg {String} afterCls A css class to apply after the effect
9931 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9932 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9933 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9934 * effects that end with the element being visually hidden, ignored otherwise)
9935 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9936 * a function which returns such a specification that will be applied to the Element after the effect finishes
9937 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9938 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9939 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9943 * Slides the element into view. An anchor point can be optionally passed to set the point of
9944 * origin for the slide effect. This function automatically handles wrapping the element with
9945 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9948 // default: slide the element in from the top
9951 // custom: slide the element in from the right with a 2-second duration
9952 el.slideIn('r', { duration: 2 });
9954 // common config options shown with default values
9960 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9961 * @param {Object} options (optional) Object literal with any of the Fx config options
9962 * @return {Roo.Element} The Element
9964 slideIn : function(anchor, o){
9965 var el = this.getFxEl();
9968 el.queueFx(o, function(){
9970 anchor = anchor || "t";
9972 // fix display to visibility
9975 // restore values after effect
9976 var r = this.getFxRestore();
9977 var b = this.getBox();
9978 // fixed size for slide
9982 var wrap = this.fxWrap(r.pos, o, "hidden");
9984 var st = this.dom.style;
9985 st.visibility = "visible";
9986 st.position = "absolute";
9988 // clear out temp styles after slide and unwrap
9989 var after = function(){
9990 el.fxUnwrap(wrap, r.pos, o);
9992 st.height = r.height;
9995 // time to calc the positions
9996 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9998 switch(anchor.toLowerCase()){
10000 wrap.setSize(b.width, 0);
10001 st.left = st.bottom = "0";
10005 wrap.setSize(0, b.height);
10006 st.right = st.top = "0";
10010 wrap.setSize(0, b.height);
10011 wrap.setX(b.right);
10012 st.left = st.top = "0";
10013 a = {width: bw, points: pt};
10016 wrap.setSize(b.width, 0);
10017 wrap.setY(b.bottom);
10018 st.left = st.top = "0";
10019 a = {height: bh, points: pt};
10022 wrap.setSize(0, 0);
10023 st.right = st.bottom = "0";
10024 a = {width: bw, height: bh};
10027 wrap.setSize(0, 0);
10028 wrap.setY(b.y+b.height);
10029 st.right = st.top = "0";
10030 a = {width: bw, height: bh, points: pt};
10033 wrap.setSize(0, 0);
10034 wrap.setXY([b.right, b.bottom]);
10035 st.left = st.top = "0";
10036 a = {width: bw, height: bh, points: pt};
10039 wrap.setSize(0, 0);
10040 wrap.setX(b.x+b.width);
10041 st.left = st.bottom = "0";
10042 a = {width: bw, height: bh, points: pt};
10045 this.dom.style.visibility = "visible";
10048 arguments.callee.anim = wrap.fxanim(a,
10058 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10059 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10060 * 'hidden') but block elements will still take up space in the document. The element must be removed
10061 * from the DOM using the 'remove' config option if desired. This function automatically handles
10062 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10065 // default: slide the element out to the top
10068 // custom: slide the element out to the right with a 2-second duration
10069 el.slideOut('r', { duration: 2 });
10071 // common config options shown with default values
10079 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10080 * @param {Object} options (optional) Object literal with any of the Fx config options
10081 * @return {Roo.Element} The Element
10083 slideOut : function(anchor, o){
10084 var el = this.getFxEl();
10087 el.queueFx(o, function(){
10089 anchor = anchor || "t";
10091 // restore values after effect
10092 var r = this.getFxRestore();
10094 var b = this.getBox();
10095 // fixed size for slide
10099 var wrap = this.fxWrap(r.pos, o, "visible");
10101 var st = this.dom.style;
10102 st.visibility = "visible";
10103 st.position = "absolute";
10107 var after = function(){
10109 el.setDisplayed(false);
10114 el.fxUnwrap(wrap, r.pos, o);
10116 st.width = r.width;
10117 st.height = r.height;
10122 var a, zero = {to: 0};
10123 switch(anchor.toLowerCase()){
10125 st.left = st.bottom = "0";
10126 a = {height: zero};
10129 st.right = st.top = "0";
10133 st.left = st.top = "0";
10134 a = {width: zero, points: {to:[b.right, b.y]}};
10137 st.left = st.top = "0";
10138 a = {height: zero, points: {to:[b.x, b.bottom]}};
10141 st.right = st.bottom = "0";
10142 a = {width: zero, height: zero};
10145 st.right = st.top = "0";
10146 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10149 st.left = st.top = "0";
10150 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10153 st.left = st.bottom = "0";
10154 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10158 arguments.callee.anim = wrap.fxanim(a,
10168 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10169 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10170 * The element must be removed from the DOM using the 'remove' config option if desired.
10176 // common config options shown with default values
10184 * @param {Object} options (optional) Object literal with any of the Fx config options
10185 * @return {Roo.Element} The Element
10187 puff : function(o){
10188 var el = this.getFxEl();
10191 el.queueFx(o, function(){
10192 this.clearOpacity();
10195 // restore values after effect
10196 var r = this.getFxRestore();
10197 var st = this.dom.style;
10199 var after = function(){
10201 el.setDisplayed(false);
10208 el.setPositioning(r.pos);
10209 st.width = r.width;
10210 st.height = r.height;
10215 var width = this.getWidth();
10216 var height = this.getHeight();
10218 arguments.callee.anim = this.fxanim({
10219 width : {to: this.adjustWidth(width * 2)},
10220 height : {to: this.adjustHeight(height * 2)},
10221 points : {by: [-(width * .5), -(height * .5)]},
10223 fontSize: {to:200, unit: "%"}
10234 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10235 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10236 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10242 // all config options shown with default values
10250 * @param {Object} options (optional) Object literal with any of the Fx config options
10251 * @return {Roo.Element} The Element
10253 switchOff : function(o){
10254 var el = this.getFxEl();
10257 el.queueFx(o, function(){
10258 this.clearOpacity();
10261 // restore values after effect
10262 var r = this.getFxRestore();
10263 var st = this.dom.style;
10265 var after = function(){
10267 el.setDisplayed(false);
10273 el.setPositioning(r.pos);
10274 st.width = r.width;
10275 st.height = r.height;
10280 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10281 this.clearOpacity();
10285 points:{by:[0, this.getHeight() * .5]}
10286 }, o, 'motion', 0.3, 'easeIn', after);
10287 }).defer(100, this);
10294 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10295 * changed using the "attr" config option) and then fading back to the original color. If no original
10296 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10299 // default: highlight background to yellow
10302 // custom: highlight foreground text to blue for 2 seconds
10303 el.highlight("0000ff", { attr: 'color', duration: 2 });
10305 // common config options shown with default values
10306 el.highlight("ffff9c", {
10307 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10308 endColor: (current color) or "ffffff",
10313 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10314 * @param {Object} options (optional) Object literal with any of the Fx config options
10315 * @return {Roo.Element} The Element
10317 highlight : function(color, o){
10318 var el = this.getFxEl();
10321 el.queueFx(o, function(){
10322 color = color || "ffff9c";
10323 attr = o.attr || "backgroundColor";
10325 this.clearOpacity();
10328 var origColor = this.getColor(attr);
10329 var restoreColor = this.dom.style[attr];
10330 endColor = (o.endColor || origColor) || "ffffff";
10332 var after = function(){
10333 el.dom.style[attr] = restoreColor;
10338 a[attr] = {from: color, to: endColor};
10339 arguments.callee.anim = this.fxanim(a,
10349 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10352 // default: a single light blue ripple
10355 // custom: 3 red ripples lasting 3 seconds total
10356 el.frame("ff0000", 3, { duration: 3 });
10358 // common config options shown with default values
10359 el.frame("C3DAF9", 1, {
10360 duration: 1 //duration of entire animation (not each individual ripple)
10361 // Note: Easing is not configurable and will be ignored if included
10364 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10365 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10366 * @param {Object} options (optional) Object literal with any of the Fx config options
10367 * @return {Roo.Element} The Element
10369 frame : function(color, count, o){
10370 var el = this.getFxEl();
10373 el.queueFx(o, function(){
10374 color = color || "#C3DAF9";
10375 if(color.length == 6){
10376 color = "#" + color;
10378 count = count || 1;
10379 duration = o.duration || 1;
10382 var b = this.getBox();
10383 var animFn = function(){
10384 var proxy = this.createProxy({
10387 visbility:"hidden",
10388 position:"absolute",
10389 "z-index":"35000", // yee haw
10390 border:"0px solid " + color
10393 var scale = Roo.isBorderBox ? 2 : 1;
10395 top:{from:b.y, to:b.y - 20},
10396 left:{from:b.x, to:b.x - 20},
10397 borderWidth:{from:0, to:10},
10398 opacity:{from:1, to:0},
10399 height:{from:b.height, to:(b.height + (20*scale))},
10400 width:{from:b.width, to:(b.width + (20*scale))}
10401 }, duration, function(){
10405 animFn.defer((duration/2)*1000, this);
10416 * Creates a pause before any subsequent queued effects begin. If there are
10417 * no effects queued after the pause it will have no effect.
10422 * @param {Number} seconds The length of time to pause (in seconds)
10423 * @return {Roo.Element} The Element
10425 pause : function(seconds){
10426 var el = this.getFxEl();
10429 el.queueFx(o, function(){
10430 setTimeout(function(){
10432 }, seconds * 1000);
10438 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10439 * using the "endOpacity" config option.
10442 // default: fade in from opacity 0 to 100%
10445 // custom: fade in from opacity 0 to 75% over 2 seconds
10446 el.fadeIn({ endOpacity: .75, duration: 2});
10448 // common config options shown with default values
10450 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10455 * @param {Object} options (optional) Object literal with any of the Fx config options
10456 * @return {Roo.Element} The Element
10458 fadeIn : function(o){
10459 var el = this.getFxEl();
10461 el.queueFx(o, function(){
10462 this.setOpacity(0);
10464 this.dom.style.visibility = 'visible';
10465 var to = o.endOpacity || 1;
10466 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10467 o, null, .5, "easeOut", function(){
10469 this.clearOpacity();
10478 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10479 * using the "endOpacity" config option.
10482 // default: fade out from the element's current opacity to 0
10485 // custom: fade out from the element's current opacity to 25% over 2 seconds
10486 el.fadeOut({ endOpacity: .25, duration: 2});
10488 // common config options shown with default values
10490 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10497 * @param {Object} options (optional) Object literal with any of the Fx config options
10498 * @return {Roo.Element} The Element
10500 fadeOut : function(o){
10501 var el = this.getFxEl();
10503 el.queueFx(o, function(){
10504 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10505 o, null, .5, "easeOut", function(){
10506 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10507 this.dom.style.display = "none";
10509 this.dom.style.visibility = "hidden";
10511 this.clearOpacity();
10519 * Animates the transition of an element's dimensions from a starting height/width
10520 * to an ending height/width.
10523 // change height and width to 100x100 pixels
10524 el.scale(100, 100);
10526 // common config options shown with default values. The height and width will default to
10527 // the element's existing values if passed as null.
10530 [element's height], {
10535 * @param {Number} width The new width (pass undefined to keep the original width)
10536 * @param {Number} height The new height (pass undefined to keep the original height)
10537 * @param {Object} options (optional) Object literal with any of the Fx config options
10538 * @return {Roo.Element} The Element
10540 scale : function(w, h, o){
10541 this.shift(Roo.apply({}, o, {
10549 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10550 * Any of these properties not specified in the config object will not be changed. This effect
10551 * requires that at least one new dimension, position or opacity setting must be passed in on
10552 * the config object in order for the function to have any effect.
10555 // slide the element horizontally to x position 200 while changing the height and opacity
10556 el.shift({ x: 200, height: 50, opacity: .8 });
10558 // common config options shown with default values.
10560 width: [element's width],
10561 height: [element's height],
10562 x: [element's x position],
10563 y: [element's y position],
10564 opacity: [element's opacity],
10569 * @param {Object} options Object literal with any of the Fx config options
10570 * @return {Roo.Element} The Element
10572 shift : function(o){
10573 var el = this.getFxEl();
10575 el.queueFx(o, function(){
10576 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10577 if(w !== undefined){
10578 a.width = {to: this.adjustWidth(w)};
10580 if(h !== undefined){
10581 a.height = {to: this.adjustHeight(h)};
10583 if(x !== undefined || y !== undefined){
10585 x !== undefined ? x : this.getX(),
10586 y !== undefined ? y : this.getY()
10589 if(op !== undefined){
10590 a.opacity = {to: op};
10592 if(o.xy !== undefined){
10593 a.points = {to: o.xy};
10595 arguments.callee.anim = this.fxanim(a,
10596 o, 'motion', .35, "easeOut", function(){
10604 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10605 * ending point of the effect.
10608 // default: slide the element downward while fading out
10611 // custom: slide the element out to the right with a 2-second duration
10612 el.ghost('r', { duration: 2 });
10614 // common config options shown with default values
10622 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10623 * @param {Object} options (optional) Object literal with any of the Fx config options
10624 * @return {Roo.Element} The Element
10626 ghost : function(anchor, o){
10627 var el = this.getFxEl();
10630 el.queueFx(o, function(){
10631 anchor = anchor || "b";
10633 // restore values after effect
10634 var r = this.getFxRestore();
10635 var w = this.getWidth(),
10636 h = this.getHeight();
10638 var st = this.dom.style;
10640 var after = function(){
10642 el.setDisplayed(false);
10648 el.setPositioning(r.pos);
10649 st.width = r.width;
10650 st.height = r.height;
10655 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10656 switch(anchor.toLowerCase()){
10683 arguments.callee.anim = this.fxanim(a,
10693 * Ensures that all effects queued after syncFx is called on the element are
10694 * run concurrently. This is the opposite of {@link #sequenceFx}.
10695 * @return {Roo.Element} The Element
10697 syncFx : function(){
10698 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10707 * Ensures that all effects queued after sequenceFx is called on the element are
10708 * run in sequence. This is the opposite of {@link #syncFx}.
10709 * @return {Roo.Element} The Element
10711 sequenceFx : function(){
10712 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10714 concurrent : false,
10721 nextFx : function(){
10722 var ef = this.fxQueue[0];
10729 * Returns true if the element has any effects actively running or queued, else returns false.
10730 * @return {Boolean} True if element has active effects, else false
10732 hasActiveFx : function(){
10733 return this.fxQueue && this.fxQueue[0];
10737 * Stops any running effects and clears the element's internal effects queue if it contains
10738 * any additional effects that haven't started yet.
10739 * @return {Roo.Element} The Element
10741 stopFx : function(){
10742 if(this.hasActiveFx()){
10743 var cur = this.fxQueue[0];
10744 if(cur && cur.anim && cur.anim.isAnimated()){
10745 this.fxQueue = [cur]; // clear out others
10746 cur.anim.stop(true);
10753 beforeFx : function(o){
10754 if(this.hasActiveFx() && !o.concurrent){
10765 * Returns true if the element is currently blocking so that no other effect can be queued
10766 * until this effect is finished, else returns false if blocking is not set. This is commonly
10767 * used to ensure that an effect initiated by a user action runs to completion prior to the
10768 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10769 * @return {Boolean} True if blocking, else false
10771 hasFxBlock : function(){
10772 var q = this.fxQueue;
10773 return q && q[0] && q[0].block;
10777 queueFx : function(o, fn){
10781 if(!this.hasFxBlock()){
10782 Roo.applyIf(o, this.fxDefaults);
10784 var run = this.beforeFx(o);
10785 fn.block = o.block;
10786 this.fxQueue.push(fn);
10798 fxWrap : function(pos, o, vis){
10800 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10803 wrapXY = this.getXY();
10805 var div = document.createElement("div");
10806 div.style.visibility = vis;
10807 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10808 wrap.setPositioning(pos);
10809 if(wrap.getStyle("position") == "static"){
10810 wrap.position("relative");
10812 this.clearPositioning('auto');
10814 wrap.dom.appendChild(this.dom);
10816 wrap.setXY(wrapXY);
10823 fxUnwrap : function(wrap, pos, o){
10824 this.clearPositioning();
10825 this.setPositioning(pos);
10827 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10833 getFxRestore : function(){
10834 var st = this.dom.style;
10835 return {pos: this.getPositioning(), width: st.width, height : st.height};
10839 afterFx : function(o){
10841 this.applyStyles(o.afterStyle);
10844 this.addClass(o.afterCls);
10846 if(o.remove === true){
10849 Roo.callback(o.callback, o.scope, [this]);
10851 this.fxQueue.shift();
10857 getFxEl : function(){ // support for composite element fx
10858 return Roo.get(this.dom);
10862 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10863 animType = animType || 'run';
10865 var anim = Roo.lib.Anim[animType](
10867 (opt.duration || defaultDur) || .35,
10868 (opt.easing || defaultEase) || 'easeOut',
10870 Roo.callback(cb, this);
10879 // backwords compat
10880 Roo.Fx.resize = Roo.Fx.scale;
10882 //When included, Roo.Fx is automatically applied to Element so that all basic
10883 //effects are available directly via the Element API
10884 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10886 * Ext JS Library 1.1.1
10887 * Copyright(c) 2006-2007, Ext JS, LLC.
10889 * Originally Released Under LGPL - original licence link has changed is not relivant.
10892 * <script type="text/javascript">
10897 * @class Roo.CompositeElement
10898 * Standard composite class. Creates a Roo.Element for every element in the collection.
10900 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10901 * actions will be performed on all the elements in this collection.</b>
10903 * All methods return <i>this</i> and can be chained.
10905 var els = Roo.select("#some-el div.some-class", true);
10906 // or select directly from an existing element
10907 var el = Roo.get('some-el');
10908 el.select('div.some-class', true);
10910 els.setWidth(100); // all elements become 100 width
10911 els.hide(true); // all elements fade out and hide
10913 els.setWidth(100).hide(true);
10916 Roo.CompositeElement = function(els){
10917 this.elements = [];
10918 this.addElements(els);
10920 Roo.CompositeElement.prototype = {
10922 addElements : function(els){
10923 if(!els) return this;
10924 if(typeof els == "string"){
10925 els = Roo.Element.selectorFunction(els);
10927 var yels = this.elements;
10928 var index = yels.length-1;
10929 for(var i = 0, len = els.length; i < len; i++) {
10930 yels[++index] = Roo.get(els[i]);
10936 * Clears this composite and adds the elements returned by the passed selector.
10937 * @param {String/Array} els A string CSS selector, an array of elements or an element
10938 * @return {CompositeElement} this
10940 fill : function(els){
10941 this.elements = [];
10947 * Filters this composite to only elements that match the passed selector.
10948 * @param {String} selector A string CSS selector
10949 * @return {CompositeElement} this
10951 filter : function(selector){
10953 this.each(function(el){
10954 if(el.is(selector)){
10955 els[els.length] = el.dom;
10962 invoke : function(fn, args){
10963 var els = this.elements;
10964 for(var i = 0, len = els.length; i < len; i++) {
10965 Roo.Element.prototype[fn].apply(els[i], args);
10970 * Adds elements to this composite.
10971 * @param {String/Array} els A string CSS selector, an array of elements or an element
10972 * @return {CompositeElement} this
10974 add : function(els){
10975 if(typeof els == "string"){
10976 this.addElements(Roo.Element.selectorFunction(els));
10977 }else if(els.length !== undefined){
10978 this.addElements(els);
10980 this.addElements([els]);
10985 * Calls the passed function passing (el, this, index) for each element in this composite.
10986 * @param {Function} fn The function to call
10987 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10988 * @return {CompositeElement} this
10990 each : function(fn, scope){
10991 var els = this.elements;
10992 for(var i = 0, len = els.length; i < len; i++){
10993 if(fn.call(scope || els[i], els[i], this, i) === false) {
11001 * Returns the Element object at the specified index
11002 * @param {Number} index
11003 * @return {Roo.Element}
11005 item : function(index){
11006 return this.elements[index] || null;
11010 * Returns the first Element
11011 * @return {Roo.Element}
11013 first : function(){
11014 return this.item(0);
11018 * Returns the last Element
11019 * @return {Roo.Element}
11022 return this.item(this.elements.length-1);
11026 * Returns the number of elements in this composite
11029 getCount : function(){
11030 return this.elements.length;
11034 * Returns true if this composite contains the passed element
11037 contains : function(el){
11038 return this.indexOf(el) !== -1;
11042 * Returns true if this composite contains the passed element
11045 indexOf : function(el){
11046 return this.elements.indexOf(Roo.get(el));
11051 * Removes the specified element(s).
11052 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11053 * or an array of any of those.
11054 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11055 * @return {CompositeElement} this
11057 removeElement : function(el, removeDom){
11058 if(el instanceof Array){
11059 for(var i = 0, len = el.length; i < len; i++){
11060 this.removeElement(el[i]);
11064 var index = typeof el == 'number' ? el : this.indexOf(el);
11067 var d = this.elements[index];
11071 d.parentNode.removeChild(d);
11074 this.elements.splice(index, 1);
11080 * Replaces the specified element with the passed element.
11081 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11083 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11084 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11085 * @return {CompositeElement} this
11087 replaceElement : function(el, replacement, domReplace){
11088 var index = typeof el == 'number' ? el : this.indexOf(el);
11091 this.elements[index].replaceWith(replacement);
11093 this.elements.splice(index, 1, Roo.get(replacement))
11100 * Removes all elements.
11102 clear : function(){
11103 this.elements = [];
11107 Roo.CompositeElement.createCall = function(proto, fnName){
11108 if(!proto[fnName]){
11109 proto[fnName] = function(){
11110 return this.invoke(fnName, arguments);
11114 for(var fnName in Roo.Element.prototype){
11115 if(typeof Roo.Element.prototype[fnName] == "function"){
11116 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11122 * Ext JS Library 1.1.1
11123 * Copyright(c) 2006-2007, Ext JS, LLC.
11125 * Originally Released Under LGPL - original licence link has changed is not relivant.
11128 * <script type="text/javascript">
11132 * @class Roo.CompositeElementLite
11133 * @extends Roo.CompositeElement
11134 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11136 var els = Roo.select("#some-el div.some-class");
11137 // or select directly from an existing element
11138 var el = Roo.get('some-el');
11139 el.select('div.some-class');
11141 els.setWidth(100); // all elements become 100 width
11142 els.hide(true); // all elements fade out and hide
11144 els.setWidth(100).hide(true);
11145 </code></pre><br><br>
11146 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11147 * actions will be performed on all the elements in this collection.</b>
11149 Roo.CompositeElementLite = function(els){
11150 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11151 this.el = new Roo.Element.Flyweight();
11153 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11154 addElements : function(els){
11156 if(els instanceof Array){
11157 this.elements = this.elements.concat(els);
11159 var yels = this.elements;
11160 var index = yels.length-1;
11161 for(var i = 0, len = els.length; i < len; i++) {
11162 yels[++index] = els[i];
11168 invoke : function(fn, args){
11169 var els = this.elements;
11171 for(var i = 0, len = els.length; i < len; i++) {
11173 Roo.Element.prototype[fn].apply(el, args);
11178 * Returns a flyweight Element of the dom element object at the specified index
11179 * @param {Number} index
11180 * @return {Roo.Element}
11182 item : function(index){
11183 if(!this.elements[index]){
11186 this.el.dom = this.elements[index];
11190 // fixes scope with flyweight
11191 addListener : function(eventName, handler, scope, opt){
11192 var els = this.elements;
11193 for(var i = 0, len = els.length; i < len; i++) {
11194 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11200 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11201 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11202 * a reference to the dom node, use el.dom.</b>
11203 * @param {Function} fn The function to call
11204 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11205 * @return {CompositeElement} this
11207 each : function(fn, scope){
11208 var els = this.elements;
11210 for(var i = 0, len = els.length; i < len; i++){
11212 if(fn.call(scope || el, el, this, i) === false){
11219 indexOf : function(el){
11220 return this.elements.indexOf(Roo.getDom(el));
11223 replaceElement : function(el, replacement, domReplace){
11224 var index = typeof el == 'number' ? el : this.indexOf(el);
11226 replacement = Roo.getDom(replacement);
11228 var d = this.elements[index];
11229 d.parentNode.insertBefore(replacement, d);
11230 d.parentNode.removeChild(d);
11232 this.elements.splice(index, 1, replacement);
11237 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11241 * Ext JS Library 1.1.1
11242 * Copyright(c) 2006-2007, Ext JS, LLC.
11244 * Originally Released Under LGPL - original licence link has changed is not relivant.
11247 * <script type="text/javascript">
11253 * @class Roo.data.Connection
11254 * @extends Roo.util.Observable
11255 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11256 * either to a configured URL, or to a URL specified at request time.<br><br>
11258 * Requests made by this class are asynchronous, and will return immediately. No data from
11259 * the server will be available to the statement immediately following the {@link #request} call.
11260 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11262 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11263 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11264 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11265 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11266 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11267 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11268 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11269 * standard DOM methods.
11271 * @param {Object} config a configuration object.
11273 Roo.data.Connection = function(config){
11274 Roo.apply(this, config);
11277 * @event beforerequest
11278 * Fires before a network request is made to retrieve a data object.
11279 * @param {Connection} conn This Connection object.
11280 * @param {Object} options The options config object passed to the {@link #request} method.
11282 "beforerequest" : true,
11284 * @event requestcomplete
11285 * Fires if the request was successfully completed.
11286 * @param {Connection} conn This Connection object.
11287 * @param {Object} response The XHR object containing the response data.
11288 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11289 * @param {Object} options The options config object passed to the {@link #request} method.
11291 "requestcomplete" : true,
11293 * @event requestexception
11294 * Fires if an error HTTP status was returned from the server.
11295 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11296 * @param {Connection} conn This Connection object.
11297 * @param {Object} response The XHR object containing the response data.
11298 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11299 * @param {Object} options The options config object passed to the {@link #request} method.
11301 "requestexception" : true
11303 Roo.data.Connection.superclass.constructor.call(this);
11306 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11308 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11311 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11312 * extra parameters to each request made by this object. (defaults to undefined)
11315 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11316 * to each request made by this object. (defaults to undefined)
11319 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11322 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11326 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11332 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11335 disableCaching: true,
11338 * Sends an HTTP request to a remote server.
11339 * @param {Object} options An object which may contain the following properties:<ul>
11340 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11341 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11342 * request, a url encoded string or a function to call to get either.</li>
11343 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11344 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11345 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11346 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11347 * <li>options {Object} The parameter to the request call.</li>
11348 * <li>success {Boolean} True if the request succeeded.</li>
11349 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11351 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11352 * The callback is passed the following parameters:<ul>
11353 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11354 * <li>options {Object} The parameter to the request call.</li>
11356 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11357 * The callback is passed the following parameters:<ul>
11358 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11359 * <li>options {Object} The parameter to the request call.</li>
11361 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11362 * for the callback function. Defaults to the browser window.</li>
11363 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11364 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11365 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11366 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11367 * params for the post data. Any params will be appended to the URL.</li>
11368 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11370 * @return {Number} transactionId
11372 request : function(o){
11373 if(this.fireEvent("beforerequest", this, o) !== false){
11376 if(typeof p == "function"){
11377 p = p.call(o.scope||window, o);
11379 if(typeof p == "object"){
11380 p = Roo.urlEncode(o.params);
11382 if(this.extraParams){
11383 var extras = Roo.urlEncode(this.extraParams);
11384 p = p ? (p + '&' + extras) : extras;
11387 var url = o.url || this.url;
11388 if(typeof url == 'function'){
11389 url = url.call(o.scope||window, o);
11393 var form = Roo.getDom(o.form);
11394 url = url || form.action;
11396 var enctype = form.getAttribute("enctype");
11397 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11398 return this.doFormUpload(o, p, url);
11400 var f = Roo.lib.Ajax.serializeForm(form);
11401 p = p ? (p + '&' + f) : f;
11404 var hs = o.headers;
11405 if(this.defaultHeaders){
11406 hs = Roo.apply(hs || {}, this.defaultHeaders);
11413 success: this.handleResponse,
11414 failure: this.handleFailure,
11416 argument: {options: o},
11417 timeout : o.timeout || this.timeout
11420 var method = o.method||this.method||(p ? "POST" : "GET");
11422 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11423 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11426 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11430 }else if(this.autoAbort !== false){
11434 if((method == 'GET' && p) || o.xmlData){
11435 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11438 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11439 return this.transId;
11441 Roo.callback(o.callback, o.scope, [o, null, null]);
11447 * Determine whether this object has a request outstanding.
11448 * @param {Number} transactionId (Optional) defaults to the last transaction
11449 * @return {Boolean} True if there is an outstanding request.
11451 isLoading : function(transId){
11453 return Roo.lib.Ajax.isCallInProgress(transId);
11455 return this.transId ? true : false;
11460 * Aborts any outstanding request.
11461 * @param {Number} transactionId (Optional) defaults to the last transaction
11463 abort : function(transId){
11464 if(transId || this.isLoading()){
11465 Roo.lib.Ajax.abort(transId || this.transId);
11470 handleResponse : function(response){
11471 this.transId = false;
11472 var options = response.argument.options;
11473 response.argument = options ? options.argument : null;
11474 this.fireEvent("requestcomplete", this, response, options);
11475 Roo.callback(options.success, options.scope, [response, options]);
11476 Roo.callback(options.callback, options.scope, [options, true, response]);
11480 handleFailure : function(response, e){
11481 this.transId = false;
11482 var options = response.argument.options;
11483 response.argument = options ? options.argument : null;
11484 this.fireEvent("requestexception", this, response, options, e);
11485 Roo.callback(options.failure, options.scope, [response, options]);
11486 Roo.callback(options.callback, options.scope, [options, false, response]);
11490 doFormUpload : function(o, ps, url){
11492 var frame = document.createElement('iframe');
11495 frame.className = 'x-hidden';
11497 frame.src = Roo.SSL_SECURE_URL;
11499 document.body.appendChild(frame);
11502 document.frames[id].name = id;
11505 var form = Roo.getDom(o.form);
11507 form.method = 'POST';
11508 form.enctype = form.encoding = 'multipart/form-data';
11514 if(ps){ // add dynamic params
11516 ps = Roo.urlDecode(ps, false);
11518 if(ps.hasOwnProperty(k)){
11519 hd = document.createElement('input');
11520 hd.type = 'hidden';
11523 form.appendChild(hd);
11530 var r = { // bogus response object
11535 r.argument = o ? o.argument : null;
11540 doc = frame.contentWindow.document;
11542 doc = (frame.contentDocument || window.frames[id].document);
11544 if(doc && doc.body){
11545 r.responseText = doc.body.innerHTML;
11547 if(doc && doc.XMLDocument){
11548 r.responseXML = doc.XMLDocument;
11550 r.responseXML = doc;
11557 Roo.EventManager.removeListener(frame, 'load', cb, this);
11559 this.fireEvent("requestcomplete", this, r, o);
11560 Roo.callback(o.success, o.scope, [r, o]);
11561 Roo.callback(o.callback, o.scope, [o, true, r]);
11563 setTimeout(function(){document.body.removeChild(frame);}, 100);
11566 Roo.EventManager.on(frame, 'load', cb, this);
11569 if(hiddens){ // remove dynamic params
11570 for(var i = 0, len = hiddens.length; i < len; i++){
11571 form.removeChild(hiddens[i]);
11578 * Ext JS Library 1.1.1
11579 * Copyright(c) 2006-2007, Ext JS, LLC.
11581 * Originally Released Under LGPL - original licence link has changed is not relivant.
11584 * <script type="text/javascript">
11588 * Global Ajax request class.
11591 * @extends Roo.data.Connection
11594 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11595 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11596 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11597 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11598 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11599 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11600 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11602 Roo.Ajax = new Roo.data.Connection({
11611 * Serialize the passed form into a url encoded string
11613 * @param {String/HTMLElement} form
11616 serializeForm : function(form){
11617 return Roo.lib.Ajax.serializeForm(form);
11621 * Ext JS Library 1.1.1
11622 * Copyright(c) 2006-2007, Ext JS, LLC.
11624 * Originally Released Under LGPL - original licence link has changed is not relivant.
11627 * <script type="text/javascript">
11632 * @class Roo.UpdateManager
11633 * @extends Roo.util.Observable
11634 * Provides AJAX-style update for Element object.<br><br>
11637 * // Get it from a Roo.Element object
11638 * var el = Roo.get("foo");
11639 * var mgr = el.getUpdateManager();
11640 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11642 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11644 * // or directly (returns the same UpdateManager instance)
11645 * var mgr = new Roo.UpdateManager("myElementId");
11646 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11647 * mgr.on("update", myFcnNeedsToKnow);
11649 // short handed call directly from the element object
11650 Roo.get("foo").load({
11654 text: "Loading Foo..."
11658 * Create new UpdateManager directly.
11659 * @param {String/HTMLElement/Roo.Element} el The element to update
11660 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11662 Roo.UpdateManager = function(el, forceNew){
11664 if(!forceNew && el.updateManager){
11665 return el.updateManager;
11668 * The Element object
11669 * @type Roo.Element
11673 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11676 this.defaultUrl = null;
11680 * @event beforeupdate
11681 * Fired before an update is made, return false from your handler and the update is cancelled.
11682 * @param {Roo.Element} el
11683 * @param {String/Object/Function} url
11684 * @param {String/Object} params
11686 "beforeupdate": true,
11689 * Fired after successful update is made.
11690 * @param {Roo.Element} el
11691 * @param {Object} oResponseObject The response Object
11696 * Fired on update failure.
11697 * @param {Roo.Element} el
11698 * @param {Object} oResponseObject The response Object
11702 var d = Roo.UpdateManager.defaults;
11704 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11707 this.sslBlankUrl = d.sslBlankUrl;
11709 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11712 this.disableCaching = d.disableCaching;
11714 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11717 this.indicatorText = d.indicatorText;
11719 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11722 this.showLoadIndicator = d.showLoadIndicator;
11724 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11727 this.timeout = d.timeout;
11730 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11733 this.loadScripts = d.loadScripts;
11736 * Transaction object of current executing transaction
11738 this.transaction = null;
11743 this.autoRefreshProcId = null;
11745 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11748 this.refreshDelegate = this.refresh.createDelegate(this);
11750 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11753 this.updateDelegate = this.update.createDelegate(this);
11755 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11758 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11762 this.successDelegate = this.processSuccess.createDelegate(this);
11766 this.failureDelegate = this.processFailure.createDelegate(this);
11768 if(!this.renderer){
11770 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11772 this.renderer = new Roo.UpdateManager.BasicRenderer();
11775 Roo.UpdateManager.superclass.constructor.call(this);
11778 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11780 * Get the Element this UpdateManager is bound to
11781 * @return {Roo.Element} The element
11783 getEl : function(){
11787 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11788 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11791 url: "your-url.php",<br/>
11792 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11793 callback: yourFunction,<br/>
11794 scope: yourObject, //(optional scope) <br/>
11795 discardUrl: false, <br/>
11796 nocache: false,<br/>
11797 text: "Loading...",<br/>
11799 scripts: false<br/>
11802 * The only required property is url. The optional properties nocache, text and scripts
11803 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11804 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11805 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11806 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11808 update : function(url, params, callback, discardUrl){
11809 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11810 var method = this.method,
11812 if(typeof url == "object"){ // must be config object
11815 params = params || cfg.params;
11816 callback = callback || cfg.callback;
11817 discardUrl = discardUrl || cfg.discardUrl;
11818 if(callback && cfg.scope){
11819 callback = callback.createDelegate(cfg.scope);
11821 if(typeof cfg.method != "undefined"){method = cfg.method;};
11822 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11823 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11824 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11825 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11827 this.showLoading();
11829 this.defaultUrl = url;
11831 if(typeof url == "function"){
11832 url = url.call(this);
11835 method = method || (params ? "POST" : "GET");
11836 if(method == "GET"){
11837 url = this.prepareUrl(url);
11840 var o = Roo.apply(cfg ||{}, {
11843 success: this.successDelegate,
11844 failure: this.failureDelegate,
11845 callback: undefined,
11846 timeout: (this.timeout*1000),
11847 argument: {"url": url, "form": null, "callback": callback, "params": params}
11849 Roo.log("updated manager called with timeout of " + o.timeout);
11850 this.transaction = Roo.Ajax.request(o);
11855 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11856 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11857 * @param {String/HTMLElement} form The form Id or form element
11858 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11859 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11860 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11862 formUpdate : function(form, url, reset, callback){
11863 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11864 if(typeof url == "function"){
11865 url = url.call(this);
11867 form = Roo.getDom(form);
11868 this.transaction = Roo.Ajax.request({
11871 success: this.successDelegate,
11872 failure: this.failureDelegate,
11873 timeout: (this.timeout*1000),
11874 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11876 this.showLoading.defer(1, this);
11881 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11882 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11884 refresh : function(callback){
11885 if(this.defaultUrl == null){
11888 this.update(this.defaultUrl, null, callback, true);
11892 * Set this element to auto refresh.
11893 * @param {Number} interval How often to update (in seconds).
11894 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11895 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11896 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11897 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11899 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11901 this.update(url || this.defaultUrl, params, callback, true);
11903 if(this.autoRefreshProcId){
11904 clearInterval(this.autoRefreshProcId);
11906 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11910 * Stop auto refresh on this element.
11912 stopAutoRefresh : function(){
11913 if(this.autoRefreshProcId){
11914 clearInterval(this.autoRefreshProcId);
11915 delete this.autoRefreshProcId;
11919 isAutoRefreshing : function(){
11920 return this.autoRefreshProcId ? true : false;
11923 * Called to update the element to "Loading" state. Override to perform custom action.
11925 showLoading : function(){
11926 if(this.showLoadIndicator){
11927 this.el.update(this.indicatorText);
11932 * Adds unique parameter to query string if disableCaching = true
11935 prepareUrl : function(url){
11936 if(this.disableCaching){
11937 var append = "_dc=" + (new Date().getTime());
11938 if(url.indexOf("?") !== -1){
11939 url += "&" + append;
11941 url += "?" + append;
11950 processSuccess : function(response){
11951 this.transaction = null;
11952 if(response.argument.form && response.argument.reset){
11953 try{ // put in try/catch since some older FF releases had problems with this
11954 response.argument.form.reset();
11957 if(this.loadScripts){
11958 this.renderer.render(this.el, response, this,
11959 this.updateComplete.createDelegate(this, [response]));
11961 this.renderer.render(this.el, response, this);
11962 this.updateComplete(response);
11966 updateComplete : function(response){
11967 this.fireEvent("update", this.el, response);
11968 if(typeof response.argument.callback == "function"){
11969 response.argument.callback(this.el, true, response);
11976 processFailure : function(response){
11977 this.transaction = null;
11978 this.fireEvent("failure", this.el, response);
11979 if(typeof response.argument.callback == "function"){
11980 response.argument.callback(this.el, false, response);
11985 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11986 * @param {Object} renderer The object implementing the render() method
11988 setRenderer : function(renderer){
11989 this.renderer = renderer;
11992 getRenderer : function(){
11993 return this.renderer;
11997 * Set the defaultUrl used for updates
11998 * @param {String/Function} defaultUrl The url or a function to call to get the url
12000 setDefaultUrl : function(defaultUrl){
12001 this.defaultUrl = defaultUrl;
12005 * Aborts the executing transaction
12007 abort : function(){
12008 if(this.transaction){
12009 Roo.Ajax.abort(this.transaction);
12014 * Returns true if an update is in progress
12015 * @return {Boolean}
12017 isUpdating : function(){
12018 if(this.transaction){
12019 return Roo.Ajax.isLoading(this.transaction);
12026 * @class Roo.UpdateManager.defaults
12027 * @static (not really - but it helps the doc tool)
12028 * The defaults collection enables customizing the default properties of UpdateManager
12030 Roo.UpdateManager.defaults = {
12032 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12038 * True to process scripts by default (Defaults to false).
12041 loadScripts : false,
12044 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12047 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12049 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12052 disableCaching : false,
12054 * Whether to show indicatorText when loading (Defaults to true).
12057 showLoadIndicator : true,
12059 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12062 indicatorText : '<div class="loading-indicator">Loading...</div>'
12066 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12068 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12069 * @param {String/HTMLElement/Roo.Element} el The element to update
12070 * @param {String} url The url
12071 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12072 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12075 * @member Roo.UpdateManager
12077 Roo.UpdateManager.updateElement = function(el, url, params, options){
12078 var um = Roo.get(el, true).getUpdateManager();
12079 Roo.apply(um, options);
12080 um.update(url, params, options ? options.callback : null);
12082 // alias for backwards compat
12083 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12085 * @class Roo.UpdateManager.BasicRenderer
12086 * Default Content renderer. Updates the elements innerHTML with the responseText.
12088 Roo.UpdateManager.BasicRenderer = function(){};
12090 Roo.UpdateManager.BasicRenderer.prototype = {
12092 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12093 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12094 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12095 * @param {Roo.Element} el The element being rendered
12096 * @param {Object} response The YUI Connect response object
12097 * @param {UpdateManager} updateManager The calling update manager
12098 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12100 render : function(el, response, updateManager, callback){
12101 el.update(response.responseText, updateManager.loadScripts, callback);
12107 * (c)) Alan Knowles
12113 * @class Roo.DomTemplate
12114 * @extends Roo.Template
12115 * An effort at a dom based template engine..
12117 * Similar to XTemplate, except it uses dom parsing to create the template..
12119 * Supported features:
12124 {a_variable} - output encoded.
12125 {a_variable.format:("Y-m-d")} - call a method on the variable
12126 {a_variable:raw} - unencoded output
12127 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12128 {a_variable:this.method_on_template(...)} - call a method on the template object.
12133 <div roo-for="a_variable or condition.."></div>
12134 <div roo-if="a_variable or condition"></div>
12135 <div roo-exec="some javascript"></div>
12136 <div roo-name="named_template"></div>
12141 Roo.DomTemplate = function()
12143 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12150 Roo.extend(Roo.DomTemplate, Roo.Template, {
12152 * id counter for sub templates.
12156 * flag to indicate if dom parser is inside a pre,
12157 * it will strip whitespace if not.
12162 * The various sub templates
12170 * basic tag replacing syntax
12173 * // you can fake an object call by doing this
12177 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12178 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12180 iterChild : function (node, method) {
12182 var oldPre = this.inPre;
12183 if (node.tagName == 'PRE') {
12186 for( var i = 0; i < node.childNodes.length; i++) {
12187 method.call(this, node.childNodes[i]);
12189 this.inPre = oldPre;
12195 * compile the template
12197 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12200 compile: function()
12204 // covert the html into DOM...
12208 doc = document.implementation.createHTMLDocument("");
12209 doc.documentElement.innerHTML = this.html ;
12210 div = doc.documentElement;
12212 // old IE... - nasty -- it causes all sorts of issues.. with
12213 // images getting pulled from server..
12214 div = document.createElement('div');
12215 div.innerHTML = this.html;
12217 //doc.documentElement.innerHTML = htmlBody
12223 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12225 var tpls = this.tpls;
12227 // create a top level template from the snippet..
12229 //Roo.log(div.innerHTML);
12236 body : div.innerHTML,
12249 Roo.each(tpls, function(tp){
12250 this.compileTpl(tp);
12251 this.tpls[tp.id] = tp;
12254 this.master = tpls[0];
12260 compileNode : function(node, istop) {
12265 // skip anything not a tag..
12266 if (node.nodeType != 1) {
12267 if (node.nodeType == 3 && !this.inPre) {
12268 // reduce white space..
12269 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12292 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12293 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12294 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12295 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12301 // just itterate children..
12302 this.iterChild(node,this.compileNode);
12305 tpl.uid = this.id++;
12306 tpl.value = node.getAttribute('roo-' + tpl.attr);
12307 node.removeAttribute('roo-'+ tpl.attr);
12308 if (tpl.attr != 'name') {
12309 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12310 node.parentNode.replaceChild(placeholder, node);
12313 var placeholder = document.createElement('span');
12314 placeholder.className = 'roo-tpl-' + tpl.value;
12315 node.parentNode.replaceChild(placeholder, node);
12318 // parent now sees '{domtplXXXX}
12319 this.iterChild(node,this.compileNode);
12321 // we should now have node body...
12322 var div = document.createElement('div');
12323 div.appendChild(node);
12325 // this has the unfortunate side effect of converting tagged attributes
12326 // eg. href="{...}" into %7C...%7D
12327 // this has been fixed by searching for those combo's although it's a bit hacky..
12330 tpl.body = div.innerHTML;
12337 switch (tpl.value) {
12338 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12339 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12340 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12345 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12349 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12353 tpl.id = tpl.value; // replace non characters???
12359 this.tpls.push(tpl);
12369 * Compile a segment of the template into a 'sub-template'
12375 compileTpl : function(tpl)
12377 var fm = Roo.util.Format;
12378 var useF = this.disableFormats !== true;
12380 var sep = Roo.isGecko ? "+\n" : ",\n";
12382 var undef = function(str) {
12383 Roo.debug && Roo.log("Property not found :" + str);
12387 //Roo.log(tpl.body);
12391 var fn = function(m, lbrace, name, format, args)
12394 //Roo.log(arguments);
12395 args = args ? args.replace(/\\'/g,"'") : args;
12396 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12397 if (typeof(format) == 'undefined') {
12398 format = 'htmlEncode';
12400 if (format == 'raw' ) {
12404 if(name.substr(0, 6) == 'domtpl'){
12405 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12408 // build an array of options to determine if value is undefined..
12410 // basically get 'xxxx.yyyy' then do
12411 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12412 // (function () { Roo.log("Property not found"); return ''; })() :
12417 Roo.each(name.split('.'), function(st) {
12418 lookfor += (lookfor.length ? '.': '') + st;
12419 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12422 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12425 if(format && useF){
12427 args = args ? ',' + args : "";
12429 if(format.substr(0, 5) != "this."){
12430 format = "fm." + format + '(';
12432 format = 'this.call("'+ format.substr(5) + '", ';
12436 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12439 if (args && args.length) {
12440 // called with xxyx.yuu:(test,test)
12442 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12444 // raw.. - :raw modifier..
12445 return "'"+ sep + udef_st + name + ")"+sep+"'";
12449 // branched to use + in gecko and [].join() in others
12451 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12452 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12455 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12456 body.push(tpl.body.replace(/(\r\n|\n)/g,
12457 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12458 body.push("'].join('');};};");
12459 body = body.join('');
12462 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12464 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12471 * same as applyTemplate, except it's done to one of the subTemplates
12472 * when using named templates, you can do:
12474 * var str = pl.applySubTemplate('your-name', values);
12477 * @param {Number} id of the template
12478 * @param {Object} values to apply to template
12479 * @param {Object} parent (normaly the instance of this object)
12481 applySubTemplate : function(id, values, parent)
12485 var t = this.tpls[id];
12489 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12490 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12494 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12501 if(t.execCall && t.execCall.call(this, values, parent)){
12505 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12511 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12512 parent = t.target ? values : parent;
12513 if(t.forCall && vs instanceof Array){
12515 for(var i = 0, len = vs.length; i < len; i++){
12517 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12519 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12521 //Roo.log(t.compiled);
12525 return buf.join('');
12528 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12533 return t.compiled.call(this, vs, parent);
12535 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12537 //Roo.log(t.compiled);
12545 applyTemplate : function(values){
12546 return this.master.compiled.call(this, values, {});
12547 //var s = this.subs;
12550 apply : function(){
12551 return this.applyTemplate.apply(this, arguments);
12556 Roo.DomTemplate.from = function(el){
12557 el = Roo.getDom(el);
12558 return new Roo.Domtemplate(el.value || el.innerHTML);
12561 * Ext JS Library 1.1.1
12562 * Copyright(c) 2006-2007, Ext JS, LLC.
12564 * Originally Released Under LGPL - original licence link has changed is not relivant.
12567 * <script type="text/javascript">
12571 * @class Roo.util.DelayedTask
12572 * Provides a convenient method of performing setTimeout where a new
12573 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12574 * You can use this class to buffer
12575 * the keypress events for a certain number of milliseconds, and perform only if they stop
12576 * for that amount of time.
12577 * @constructor The parameters to this constructor serve as defaults and are not required.
12578 * @param {Function} fn (optional) The default function to timeout
12579 * @param {Object} scope (optional) The default scope of that timeout
12580 * @param {Array} args (optional) The default Array of arguments
12582 Roo.util.DelayedTask = function(fn, scope, args){
12583 var id = null, d, t;
12585 var call = function(){
12586 var now = new Date().getTime();
12590 fn.apply(scope, args || []);
12594 * Cancels any pending timeout and queues a new one
12595 * @param {Number} delay The milliseconds to delay
12596 * @param {Function} newFn (optional) Overrides function passed to constructor
12597 * @param {Object} newScope (optional) Overrides scope passed to constructor
12598 * @param {Array} newArgs (optional) Overrides args passed to constructor
12600 this.delay = function(delay, newFn, newScope, newArgs){
12601 if(id && delay != d){
12605 t = new Date().getTime();
12607 scope = newScope || scope;
12608 args = newArgs || args;
12610 id = setInterval(call, d);
12615 * Cancel the last queued timeout
12617 this.cancel = function(){
12625 * Ext JS Library 1.1.1
12626 * Copyright(c) 2006-2007, Ext JS, LLC.
12628 * Originally Released Under LGPL - original licence link has changed is not relivant.
12631 * <script type="text/javascript">
12635 Roo.util.TaskRunner = function(interval){
12636 interval = interval || 10;
12637 var tasks = [], removeQueue = [];
12639 var running = false;
12641 var stopThread = function(){
12647 var startThread = function(){
12650 id = setInterval(runTasks, interval);
12654 var removeTask = function(task){
12655 removeQueue.push(task);
12661 var runTasks = function(){
12662 if(removeQueue.length > 0){
12663 for(var i = 0, len = removeQueue.length; i < len; i++){
12664 tasks.remove(removeQueue[i]);
12667 if(tasks.length < 1){
12672 var now = new Date().getTime();
12673 for(var i = 0, len = tasks.length; i < len; ++i){
12675 var itime = now - t.taskRunTime;
12676 if(t.interval <= itime){
12677 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12678 t.taskRunTime = now;
12679 if(rt === false || t.taskRunCount === t.repeat){
12684 if(t.duration && t.duration <= (now - t.taskStartTime)){
12691 * Queues a new task.
12692 * @param {Object} task
12694 this.start = function(task){
12696 task.taskStartTime = new Date().getTime();
12697 task.taskRunTime = 0;
12698 task.taskRunCount = 0;
12703 this.stop = function(task){
12708 this.stopAll = function(){
12710 for(var i = 0, len = tasks.length; i < len; i++){
12711 if(tasks[i].onStop){
12720 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12722 * Ext JS Library 1.1.1
12723 * Copyright(c) 2006-2007, Ext JS, LLC.
12725 * Originally Released Under LGPL - original licence link has changed is not relivant.
12728 * <script type="text/javascript">
12733 * @class Roo.util.MixedCollection
12734 * @extends Roo.util.Observable
12735 * A Collection class that maintains both numeric indexes and keys and exposes events.
12737 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12738 * collection (defaults to false)
12739 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12740 * and return the key value for that item. This is used when available to look up the key on items that
12741 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12742 * equivalent to providing an implementation for the {@link #getKey} method.
12744 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12752 * Fires when the collection is cleared.
12757 * Fires when an item is added to the collection.
12758 * @param {Number} index The index at which the item was added.
12759 * @param {Object} o The item added.
12760 * @param {String} key The key associated with the added item.
12765 * Fires when an item is replaced in the collection.
12766 * @param {String} key he key associated with the new added.
12767 * @param {Object} old The item being replaced.
12768 * @param {Object} new The new item.
12773 * Fires when an item is removed from the collection.
12774 * @param {Object} o The item being removed.
12775 * @param {String} key (optional) The key associated with the removed item.
12780 this.allowFunctions = allowFunctions === true;
12782 this.getKey = keyFn;
12784 Roo.util.MixedCollection.superclass.constructor.call(this);
12787 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12788 allowFunctions : false,
12791 * Adds an item to the collection.
12792 * @param {String} key The key to associate with the item
12793 * @param {Object} o The item to add.
12794 * @return {Object} The item added.
12796 add : function(key, o){
12797 if(arguments.length == 1){
12799 key = this.getKey(o);
12801 if(typeof key == "undefined" || key === null){
12803 this.items.push(o);
12804 this.keys.push(null);
12806 var old = this.map[key];
12808 return this.replace(key, o);
12811 this.items.push(o);
12813 this.keys.push(key);
12815 this.fireEvent("add", this.length-1, o, key);
12820 * MixedCollection has a generic way to fetch keys if you implement getKey.
12823 var mc = new Roo.util.MixedCollection();
12824 mc.add(someEl.dom.id, someEl);
12825 mc.add(otherEl.dom.id, otherEl);
12829 var mc = new Roo.util.MixedCollection();
12830 mc.getKey = function(el){
12836 // or via the constructor
12837 var mc = new Roo.util.MixedCollection(false, function(el){
12843 * @param o {Object} The item for which to find the key.
12844 * @return {Object} The key for the passed item.
12846 getKey : function(o){
12851 * Replaces an item in the collection.
12852 * @param {String} key The key associated with the item to replace, or the item to replace.
12853 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12854 * @return {Object} The new item.
12856 replace : function(key, o){
12857 if(arguments.length == 1){
12859 key = this.getKey(o);
12861 var old = this.item(key);
12862 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12863 return this.add(key, o);
12865 var index = this.indexOfKey(key);
12866 this.items[index] = o;
12868 this.fireEvent("replace", key, old, o);
12873 * Adds all elements of an Array or an Object to the collection.
12874 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12875 * an Array of values, each of which are added to the collection.
12877 addAll : function(objs){
12878 if(arguments.length > 1 || objs instanceof Array){
12879 var args = arguments.length > 1 ? arguments : objs;
12880 for(var i = 0, len = args.length; i < len; i++){
12884 for(var key in objs){
12885 if(this.allowFunctions || typeof objs[key] != "function"){
12886 this.add(key, objs[key]);
12893 * Executes the specified function once for every item in the collection, passing each
12894 * item as the first and only parameter. returning false from the function will stop the iteration.
12895 * @param {Function} fn The function to execute for each item.
12896 * @param {Object} scope (optional) The scope in which to execute the function.
12898 each : function(fn, scope){
12899 var items = [].concat(this.items); // each safe for removal
12900 for(var i = 0, len = items.length; i < len; i++){
12901 if(fn.call(scope || items[i], items[i], i, len) === false){
12908 * Executes the specified function once for every key in the collection, passing each
12909 * key, and its associated item as the first two parameters.
12910 * @param {Function} fn The function to execute for each item.
12911 * @param {Object} scope (optional) The scope in which to execute the function.
12913 eachKey : function(fn, scope){
12914 for(var i = 0, len = this.keys.length; i < len; i++){
12915 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12920 * Returns the first item in the collection which elicits a true return value from the
12921 * passed selection function.
12922 * @param {Function} fn The selection function to execute for each item.
12923 * @param {Object} scope (optional) The scope in which to execute the function.
12924 * @return {Object} The first item in the collection which returned true from the selection function.
12926 find : function(fn, scope){
12927 for(var i = 0, len = this.items.length; i < len; i++){
12928 if(fn.call(scope || window, this.items[i], this.keys[i])){
12929 return this.items[i];
12936 * Inserts an item at the specified index in the collection.
12937 * @param {Number} index The index to insert the item at.
12938 * @param {String} key The key to associate with the new item, or the item itself.
12939 * @param {Object} o (optional) If the second parameter was a key, the new item.
12940 * @return {Object} The item inserted.
12942 insert : function(index, key, o){
12943 if(arguments.length == 2){
12945 key = this.getKey(o);
12947 if(index >= this.length){
12948 return this.add(key, o);
12951 this.items.splice(index, 0, o);
12952 if(typeof key != "undefined" && key != null){
12955 this.keys.splice(index, 0, key);
12956 this.fireEvent("add", index, o, key);
12961 * Removed an item from the collection.
12962 * @param {Object} o The item to remove.
12963 * @return {Object} The item removed.
12965 remove : function(o){
12966 return this.removeAt(this.indexOf(o));
12970 * Remove an item from a specified index in the collection.
12971 * @param {Number} index The index within the collection of the item to remove.
12973 removeAt : function(index){
12974 if(index < this.length && index >= 0){
12976 var o = this.items[index];
12977 this.items.splice(index, 1);
12978 var key = this.keys[index];
12979 if(typeof key != "undefined"){
12980 delete this.map[key];
12982 this.keys.splice(index, 1);
12983 this.fireEvent("remove", o, key);
12988 * Removed an item associated with the passed key fom the collection.
12989 * @param {String} key The key of the item to remove.
12991 removeKey : function(key){
12992 return this.removeAt(this.indexOfKey(key));
12996 * Returns the number of items in the collection.
12997 * @return {Number} the number of items in the collection.
12999 getCount : function(){
13000 return this.length;
13004 * Returns index within the collection of the passed Object.
13005 * @param {Object} o The item to find the index of.
13006 * @return {Number} index of the item.
13008 indexOf : function(o){
13009 if(!this.items.indexOf){
13010 for(var i = 0, len = this.items.length; i < len; i++){
13011 if(this.items[i] == o) return i;
13015 return this.items.indexOf(o);
13020 * Returns index within the collection of the passed key.
13021 * @param {String} key The key to find the index of.
13022 * @return {Number} index of the key.
13024 indexOfKey : function(key){
13025 if(!this.keys.indexOf){
13026 for(var i = 0, len = this.keys.length; i < len; i++){
13027 if(this.keys[i] == key) return i;
13031 return this.keys.indexOf(key);
13036 * Returns the item associated with the passed key OR index. Key has priority over index.
13037 * @param {String/Number} key The key or index of the item.
13038 * @return {Object} The item associated with the passed key.
13040 item : function(key){
13041 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13042 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13046 * Returns the item at the specified index.
13047 * @param {Number} index The index of the item.
13050 itemAt : function(index){
13051 return this.items[index];
13055 * Returns the item associated with the passed key.
13056 * @param {String/Number} key The key of the item.
13057 * @return {Object} The item associated with the passed key.
13059 key : function(key){
13060 return this.map[key];
13064 * Returns true if the collection contains the passed Object as an item.
13065 * @param {Object} o The Object to look for in the collection.
13066 * @return {Boolean} True if the collection contains the Object as an item.
13068 contains : function(o){
13069 return this.indexOf(o) != -1;
13073 * Returns true if the collection contains the passed Object as a key.
13074 * @param {String} key The key to look for in the collection.
13075 * @return {Boolean} True if the collection contains the Object as a key.
13077 containsKey : function(key){
13078 return typeof this.map[key] != "undefined";
13082 * Removes all items from the collection.
13084 clear : function(){
13089 this.fireEvent("clear");
13093 * Returns the first item in the collection.
13094 * @return {Object} the first item in the collection..
13096 first : function(){
13097 return this.items[0];
13101 * Returns the last item in the collection.
13102 * @return {Object} the last item in the collection..
13105 return this.items[this.length-1];
13108 _sort : function(property, dir, fn){
13109 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13110 fn = fn || function(a, b){
13113 var c = [], k = this.keys, items = this.items;
13114 for(var i = 0, len = items.length; i < len; i++){
13115 c[c.length] = {key: k[i], value: items[i], index: i};
13117 c.sort(function(a, b){
13118 var v = fn(a[property], b[property]) * dsc;
13120 v = (a.index < b.index ? -1 : 1);
13124 for(var i = 0, len = c.length; i < len; i++){
13125 items[i] = c[i].value;
13128 this.fireEvent("sort", this);
13132 * Sorts this collection with the passed comparison function
13133 * @param {String} direction (optional) "ASC" or "DESC"
13134 * @param {Function} fn (optional) comparison function
13136 sort : function(dir, fn){
13137 this._sort("value", dir, fn);
13141 * Sorts this collection by keys
13142 * @param {String} direction (optional) "ASC" or "DESC"
13143 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13145 keySort : function(dir, fn){
13146 this._sort("key", dir, fn || function(a, b){
13147 return String(a).toUpperCase()-String(b).toUpperCase();
13152 * Returns a range of items in this collection
13153 * @param {Number} startIndex (optional) defaults to 0
13154 * @param {Number} endIndex (optional) default to the last item
13155 * @return {Array} An array of items
13157 getRange : function(start, end){
13158 var items = this.items;
13159 if(items.length < 1){
13162 start = start || 0;
13163 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13166 for(var i = start; i <= end; i++) {
13167 r[r.length] = items[i];
13170 for(var i = start; i >= end; i--) {
13171 r[r.length] = items[i];
13178 * Filter the <i>objects</i> in this collection by a specific property.
13179 * Returns a new collection that has been filtered.
13180 * @param {String} property A property on your objects
13181 * @param {String/RegExp} value Either string that the property values
13182 * should start with or a RegExp to test against the property
13183 * @return {MixedCollection} The new filtered collection
13185 filter : function(property, value){
13186 if(!value.exec){ // not a regex
13187 value = String(value);
13188 if(value.length == 0){
13189 return this.clone();
13191 value = new RegExp("^" + Roo.escapeRe(value), "i");
13193 return this.filterBy(function(o){
13194 return o && value.test(o[property]);
13199 * Filter by a function. * Returns a new collection that has been filtered.
13200 * The passed function will be called with each
13201 * object in the collection. If the function returns true, the value is included
13202 * otherwise it is filtered.
13203 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13204 * @param {Object} scope (optional) The scope of the function (defaults to this)
13205 * @return {MixedCollection} The new filtered collection
13207 filterBy : function(fn, scope){
13208 var r = new Roo.util.MixedCollection();
13209 r.getKey = this.getKey;
13210 var k = this.keys, it = this.items;
13211 for(var i = 0, len = it.length; i < len; i++){
13212 if(fn.call(scope||this, it[i], k[i])){
13213 r.add(k[i], it[i]);
13220 * Creates a duplicate of this collection
13221 * @return {MixedCollection}
13223 clone : function(){
13224 var r = new Roo.util.MixedCollection();
13225 var k = this.keys, it = this.items;
13226 for(var i = 0, len = it.length; i < len; i++){
13227 r.add(k[i], it[i]);
13229 r.getKey = this.getKey;
13234 * Returns the item associated with the passed key or index.
13236 * @param {String/Number} key The key or index of the item.
13237 * @return {Object} The item associated with the passed key.
13239 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13241 * Ext JS Library 1.1.1
13242 * Copyright(c) 2006-2007, Ext JS, LLC.
13244 * Originally Released Under LGPL - original licence link has changed is not relivant.
13247 * <script type="text/javascript">
13250 * @class Roo.util.JSON
13251 * Modified version of Douglas Crockford"s json.js that doesn"t
13252 * mess with the Object prototype
13253 * http://www.json.org/js.html
13256 Roo.util.JSON = new (function(){
13257 var useHasOwn = {}.hasOwnProperty ? true : false;
13259 // crashes Safari in some instances
13260 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13262 var pad = function(n) {
13263 return n < 10 ? "0" + n : n;
13276 var encodeString = function(s){
13277 if (/["\\\x00-\x1f]/.test(s)) {
13278 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13283 c = b.charCodeAt();
13285 Math.floor(c / 16).toString(16) +
13286 (c % 16).toString(16);
13289 return '"' + s + '"';
13292 var encodeArray = function(o){
13293 var a = ["["], b, i, l = o.length, v;
13294 for (i = 0; i < l; i += 1) {
13296 switch (typeof v) {
13305 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13313 var encodeDate = function(o){
13314 return '"' + o.getFullYear() + "-" +
13315 pad(o.getMonth() + 1) + "-" +
13316 pad(o.getDate()) + "T" +
13317 pad(o.getHours()) + ":" +
13318 pad(o.getMinutes()) + ":" +
13319 pad(o.getSeconds()) + '"';
13323 * Encodes an Object, Array or other value
13324 * @param {Mixed} o The variable to encode
13325 * @return {String} The JSON string
13327 this.encode = function(o)
13329 // should this be extended to fully wrap stringify..
13331 if(typeof o == "undefined" || o === null){
13333 }else if(o instanceof Array){
13334 return encodeArray(o);
13335 }else if(o instanceof Date){
13336 return encodeDate(o);
13337 }else if(typeof o == "string"){
13338 return encodeString(o);
13339 }else if(typeof o == "number"){
13340 return isFinite(o) ? String(o) : "null";
13341 }else if(typeof o == "boolean"){
13344 var a = ["{"], b, i, v;
13346 if(!useHasOwn || o.hasOwnProperty(i)) {
13348 switch (typeof v) {
13357 a.push(this.encode(i), ":",
13358 v === null ? "null" : this.encode(v));
13369 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13370 * @param {String} json The JSON string
13371 * @return {Object} The resulting object
13373 this.decode = function(json){
13375 return /** eval:var:json */ eval("(" + json + ')');
13379 * Shorthand for {@link Roo.util.JSON#encode}
13380 * @member Roo encode
13382 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13384 * Shorthand for {@link Roo.util.JSON#decode}
13385 * @member Roo decode
13387 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13390 * Ext JS Library 1.1.1
13391 * Copyright(c) 2006-2007, Ext JS, LLC.
13393 * Originally Released Under LGPL - original licence link has changed is not relivant.
13396 * <script type="text/javascript">
13400 * @class Roo.util.Format
13401 * Reusable data formatting functions
13404 Roo.util.Format = function(){
13405 var trimRe = /^\s+|\s+$/g;
13408 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13409 * @param {String} value The string to truncate
13410 * @param {Number} length The maximum length to allow before truncating
13411 * @return {String} The converted text
13413 ellipsis : function(value, len){
13414 if(value && value.length > len){
13415 return value.substr(0, len-3)+"...";
13421 * Checks a reference and converts it to empty string if it is undefined
13422 * @param {Mixed} value Reference to check
13423 * @return {Mixed} Empty string if converted, otherwise the original value
13425 undef : function(value){
13426 return typeof value != "undefined" ? value : "";
13430 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13431 * @param {String} value The string to encode
13432 * @return {String} The encoded text
13434 htmlEncode : function(value){
13435 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13439 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13440 * @param {String} value The string to decode
13441 * @return {String} The decoded text
13443 htmlDecode : function(value){
13444 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13448 * Trims any whitespace from either side of a string
13449 * @param {String} value The text to trim
13450 * @return {String} The trimmed text
13452 trim : function(value){
13453 return String(value).replace(trimRe, "");
13457 * Returns a substring from within an original string
13458 * @param {String} value The original text
13459 * @param {Number} start The start index of the substring
13460 * @param {Number} length The length of the substring
13461 * @return {String} The substring
13463 substr : function(value, start, length){
13464 return String(value).substr(start, length);
13468 * Converts a string to all lower case letters
13469 * @param {String} value The text to convert
13470 * @return {String} The converted text
13472 lowercase : function(value){
13473 return String(value).toLowerCase();
13477 * Converts a string to all upper case letters
13478 * @param {String} value The text to convert
13479 * @return {String} The converted text
13481 uppercase : function(value){
13482 return String(value).toUpperCase();
13486 * Converts the first character only of a string to upper case
13487 * @param {String} value The text to convert
13488 * @return {String} The converted text
13490 capitalize : function(value){
13491 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13495 call : function(value, fn){
13496 if(arguments.length > 2){
13497 var args = Array.prototype.slice.call(arguments, 2);
13498 args.unshift(value);
13500 return /** eval:var:value */ eval(fn).apply(window, args);
13502 /** eval:var:value */
13503 return /** eval:var:value */ eval(fn).call(window, value);
13509 * safer version of Math.toFixed..??/
13510 * @param {Number/String} value The numeric value to format
13511 * @param {Number/String} value Decimal places
13512 * @return {String} The formatted currency string
13514 toFixed : function(v, n)
13516 // why not use to fixed - precision is buggered???
13518 return Math.round(v-0);
13520 var fact = Math.pow(10,n+1);
13521 v = (Math.round((v-0)*fact))/fact;
13522 var z = (''+fact).substring(2);
13523 if (v == Math.floor(v)) {
13524 return Math.floor(v) + '.' + z;
13527 // now just padd decimals..
13528 var ps = String(v).split('.');
13529 var fd = (ps[1] + z);
13530 var r = fd.substring(0,n);
13531 var rm = fd.substring(n);
13533 return ps[0] + '.' + r;
13535 r*=1; // turn it into a number;
13537 if (String(r).length != n) {
13540 r = String(r).substring(1); // chop the end off.
13543 return ps[0] + '.' + r;
13548 * Format a number as US currency
13549 * @param {Number/String} value The numeric value to format
13550 * @return {String} The formatted currency string
13552 usMoney : function(v){
13553 return '$' + Roo.util.Format.number(v);
13558 * eventually this should probably emulate php's number_format
13559 * @param {Number/String} value The numeric value to format
13560 * @param {Number} decimals number of decimal places
13561 * @return {String} The formatted currency string
13563 number : function(v,decimals)
13565 // multiply and round.
13566 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13567 var mul = Math.pow(10, decimals);
13568 var zero = String(mul).substring(1);
13569 v = (Math.round((v-0)*mul))/mul;
13571 // if it's '0' number.. then
13573 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13575 var ps = v.split('.');
13579 var r = /(\d+)(\d{3})/;
13581 while (r.test(whole)) {
13582 whole = whole.replace(r, '$1' + ',' + '$2');
13588 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13589 // does not have decimals
13590 (decimals ? ('.' + zero) : '');
13593 return whole + sub ;
13597 * Parse a value into a formatted date using the specified format pattern.
13598 * @param {Mixed} value The value to format
13599 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13600 * @return {String} The formatted date string
13602 date : function(v, format){
13606 if(!(v instanceof Date)){
13607 v = new Date(Date.parse(v));
13609 return v.dateFormat(format || "m/d/Y");
13613 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13614 * @param {String} format Any valid date format string
13615 * @return {Function} The date formatting function
13617 dateRenderer : function(format){
13618 return function(v){
13619 return Roo.util.Format.date(v, format);
13624 stripTagsRE : /<\/?[^>]+>/gi,
13627 * Strips all HTML tags
13628 * @param {Mixed} value The text from which to strip tags
13629 * @return {String} The stripped text
13631 stripTags : function(v){
13632 return !v ? v : String(v).replace(this.stripTagsRE, "");
13637 * Ext JS Library 1.1.1
13638 * Copyright(c) 2006-2007, Ext JS, LLC.
13640 * Originally Released Under LGPL - original licence link has changed is not relivant.
13643 * <script type="text/javascript">
13650 * @class Roo.MasterTemplate
13651 * @extends Roo.Template
13652 * Provides a template that can have child templates. The syntax is:
13654 var t = new Roo.MasterTemplate(
13655 '<select name="{name}">',
13656 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13659 t.add('options', {value: 'foo', text: 'bar'});
13660 // or you can add multiple child elements in one shot
13661 t.addAll('options', [
13662 {value: 'foo', text: 'bar'},
13663 {value: 'foo2', text: 'bar2'},
13664 {value: 'foo3', text: 'bar3'}
13666 // then append, applying the master template values
13667 t.append('my-form', {name: 'my-select'});
13669 * A name attribute for the child template is not required if you have only one child
13670 * template or you want to refer to them by index.
13672 Roo.MasterTemplate = function(){
13673 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13674 this.originalHtml = this.html;
13676 var m, re = this.subTemplateRe;
13679 while(m = re.exec(this.html)){
13680 var name = m[1], content = m[2];
13685 tpl : new Roo.Template(content)
13688 st[name] = st[subIndex];
13690 st[subIndex].tpl.compile();
13691 st[subIndex].tpl.call = this.call.createDelegate(this);
13694 this.subCount = subIndex;
13697 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13699 * The regular expression used to match sub templates
13703 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13706 * Applies the passed values to a child template.
13707 * @param {String/Number} name (optional) The name or index of the child template
13708 * @param {Array/Object} values The values to be applied to the template
13709 * @return {MasterTemplate} this
13711 add : function(name, values){
13712 if(arguments.length == 1){
13713 values = arguments[0];
13716 var s = this.subs[name];
13717 s.buffer[s.buffer.length] = s.tpl.apply(values);
13722 * Applies all the passed values to a child template.
13723 * @param {String/Number} name (optional) The name or index of the child template
13724 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13725 * @param {Boolean} reset (optional) True to reset the template first
13726 * @return {MasterTemplate} this
13728 fill : function(name, values, reset){
13730 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13738 for(var i = 0, len = values.length; i < len; i++){
13739 this.add(name, values[i]);
13745 * Resets the template for reuse
13746 * @return {MasterTemplate} this
13748 reset : function(){
13750 for(var i = 0; i < this.subCount; i++){
13756 applyTemplate : function(values){
13758 var replaceIndex = -1;
13759 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13760 return s[++replaceIndex].buffer.join("");
13762 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13765 apply : function(){
13766 return this.applyTemplate.apply(this, arguments);
13769 compile : function(){return this;}
13773 * Alias for fill().
13776 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13778 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13779 * var tpl = Roo.MasterTemplate.from('element-id');
13780 * @param {String/HTMLElement} el
13781 * @param {Object} config
13784 Roo.MasterTemplate.from = function(el, config){
13785 el = Roo.getDom(el);
13786 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13789 * Ext JS Library 1.1.1
13790 * Copyright(c) 2006-2007, Ext JS, LLC.
13792 * Originally Released Under LGPL - original licence link has changed is not relivant.
13795 * <script type="text/javascript">
13800 * @class Roo.util.CSS
13801 * Utility class for manipulating CSS rules
13804 Roo.util.CSS = function(){
13806 var doc = document;
13808 var camelRe = /(-[a-z])/gi;
13809 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13813 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13814 * tag and appended to the HEAD of the document.
13815 * @param {String|Object} cssText The text containing the css rules
13816 * @param {String} id An id to add to the stylesheet for later removal
13817 * @return {StyleSheet}
13819 createStyleSheet : function(cssText, id){
13821 var head = doc.getElementsByTagName("head")[0];
13822 var nrules = doc.createElement("style");
13823 nrules.setAttribute("type", "text/css");
13825 nrules.setAttribute("id", id);
13827 if (typeof(cssText) != 'string') {
13828 // support object maps..
13829 // not sure if this a good idea..
13830 // perhaps it should be merged with the general css handling
13831 // and handle js style props.
13832 var cssTextNew = [];
13833 for(var n in cssText) {
13835 for(var k in cssText[n]) {
13836 citems.push( k + ' : ' +cssText[n][k] + ';' );
13838 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13841 cssText = cssTextNew.join("\n");
13847 head.appendChild(nrules);
13848 ss = nrules.styleSheet;
13849 ss.cssText = cssText;
13852 nrules.appendChild(doc.createTextNode(cssText));
13854 nrules.cssText = cssText;
13856 head.appendChild(nrules);
13857 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13859 this.cacheStyleSheet(ss);
13864 * Removes a style or link tag by id
13865 * @param {String} id The id of the tag
13867 removeStyleSheet : function(id){
13868 var existing = doc.getElementById(id);
13870 existing.parentNode.removeChild(existing);
13875 * Dynamically swaps an existing stylesheet reference for a new one
13876 * @param {String} id The id of an existing link tag to remove
13877 * @param {String} url The href of the new stylesheet to include
13879 swapStyleSheet : function(id, url){
13880 this.removeStyleSheet(id);
13881 var ss = doc.createElement("link");
13882 ss.setAttribute("rel", "stylesheet");
13883 ss.setAttribute("type", "text/css");
13884 ss.setAttribute("id", id);
13885 ss.setAttribute("href", url);
13886 doc.getElementsByTagName("head")[0].appendChild(ss);
13890 * Refresh the rule cache if you have dynamically added stylesheets
13891 * @return {Object} An object (hash) of rules indexed by selector
13893 refreshCache : function(){
13894 return this.getRules(true);
13898 cacheStyleSheet : function(stylesheet){
13902 try{// try catch for cross domain access issue
13903 var ssRules = stylesheet.cssRules || stylesheet.rules;
13904 for(var j = ssRules.length-1; j >= 0; --j){
13905 rules[ssRules[j].selectorText] = ssRules[j];
13911 * Gets all css rules for the document
13912 * @param {Boolean} refreshCache true to refresh the internal cache
13913 * @return {Object} An object (hash) of rules indexed by selector
13915 getRules : function(refreshCache){
13916 if(rules == null || refreshCache){
13918 var ds = doc.styleSheets;
13919 for(var i =0, len = ds.length; i < len; i++){
13921 this.cacheStyleSheet(ds[i]);
13929 * Gets an an individual CSS rule by selector(s)
13930 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13931 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13932 * @return {CSSRule} The CSS rule or null if one is not found
13934 getRule : function(selector, refreshCache){
13935 var rs = this.getRules(refreshCache);
13936 if(!(selector instanceof Array)){
13937 return rs[selector];
13939 for(var i = 0; i < selector.length; i++){
13940 if(rs[selector[i]]){
13941 return rs[selector[i]];
13949 * Updates a rule property
13950 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13951 * @param {String} property The css property
13952 * @param {String} value The new value for the property
13953 * @return {Boolean} true If a rule was found and updated
13955 updateRule : function(selector, property, value){
13956 if(!(selector instanceof Array)){
13957 var rule = this.getRule(selector);
13959 rule.style[property.replace(camelRe, camelFn)] = value;
13963 for(var i = 0; i < selector.length; i++){
13964 if(this.updateRule(selector[i], property, value)){
13974 * Ext JS Library 1.1.1
13975 * Copyright(c) 2006-2007, Ext JS, LLC.
13977 * Originally Released Under LGPL - original licence link has changed is not relivant.
13980 * <script type="text/javascript">
13986 * @class Roo.util.ClickRepeater
13987 * @extends Roo.util.Observable
13989 * A wrapper class which can be applied to any element. Fires a "click" event while the
13990 * mouse is pressed. The interval between firings may be specified in the config but
13991 * defaults to 10 milliseconds.
13993 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13995 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13996 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13997 * Similar to an autorepeat key delay.
13998 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13999 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14000 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14001 * "interval" and "delay" are ignored. "immediate" is honored.
14002 * @cfg {Boolean} preventDefault True to prevent the default click event
14003 * @cfg {Boolean} stopDefault True to stop the default click event
14006 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14007 * 2007-02-02 jvs Renamed to ClickRepeater
14008 * 2007-02-03 jvs Modifications for FF Mac and Safari
14011 * @param {String/HTMLElement/Element} el The element to listen on
14012 * @param {Object} config
14014 Roo.util.ClickRepeater = function(el, config)
14016 this.el = Roo.get(el);
14017 this.el.unselectable();
14019 Roo.apply(this, config);
14024 * Fires when the mouse button is depressed.
14025 * @param {Roo.util.ClickRepeater} this
14027 "mousedown" : true,
14030 * Fires on a specified interval during the time the element is pressed.
14031 * @param {Roo.util.ClickRepeater} this
14036 * Fires when the mouse key is released.
14037 * @param {Roo.util.ClickRepeater} this
14042 this.el.on("mousedown", this.handleMouseDown, this);
14043 if(this.preventDefault || this.stopDefault){
14044 this.el.on("click", function(e){
14045 if(this.preventDefault){
14046 e.preventDefault();
14048 if(this.stopDefault){
14054 // allow inline handler
14056 this.on("click", this.handler, this.scope || this);
14059 Roo.util.ClickRepeater.superclass.constructor.call(this);
14062 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14065 preventDefault : true,
14066 stopDefault : false,
14070 handleMouseDown : function(){
14071 clearTimeout(this.timer);
14073 if(this.pressClass){
14074 this.el.addClass(this.pressClass);
14076 this.mousedownTime = new Date();
14078 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14079 this.el.on("mouseout", this.handleMouseOut, this);
14081 this.fireEvent("mousedown", this);
14082 this.fireEvent("click", this);
14084 this.timer = this.click.defer(this.delay || this.interval, this);
14088 click : function(){
14089 this.fireEvent("click", this);
14090 this.timer = this.click.defer(this.getInterval(), this);
14094 getInterval: function(){
14095 if(!this.accelerate){
14096 return this.interval;
14098 var pressTime = this.mousedownTime.getElapsed();
14099 if(pressTime < 500){
14101 }else if(pressTime < 1700){
14103 }else if(pressTime < 2600){
14105 }else if(pressTime < 3500){
14107 }else if(pressTime < 4400){
14109 }else if(pressTime < 5300){
14111 }else if(pressTime < 6200){
14119 handleMouseOut : function(){
14120 clearTimeout(this.timer);
14121 if(this.pressClass){
14122 this.el.removeClass(this.pressClass);
14124 this.el.on("mouseover", this.handleMouseReturn, this);
14128 handleMouseReturn : function(){
14129 this.el.un("mouseover", this.handleMouseReturn);
14130 if(this.pressClass){
14131 this.el.addClass(this.pressClass);
14137 handleMouseUp : function(){
14138 clearTimeout(this.timer);
14139 this.el.un("mouseover", this.handleMouseReturn);
14140 this.el.un("mouseout", this.handleMouseOut);
14141 Roo.get(document).un("mouseup", this.handleMouseUp);
14142 this.el.removeClass(this.pressClass);
14143 this.fireEvent("mouseup", this);
14147 * Ext JS Library 1.1.1
14148 * Copyright(c) 2006-2007, Ext JS, LLC.
14150 * Originally Released Under LGPL - original licence link has changed is not relivant.
14153 * <script type="text/javascript">
14158 * @class Roo.KeyNav
14159 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14160 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14161 * way to implement custom navigation schemes for any UI component.</p>
14162 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14163 * pageUp, pageDown, del, home, end. Usage:</p>
14165 var nav = new Roo.KeyNav("my-element", {
14166 "left" : function(e){
14167 this.moveLeft(e.ctrlKey);
14169 "right" : function(e){
14170 this.moveRight(e.ctrlKey);
14172 "enter" : function(e){
14179 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14180 * @param {Object} config The config
14182 Roo.KeyNav = function(el, config){
14183 this.el = Roo.get(el);
14184 Roo.apply(this, config);
14185 if(!this.disabled){
14186 this.disabled = true;
14191 Roo.KeyNav.prototype = {
14193 * @cfg {Boolean} disabled
14194 * True to disable this KeyNav instance (defaults to false)
14198 * @cfg {String} defaultEventAction
14199 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14200 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14201 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14203 defaultEventAction: "stopEvent",
14205 * @cfg {Boolean} forceKeyDown
14206 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14207 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14208 * handle keydown instead of keypress.
14210 forceKeyDown : false,
14213 prepareEvent : function(e){
14214 var k = e.getKey();
14215 var h = this.keyToHandler[k];
14216 //if(h && this[h]){
14217 // e.stopPropagation();
14219 if(Roo.isSafari && h && k >= 37 && k <= 40){
14225 relay : function(e){
14226 var k = e.getKey();
14227 var h = this.keyToHandler[k];
14229 if(this.doRelay(e, this[h], h) !== true){
14230 e[this.defaultEventAction]();
14236 doRelay : function(e, h, hname){
14237 return h.call(this.scope || this, e);
14240 // possible handlers
14254 // quick lookup hash
14271 * Enable this KeyNav
14273 enable: function(){
14275 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14276 // the EventObject will normalize Safari automatically
14277 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14278 this.el.on("keydown", this.relay, this);
14280 this.el.on("keydown", this.prepareEvent, this);
14281 this.el.on("keypress", this.relay, this);
14283 this.disabled = false;
14288 * Disable this KeyNav
14290 disable: function(){
14291 if(!this.disabled){
14292 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14293 this.el.un("keydown", this.relay);
14295 this.el.un("keydown", this.prepareEvent);
14296 this.el.un("keypress", this.relay);
14298 this.disabled = true;
14303 * Ext JS Library 1.1.1
14304 * Copyright(c) 2006-2007, Ext JS, LLC.
14306 * Originally Released Under LGPL - original licence link has changed is not relivant.
14309 * <script type="text/javascript">
14314 * @class Roo.KeyMap
14315 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14316 * The constructor accepts the same config object as defined by {@link #addBinding}.
14317 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14318 * combination it will call the function with this signature (if the match is a multi-key
14319 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14320 * A KeyMap can also handle a string representation of keys.<br />
14323 // map one key by key code
14324 var map = new Roo.KeyMap("my-element", {
14325 key: 13, // or Roo.EventObject.ENTER
14330 // map multiple keys to one action by string
14331 var map = new Roo.KeyMap("my-element", {
14337 // map multiple keys to multiple actions by strings and array of codes
14338 var map = new Roo.KeyMap("my-element", [
14341 fn: function(){ alert("Return was pressed"); }
14344 fn: function(){ alert('a, b or c was pressed'); }
14349 fn: function(){ alert('Control + shift + tab was pressed.'); }
14353 * <b>Note: A KeyMap starts enabled</b>
14355 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14356 * @param {Object} config The config (see {@link #addBinding})
14357 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14359 Roo.KeyMap = function(el, config, eventName){
14360 this.el = Roo.get(el);
14361 this.eventName = eventName || "keydown";
14362 this.bindings = [];
14364 this.addBinding(config);
14369 Roo.KeyMap.prototype = {
14371 * True to stop the event from bubbling and prevent the default browser action if the
14372 * key was handled by the KeyMap (defaults to false)
14378 * Add a new binding to this KeyMap. The following config object properties are supported:
14380 Property Type Description
14381 ---------- --------------- ----------------------------------------------------------------------
14382 key String/Array A single keycode or an array of keycodes to handle
14383 shift Boolean True to handle key only when shift is pressed (defaults to false)
14384 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14385 alt Boolean True to handle key only when alt is pressed (defaults to false)
14386 fn Function The function to call when KeyMap finds the expected key combination
14387 scope Object The scope of the callback function
14393 var map = new Roo.KeyMap(document, {
14394 key: Roo.EventObject.ENTER,
14399 //Add a new binding to the existing KeyMap later
14407 * @param {Object/Array} config A single KeyMap config or an array of configs
14409 addBinding : function(config){
14410 if(config instanceof Array){
14411 for(var i = 0, len = config.length; i < len; i++){
14412 this.addBinding(config[i]);
14416 var keyCode = config.key,
14417 shift = config.shift,
14418 ctrl = config.ctrl,
14421 scope = config.scope;
14422 if(typeof keyCode == "string"){
14424 var keyString = keyCode.toUpperCase();
14425 for(var j = 0, len = keyString.length; j < len; j++){
14426 ks.push(keyString.charCodeAt(j));
14430 var keyArray = keyCode instanceof Array;
14431 var handler = function(e){
14432 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14433 var k = e.getKey();
14435 for(var i = 0, len = keyCode.length; i < len; i++){
14436 if(keyCode[i] == k){
14437 if(this.stopEvent){
14440 fn.call(scope || window, k, e);
14446 if(this.stopEvent){
14449 fn.call(scope || window, k, e);
14454 this.bindings.push(handler);
14458 * Shorthand for adding a single key listener
14459 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14460 * following options:
14461 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14462 * @param {Function} fn The function to call
14463 * @param {Object} scope (optional) The scope of the function
14465 on : function(key, fn, scope){
14466 var keyCode, shift, ctrl, alt;
14467 if(typeof key == "object" && !(key instanceof Array)){
14486 handleKeyDown : function(e){
14487 if(this.enabled){ //just in case
14488 var b = this.bindings;
14489 for(var i = 0, len = b.length; i < len; i++){
14490 b[i].call(this, e);
14496 * Returns true if this KeyMap is enabled
14497 * @return {Boolean}
14499 isEnabled : function(){
14500 return this.enabled;
14504 * Enables this KeyMap
14506 enable: function(){
14508 this.el.on(this.eventName, this.handleKeyDown, this);
14509 this.enabled = true;
14514 * Disable this KeyMap
14516 disable: function(){
14518 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14519 this.enabled = false;
14524 * Ext JS Library 1.1.1
14525 * Copyright(c) 2006-2007, Ext JS, LLC.
14527 * Originally Released Under LGPL - original licence link has changed is not relivant.
14530 * <script type="text/javascript">
14535 * @class Roo.util.TextMetrics
14536 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14537 * wide, in pixels, a given block of text will be.
14540 Roo.util.TextMetrics = function(){
14544 * Measures the size of the specified text
14545 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14546 * that can affect the size of the rendered text
14547 * @param {String} text The text to measure
14548 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14549 * in order to accurately measure the text height
14550 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14552 measure : function(el, text, fixedWidth){
14554 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14557 shared.setFixedWidth(fixedWidth || 'auto');
14558 return shared.getSize(text);
14562 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14563 * the overhead of multiple calls to initialize the style properties on each measurement.
14564 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14565 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14566 * in order to accurately measure the text height
14567 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14569 createInstance : function(el, fixedWidth){
14570 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14577 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14578 var ml = new Roo.Element(document.createElement('div'));
14579 document.body.appendChild(ml.dom);
14580 ml.position('absolute');
14581 ml.setLeftTop(-1000, -1000);
14585 ml.setWidth(fixedWidth);
14590 * Returns the size of the specified text based on the internal element's style and width properties
14591 * @memberOf Roo.util.TextMetrics.Instance#
14592 * @param {String} text The text to measure
14593 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14595 getSize : function(text){
14597 var s = ml.getSize();
14603 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14604 * that can affect the size of the rendered text
14605 * @memberOf Roo.util.TextMetrics.Instance#
14606 * @param {String/HTMLElement} el The element, dom node or id
14608 bind : function(el){
14610 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14615 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14616 * to set a fixed width in order to accurately measure the text height.
14617 * @memberOf Roo.util.TextMetrics.Instance#
14618 * @param {Number} width The width to set on the element
14620 setFixedWidth : function(width){
14621 ml.setWidth(width);
14625 * Returns the measured width of the specified text
14626 * @memberOf Roo.util.TextMetrics.Instance#
14627 * @param {String} text The text to measure
14628 * @return {Number} width The width in pixels
14630 getWidth : function(text){
14631 ml.dom.style.width = 'auto';
14632 return this.getSize(text).width;
14636 * Returns the measured height of the specified text. For multiline text, be sure to call
14637 * {@link #setFixedWidth} if necessary.
14638 * @memberOf Roo.util.TextMetrics.Instance#
14639 * @param {String} text The text to measure
14640 * @return {Number} height The height in pixels
14642 getHeight : function(text){
14643 return this.getSize(text).height;
14647 instance.bind(bindTo);
14652 // backwards compat
14653 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14655 * Ext JS Library 1.1.1
14656 * Copyright(c) 2006-2007, Ext JS, LLC.
14658 * Originally Released Under LGPL - original licence link has changed is not relivant.
14661 * <script type="text/javascript">
14665 * @class Roo.state.Provider
14666 * Abstract base class for state provider implementations. This class provides methods
14667 * for encoding and decoding <b>typed</b> variables including dates and defines the
14668 * Provider interface.
14670 Roo.state.Provider = function(){
14672 * @event statechange
14673 * Fires when a state change occurs.
14674 * @param {Provider} this This state provider
14675 * @param {String} key The state key which was changed
14676 * @param {String} value The encoded value for the state
14679 "statechange": true
14682 Roo.state.Provider.superclass.constructor.call(this);
14684 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14686 * Returns the current value for a key
14687 * @param {String} name The key name
14688 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14689 * @return {Mixed} The state data
14691 get : function(name, defaultValue){
14692 return typeof this.state[name] == "undefined" ?
14693 defaultValue : this.state[name];
14697 * Clears a value from the state
14698 * @param {String} name The key name
14700 clear : function(name){
14701 delete this.state[name];
14702 this.fireEvent("statechange", this, name, null);
14706 * Sets the value for a key
14707 * @param {String} name The key name
14708 * @param {Mixed} value The value to set
14710 set : function(name, value){
14711 this.state[name] = value;
14712 this.fireEvent("statechange", this, name, value);
14716 * Decodes a string previously encoded with {@link #encodeValue}.
14717 * @param {String} value The value to decode
14718 * @return {Mixed} The decoded value
14720 decodeValue : function(cookie){
14721 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14722 var matches = re.exec(unescape(cookie));
14723 if(!matches || !matches[1]) return; // non state cookie
14724 var type = matches[1];
14725 var v = matches[2];
14728 return parseFloat(v);
14730 return new Date(Date.parse(v));
14735 var values = v.split("^");
14736 for(var i = 0, len = values.length; i < len; i++){
14737 all.push(this.decodeValue(values[i]));
14742 var values = v.split("^");
14743 for(var i = 0, len = values.length; i < len; i++){
14744 var kv = values[i].split("=");
14745 all[kv[0]] = this.decodeValue(kv[1]);
14754 * Encodes a value including type information. Decode with {@link #decodeValue}.
14755 * @param {Mixed} value The value to encode
14756 * @return {String} The encoded value
14758 encodeValue : function(v){
14760 if(typeof v == "number"){
14762 }else if(typeof v == "boolean"){
14763 enc = "b:" + (v ? "1" : "0");
14764 }else if(v instanceof Date){
14765 enc = "d:" + v.toGMTString();
14766 }else if(v instanceof Array){
14768 for(var i = 0, len = v.length; i < len; i++){
14769 flat += this.encodeValue(v[i]);
14770 if(i != len-1) flat += "^";
14773 }else if(typeof v == "object"){
14776 if(typeof v[key] != "function"){
14777 flat += key + "=" + this.encodeValue(v[key]) + "^";
14780 enc = "o:" + flat.substring(0, flat.length-1);
14784 return escape(enc);
14790 * Ext JS Library 1.1.1
14791 * Copyright(c) 2006-2007, Ext JS, LLC.
14793 * Originally Released Under LGPL - original licence link has changed is not relivant.
14796 * <script type="text/javascript">
14799 * @class Roo.state.Manager
14800 * This is the global state manager. By default all components that are "state aware" check this class
14801 * for state information if you don't pass them a custom state provider. In order for this class
14802 * to be useful, it must be initialized with a provider when your application initializes.
14804 // in your initialization function
14806 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14808 // supposed you have a {@link Roo.BorderLayout}
14809 var layout = new Roo.BorderLayout(...);
14810 layout.restoreState();
14811 // or a {Roo.BasicDialog}
14812 var dialog = new Roo.BasicDialog(...);
14813 dialog.restoreState();
14817 Roo.state.Manager = function(){
14818 var provider = new Roo.state.Provider();
14822 * Configures the default state provider for your application
14823 * @param {Provider} stateProvider The state provider to set
14825 setProvider : function(stateProvider){
14826 provider = stateProvider;
14830 * Returns the current value for a key
14831 * @param {String} name The key name
14832 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14833 * @return {Mixed} The state data
14835 get : function(key, defaultValue){
14836 return provider.get(key, defaultValue);
14840 * Sets the value for a key
14841 * @param {String} name The key name
14842 * @param {Mixed} value The state data
14844 set : function(key, value){
14845 provider.set(key, value);
14849 * Clears a value from the state
14850 * @param {String} name The key name
14852 clear : function(key){
14853 provider.clear(key);
14857 * Gets the currently configured state provider
14858 * @return {Provider} The state provider
14860 getProvider : function(){
14867 * Ext JS Library 1.1.1
14868 * Copyright(c) 2006-2007, Ext JS, LLC.
14870 * Originally Released Under LGPL - original licence link has changed is not relivant.
14873 * <script type="text/javascript">
14876 * @class Roo.state.CookieProvider
14877 * @extends Roo.state.Provider
14878 * The default Provider implementation which saves state via cookies.
14881 var cp = new Roo.state.CookieProvider({
14883 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14884 domain: "roojs.com"
14886 Roo.state.Manager.setProvider(cp);
14888 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14889 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14890 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14891 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14892 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14893 * domain the page is running on including the 'www' like 'www.roojs.com')
14894 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14896 * Create a new CookieProvider
14897 * @param {Object} config The configuration object
14899 Roo.state.CookieProvider = function(config){
14900 Roo.state.CookieProvider.superclass.constructor.call(this);
14902 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14903 this.domain = null;
14904 this.secure = false;
14905 Roo.apply(this, config);
14906 this.state = this.readCookies();
14909 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14911 set : function(name, value){
14912 if(typeof value == "undefined" || value === null){
14916 this.setCookie(name, value);
14917 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14921 clear : function(name){
14922 this.clearCookie(name);
14923 Roo.state.CookieProvider.superclass.clear.call(this, name);
14927 readCookies : function(){
14929 var c = document.cookie + ";";
14930 var re = /\s?(.*?)=(.*?);/g;
14932 while((matches = re.exec(c)) != null){
14933 var name = matches[1];
14934 var value = matches[2];
14935 if(name && name.substring(0,3) == "ys-"){
14936 cookies[name.substr(3)] = this.decodeValue(value);
14943 setCookie : function(name, value){
14944 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14945 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14946 ((this.path == null) ? "" : ("; path=" + this.path)) +
14947 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14948 ((this.secure == true) ? "; secure" : "");
14952 clearCookie : function(name){
14953 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14954 ((this.path == null) ? "" : ("; path=" + this.path)) +
14955 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14956 ((this.secure == true) ? "; secure" : "");
14960 * Ext JS Library 1.1.1
14961 * Copyright(c) 2006-2007, Ext JS, LLC.
14963 * Originally Released Under LGPL - original licence link has changed is not relivant.
14966 * <script type="text/javascript">
14971 * @class Roo.ComponentMgr
14972 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14975 Roo.ComponentMgr = function(){
14976 var all = new Roo.util.MixedCollection();
14980 * Registers a component.
14981 * @param {Roo.Component} c The component
14983 register : function(c){
14988 * Unregisters a component.
14989 * @param {Roo.Component} c The component
14991 unregister : function(c){
14996 * Returns a component by id
14997 * @param {String} id The component id
14999 get : function(id){
15000 return all.get(id);
15004 * Registers a function that will be called when a specified component is added to ComponentMgr
15005 * @param {String} id The component id
15006 * @param {Funtction} fn The callback function
15007 * @param {Object} scope The scope of the callback
15009 onAvailable : function(id, fn, scope){
15010 all.on("add", function(index, o){
15012 fn.call(scope || o, o);
15013 all.un("add", fn, scope);
15020 * Ext JS Library 1.1.1
15021 * Copyright(c) 2006-2007, Ext JS, LLC.
15023 * Originally Released Under LGPL - original licence link has changed is not relivant.
15026 * <script type="text/javascript">
15030 * @class Roo.Component
15031 * @extends Roo.util.Observable
15032 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15033 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15034 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15035 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15036 * All visual components (widgets) that require rendering into a layout should subclass Component.
15038 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15039 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
15040 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15042 Roo.Component = function(config){
15043 config = config || {};
15044 if(config.tagName || config.dom || typeof config == "string"){ // element object
15045 config = {el: config, id: config.id || config};
15047 this.initialConfig = config;
15049 Roo.apply(this, config);
15053 * Fires after the component is disabled.
15054 * @param {Roo.Component} this
15059 * Fires after the component is enabled.
15060 * @param {Roo.Component} this
15064 * @event beforeshow
15065 * Fires before the component is shown. Return false to stop the show.
15066 * @param {Roo.Component} this
15071 * Fires after the component is shown.
15072 * @param {Roo.Component} this
15076 * @event beforehide
15077 * Fires before the component is hidden. Return false to stop the hide.
15078 * @param {Roo.Component} this
15083 * Fires after the component is hidden.
15084 * @param {Roo.Component} this
15088 * @event beforerender
15089 * Fires before the component is rendered. Return false to stop the render.
15090 * @param {Roo.Component} this
15092 beforerender : true,
15095 * Fires after the component is rendered.
15096 * @param {Roo.Component} this
15100 * @event beforedestroy
15101 * Fires before the component is destroyed. Return false to stop the destroy.
15102 * @param {Roo.Component} this
15104 beforedestroy : true,
15107 * Fires after the component is destroyed.
15108 * @param {Roo.Component} this
15113 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15115 Roo.ComponentMgr.register(this);
15116 Roo.Component.superclass.constructor.call(this);
15117 this.initComponent();
15118 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15119 this.render(this.renderTo);
15120 delete this.renderTo;
15125 Roo.Component.AUTO_ID = 1000;
15127 Roo.extend(Roo.Component, Roo.util.Observable, {
15129 * @scope Roo.Component.prototype
15131 * true if this component is hidden. Read-only.
15136 * true if this component is disabled. Read-only.
15141 * true if this component has been rendered. Read-only.
15145 /** @cfg {String} disableClass
15146 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15148 disabledClass : "x-item-disabled",
15149 /** @cfg {Boolean} allowDomMove
15150 * Whether the component can move the Dom node when rendering (defaults to true).
15152 allowDomMove : true,
15153 /** @cfg {String} hideMode
15154 * How this component should hidden. Supported values are
15155 * "visibility" (css visibility), "offsets" (negative offset position) and
15156 * "display" (css display) - defaults to "display".
15158 hideMode: 'display',
15161 ctype : "Roo.Component",
15164 * @cfg {String} actionMode
15165 * which property holds the element that used for hide() / show() / disable() / enable()
15171 getActionEl : function(){
15172 return this[this.actionMode];
15175 initComponent : Roo.emptyFn,
15177 * If this is a lazy rendering component, render it to its container element.
15178 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15180 render : function(container, position){
15181 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15182 if(!container && this.el){
15183 this.el = Roo.get(this.el);
15184 container = this.el.dom.parentNode;
15185 this.allowDomMove = false;
15187 this.container = Roo.get(container);
15188 this.rendered = true;
15189 if(position !== undefined){
15190 if(typeof position == 'number'){
15191 position = this.container.dom.childNodes[position];
15193 position = Roo.getDom(position);
15196 this.onRender(this.container, position || null);
15198 this.el.addClass(this.cls);
15202 this.el.applyStyles(this.style);
15205 this.fireEvent("render", this);
15206 this.afterRender(this.container);
15218 // default function is not really useful
15219 onRender : function(ct, position){
15221 this.el = Roo.get(this.el);
15222 if(this.allowDomMove !== false){
15223 ct.dom.insertBefore(this.el.dom, position);
15229 getAutoCreate : function(){
15230 var cfg = typeof this.autoCreate == "object" ?
15231 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15232 if(this.id && !cfg.id){
15239 afterRender : Roo.emptyFn,
15242 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15243 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15245 destroy : function(){
15246 if(this.fireEvent("beforedestroy", this) !== false){
15247 this.purgeListeners();
15248 this.beforeDestroy();
15250 this.el.removeAllListeners();
15252 if(this.actionMode == "container"){
15253 this.container.remove();
15257 Roo.ComponentMgr.unregister(this);
15258 this.fireEvent("destroy", this);
15263 beforeDestroy : function(){
15268 onDestroy : function(){
15273 * Returns the underlying {@link Roo.Element}.
15274 * @return {Roo.Element} The element
15276 getEl : function(){
15281 * Returns the id of this component.
15284 getId : function(){
15289 * Try to focus this component.
15290 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15291 * @return {Roo.Component} this
15293 focus : function(selectText){
15296 if(selectText === true){
15297 this.el.dom.select();
15312 * Disable this component.
15313 * @return {Roo.Component} this
15315 disable : function(){
15319 this.disabled = true;
15320 this.fireEvent("disable", this);
15325 onDisable : function(){
15326 this.getActionEl().addClass(this.disabledClass);
15327 this.el.dom.disabled = true;
15331 * Enable this component.
15332 * @return {Roo.Component} this
15334 enable : function(){
15338 this.disabled = false;
15339 this.fireEvent("enable", this);
15344 onEnable : function(){
15345 this.getActionEl().removeClass(this.disabledClass);
15346 this.el.dom.disabled = false;
15350 * Convenience function for setting disabled/enabled by boolean.
15351 * @param {Boolean} disabled
15353 setDisabled : function(disabled){
15354 this[disabled ? "disable" : "enable"]();
15358 * Show this component.
15359 * @return {Roo.Component} this
15362 if(this.fireEvent("beforeshow", this) !== false){
15363 this.hidden = false;
15367 this.fireEvent("show", this);
15373 onShow : function(){
15374 var ae = this.getActionEl();
15375 if(this.hideMode == 'visibility'){
15376 ae.dom.style.visibility = "visible";
15377 }else if(this.hideMode == 'offsets'){
15378 ae.removeClass('x-hidden');
15380 ae.dom.style.display = "";
15385 * Hide this component.
15386 * @return {Roo.Component} this
15389 if(this.fireEvent("beforehide", this) !== false){
15390 this.hidden = true;
15394 this.fireEvent("hide", this);
15400 onHide : function(){
15401 var ae = this.getActionEl();
15402 if(this.hideMode == 'visibility'){
15403 ae.dom.style.visibility = "hidden";
15404 }else if(this.hideMode == 'offsets'){
15405 ae.addClass('x-hidden');
15407 ae.dom.style.display = "none";
15412 * Convenience function to hide or show this component by boolean.
15413 * @param {Boolean} visible True to show, false to hide
15414 * @return {Roo.Component} this
15416 setVisible: function(visible){
15426 * Returns true if this component is visible.
15428 isVisible : function(){
15429 return this.getActionEl().isVisible();
15432 cloneConfig : function(overrides){
15433 overrides = overrides || {};
15434 var id = overrides.id || Roo.id();
15435 var cfg = Roo.applyIf(overrides, this.initialConfig);
15436 cfg.id = id; // prevent dup id
15437 return new this.constructor(cfg);
15441 * Ext JS Library 1.1.1
15442 * Copyright(c) 2006-2007, Ext JS, LLC.
15444 * Originally Released Under LGPL - original licence link has changed is not relivant.
15447 * <script type="text/javascript">
15451 * @class Roo.BoxComponent
15452 * @extends Roo.Component
15453 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15454 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15455 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15456 * layout containers.
15458 * @param {Roo.Element/String/Object} config The configuration options.
15460 Roo.BoxComponent = function(config){
15461 Roo.Component.call(this, config);
15465 * Fires after the component is resized.
15466 * @param {Roo.Component} this
15467 * @param {Number} adjWidth The box-adjusted width that was set
15468 * @param {Number} adjHeight The box-adjusted height that was set
15469 * @param {Number} rawWidth The width that was originally specified
15470 * @param {Number} rawHeight The height that was originally specified
15475 * Fires after the component is moved.
15476 * @param {Roo.Component} this
15477 * @param {Number} x The new x position
15478 * @param {Number} y The new y position
15484 Roo.extend(Roo.BoxComponent, Roo.Component, {
15485 // private, set in afterRender to signify that the component has been rendered
15487 // private, used to defer height settings to subclasses
15488 deferHeight: false,
15489 /** @cfg {Number} width
15490 * width (optional) size of component
15492 /** @cfg {Number} height
15493 * height (optional) size of component
15497 * Sets the width and height of the component. This method fires the resize event. This method can accept
15498 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15499 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15500 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15501 * @return {Roo.BoxComponent} this
15503 setSize : function(w, h){
15504 // support for standard size objects
15505 if(typeof w == 'object'){
15510 if(!this.boxReady){
15516 // prevent recalcs when not needed
15517 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15520 this.lastSize = {width: w, height: h};
15522 var adj = this.adjustSize(w, h);
15523 var aw = adj.width, ah = adj.height;
15524 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15525 var rz = this.getResizeEl();
15526 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15527 rz.setSize(aw, ah);
15528 }else if(!this.deferHeight && ah !== undefined){
15530 }else if(aw !== undefined){
15533 this.onResize(aw, ah, w, h);
15534 this.fireEvent('resize', this, aw, ah, w, h);
15540 * Gets the current size of the component's underlying element.
15541 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15543 getSize : function(){
15544 return this.el.getSize();
15548 * Gets the current XY position of the component's underlying element.
15549 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15550 * @return {Array} The XY position of the element (e.g., [100, 200])
15552 getPosition : function(local){
15553 if(local === true){
15554 return [this.el.getLeft(true), this.el.getTop(true)];
15556 return this.xy || this.el.getXY();
15560 * Gets the current box measurements of the component's underlying element.
15561 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15562 * @returns {Object} box An object in the format {x, y, width, height}
15564 getBox : function(local){
15565 var s = this.el.getSize();
15567 s.x = this.el.getLeft(true);
15568 s.y = this.el.getTop(true);
15570 var xy = this.xy || this.el.getXY();
15578 * Sets the current box measurements of the component's underlying element.
15579 * @param {Object} box An object in the format {x, y, width, height}
15580 * @returns {Roo.BoxComponent} this
15582 updateBox : function(box){
15583 this.setSize(box.width, box.height);
15584 this.setPagePosition(box.x, box.y);
15589 getResizeEl : function(){
15590 return this.resizeEl || this.el;
15594 getPositionEl : function(){
15595 return this.positionEl || this.el;
15599 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15600 * This method fires the move event.
15601 * @param {Number} left The new left
15602 * @param {Number} top The new top
15603 * @returns {Roo.BoxComponent} this
15605 setPosition : function(x, y){
15608 if(!this.boxReady){
15611 var adj = this.adjustPosition(x, y);
15612 var ax = adj.x, ay = adj.y;
15614 var el = this.getPositionEl();
15615 if(ax !== undefined || ay !== undefined){
15616 if(ax !== undefined && ay !== undefined){
15617 el.setLeftTop(ax, ay);
15618 }else if(ax !== undefined){
15620 }else if(ay !== undefined){
15623 this.onPosition(ax, ay);
15624 this.fireEvent('move', this, ax, ay);
15630 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15631 * This method fires the move event.
15632 * @param {Number} x The new x position
15633 * @param {Number} y The new y position
15634 * @returns {Roo.BoxComponent} this
15636 setPagePosition : function(x, y){
15639 if(!this.boxReady){
15642 if(x === undefined || y === undefined){ // cannot translate undefined points
15645 var p = this.el.translatePoints(x, y);
15646 this.setPosition(p.left, p.top);
15651 onRender : function(ct, position){
15652 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15654 this.resizeEl = Roo.get(this.resizeEl);
15656 if(this.positionEl){
15657 this.positionEl = Roo.get(this.positionEl);
15662 afterRender : function(){
15663 Roo.BoxComponent.superclass.afterRender.call(this);
15664 this.boxReady = true;
15665 this.setSize(this.width, this.height);
15666 if(this.x || this.y){
15667 this.setPosition(this.x, this.y);
15669 if(this.pageX || this.pageY){
15670 this.setPagePosition(this.pageX, this.pageY);
15675 * Force the component's size to recalculate based on the underlying element's current height and width.
15676 * @returns {Roo.BoxComponent} this
15678 syncSize : function(){
15679 delete this.lastSize;
15680 this.setSize(this.el.getWidth(), this.el.getHeight());
15685 * Called after the component is resized, this method is empty by default but can be implemented by any
15686 * subclass that needs to perform custom logic after a resize occurs.
15687 * @param {Number} adjWidth The box-adjusted width that was set
15688 * @param {Number} adjHeight The box-adjusted height that was set
15689 * @param {Number} rawWidth The width that was originally specified
15690 * @param {Number} rawHeight The height that was originally specified
15692 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15697 * Called after the component is moved, this method is empty by default but can be implemented by any
15698 * subclass that needs to perform custom logic after a move occurs.
15699 * @param {Number} x The new x position
15700 * @param {Number} y The new y position
15702 onPosition : function(x, y){
15707 adjustSize : function(w, h){
15708 if(this.autoWidth){
15711 if(this.autoHeight){
15714 return {width : w, height: h};
15718 adjustPosition : function(x, y){
15719 return {x : x, y: y};
15722 * Original code for Roojs - LGPL
15723 * <script type="text/javascript">
15727 * @class Roo.XComponent
15728 * A delayed Element creator...
15729 * Or a way to group chunks of interface together.
15731 * Mypart.xyx = new Roo.XComponent({
15733 parent : 'Mypart.xyz', // empty == document.element.!!
15737 disabled : function() {}
15739 tree : function() { // return an tree of xtype declared components
15743 xtype : 'NestedLayoutPanel',
15750 * It can be used to build a big heiracy, with parent etc.
15751 * or you can just use this to render a single compoent to a dom element
15752 * MYPART.render(Roo.Element | String(id) | dom_element )
15754 * @extends Roo.util.Observable
15756 * @param cfg {Object} configuration of component
15759 Roo.XComponent = function(cfg) {
15760 Roo.apply(this, cfg);
15764 * Fires when this the componnt is built
15765 * @param {Roo.XComponent} c the component
15770 this.region = this.region || 'center'; // default..
15771 Roo.XComponent.register(this);
15772 this.modules = false;
15773 this.el = false; // where the layout goes..
15777 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15780 * The created element (with Roo.factory())
15781 * @type {Roo.Layout}
15787 * for BC - use el in new code
15788 * @type {Roo.Layout}
15794 * for BC - use el in new code
15795 * @type {Roo.Layout}
15800 * @cfg {Function|boolean} disabled
15801 * If this module is disabled by some rule, return true from the funtion
15806 * @cfg {String} parent
15807 * Name of parent element which it get xtype added to..
15812 * @cfg {String} order
15813 * Used to set the order in which elements are created (usefull for multiple tabs)
15818 * @cfg {String} name
15819 * String to display while loading.
15823 * @cfg {String} region
15824 * Region to render component to (defaults to center)
15829 * @cfg {Array} items
15830 * A single item array - the first element is the root of the tree..
15831 * It's done this way to stay compatible with the Xtype system...
15837 * The method that retuns the tree of parts that make up this compoennt
15844 * render element to dom or tree
15845 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15848 render : function(el)
15852 var hp = this.parent ? 1 : 0;
15854 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15855 // if parent is a '#.....' string, then let's use that..
15856 var ename = this.parent.substr(1)
15857 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
15858 el = Roo.get(ename);
15859 if (!el && !this.parent) {
15860 Roo.log("Warning - element can not be found :#" + ename );
15866 if (!this.parent) {
15868 el = el ? Roo.get(el) : false;
15870 // it's a top level one..
15872 el : new Roo.BorderLayout(el || document.body, {
15878 tabPosition: 'top',
15879 //resizeTabs: true,
15880 alwaysShowTabs: el && hp? false : true,
15881 hideTabs: el || !hp ? true : false,
15888 if (!this.parent.el) {
15889 // probably an old style ctor, which has been disabled.
15893 // The 'tree' method is '_tree now'
15895 var tree = this._tree ? this._tree() : this.tree();
15896 tree.region = tree.region || this.region;
15897 this.el = this.parent.el.addxtype(tree);
15898 this.fireEvent('built', this);
15900 this.panel = this.el;
15901 this.layout = this.panel.layout;
15902 this.parentLayout = this.parent.layout || false;
15908 Roo.apply(Roo.XComponent, {
15910 * @property hideProgress
15911 * true to disable the building progress bar.. usefull on single page renders.
15914 hideProgress : false,
15916 * @property buildCompleted
15917 * True when the builder has completed building the interface.
15920 buildCompleted : false,
15923 * @property topModule
15924 * the upper most module - uses document.element as it's constructor.
15931 * @property modules
15932 * array of modules to be created by registration system.
15933 * @type {Array} of Roo.XComponent
15938 * @property elmodules
15939 * array of modules to be created by which use #ID
15940 * @type {Array} of Roo.XComponent
15947 * Register components to be built later.
15949 * This solves the following issues
15950 * - Building is not done on page load, but after an authentication process has occured.
15951 * - Interface elements are registered on page load
15952 * - Parent Interface elements may not be loaded before child, so this handles that..
15959 module : 'Pman.Tab.projectMgr',
15961 parent : 'Pman.layout',
15962 disabled : false, // or use a function..
15965 * * @param {Object} details about module
15967 register : function(obj) {
15969 Roo.XComponent.event.fireEvent('register', obj);
15970 switch(typeof(obj.disabled) ) {
15976 if ( obj.disabled() ) {
15982 if (obj.disabled) {
15988 this.modules.push(obj);
15992 * convert a string to an object..
15993 * eg. 'AAA.BBB' -> finds AAA.BBB
15997 toObject : function(str)
15999 if (!str || typeof(str) == 'object') {
16002 if (str.substring(0,1) == '#') {
16006 var ar = str.split('.');
16011 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16013 throw "Module not found : " + str;
16017 throw "Module not found : " + str;
16019 Roo.each(ar, function(e) {
16020 if (typeof(o[e]) == 'undefined') {
16021 throw "Module not found : " + str;
16032 * move modules into their correct place in the tree..
16035 preBuild : function ()
16038 Roo.each(this.modules , function (obj)
16040 Roo.XComponent.event.fireEvent('beforebuild', obj);
16042 var opar = obj.parent;
16044 obj.parent = this.toObject(opar);
16046 Roo.log("parent:toObject failed: " + e.toString());
16051 Roo.debug && Roo.log("GOT top level module");
16052 Roo.debug && Roo.log(obj);
16053 obj.modules = new Roo.util.MixedCollection(false,
16054 function(o) { return o.order + '' }
16056 this.topModule = obj;
16059 // parent is a string (usually a dom element name..)
16060 if (typeof(obj.parent) == 'string') {
16061 this.elmodules.push(obj);
16064 if (obj.parent.constructor != Roo.XComponent) {
16065 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16067 if (!obj.parent.modules) {
16068 obj.parent.modules = new Roo.util.MixedCollection(false,
16069 function(o) { return o.order + '' }
16072 if (obj.parent.disabled) {
16073 obj.disabled = true;
16075 obj.parent.modules.add(obj);
16080 * make a list of modules to build.
16081 * @return {Array} list of modules.
16084 buildOrder : function()
16087 var cmp = function(a,b) {
16088 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16090 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16091 throw "No top level modules to build";
16094 // make a flat list in order of modules to build.
16095 var mods = this.topModule ? [ this.topModule ] : [];
16098 // elmodules (is a list of DOM based modules )
16099 Roo.each(this.elmodules, function(e) {
16101 if (!this.topModule &&
16102 typeof(e.parent) == 'string' &&
16103 e.parent.substring(0,1) == '#' &&
16104 Roo.get(e.parent.substr(1))
16107 _this.topModule = e;
16113 // add modules to their parents..
16114 var addMod = function(m) {
16115 Roo.debug && Roo.log("build Order: add: " + m.name);
16118 if (m.modules && !m.disabled) {
16119 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16120 m.modules.keySort('ASC', cmp );
16121 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16123 m.modules.each(addMod);
16125 Roo.debug && Roo.log("build Order: no child modules");
16127 // not sure if this is used any more..
16129 m.finalize.name = m.name + " (clean up) ";
16130 mods.push(m.finalize);
16134 if (this.topModule && this.topModule.modules) {
16135 this.topModule.modules.keySort('ASC', cmp );
16136 this.topModule.modules.each(addMod);
16142 * Build the registered modules.
16143 * @param {Object} parent element.
16144 * @param {Function} optional method to call after module has been added.
16152 var mods = this.buildOrder();
16154 //this.allmods = mods;
16155 //Roo.debug && Roo.log(mods);
16157 if (!mods.length) { // should not happen
16158 throw "NO modules!!!";
16162 var msg = "Building Interface...";
16163 // flash it up as modal - so we store the mask!?
16164 if (!this.hideProgress) {
16165 Roo.MessageBox.show({ title: 'loading' });
16166 Roo.MessageBox.show({
16167 title: "Please wait...",
16176 var total = mods.length;
16179 var progressRun = function() {
16180 if (!mods.length) {
16181 Roo.debug && Roo.log('hide?');
16182 if (!this.hideProgress) {
16183 Roo.MessageBox.hide();
16185 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16191 var m = mods.shift();
16194 Roo.debug && Roo.log(m);
16195 // not sure if this is supported any more.. - modules that are are just function
16196 if (typeof(m) == 'function') {
16198 return progressRun.defer(10, _this);
16202 msg = "Building Interface " + (total - mods.length) +
16204 (m.name ? (' - ' + m.name) : '');
16205 Roo.debug && Roo.log(msg);
16206 if (!this.hideProgress) {
16207 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16211 // is the module disabled?
16212 var disabled = (typeof(m.disabled) == 'function') ?
16213 m.disabled.call(m.module.disabled) : m.disabled;
16217 return progressRun(); // we do not update the display!
16225 // it's 10 on top level, and 1 on others??? why...
16226 return progressRun.defer(10, _this);
16229 progressRun.defer(1, _this);
16243 * wrapper for event.on - aliased later..
16244 * Typically use to register a event handler for register:
16246 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16255 Roo.XComponent.event = new Roo.util.Observable({
16259 * Fires when an Component is registered,
16260 * set the disable property on the Component to stop registration.
16261 * @param {Roo.XComponent} c the component being registerd.
16266 * @event beforebuild
16267 * Fires before each Component is built
16268 * can be used to apply permissions.
16269 * @param {Roo.XComponent} c the component being registerd.
16272 'beforebuild' : true,
16274 * @event buildcomplete
16275 * Fires on the top level element when all elements have been built
16276 * @param {Roo.XComponent} the top level component.
16278 'buildcomplete' : true
16283 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16286 * Ext JS Library 1.1.1
16287 * Copyright(c) 2006-2007, Ext JS, LLC.
16289 * Originally Released Under LGPL - original licence link has changed is not relivant.
16292 * <script type="text/javascript">
16298 * These classes are derivatives of the similarly named classes in the YUI Library.
16299 * The original license:
16300 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16301 * Code licensed under the BSD License:
16302 * http://developer.yahoo.net/yui/license.txt
16307 var Event=Roo.EventManager;
16308 var Dom=Roo.lib.Dom;
16311 * @class Roo.dd.DragDrop
16312 * @extends Roo.util.Observable
16313 * Defines the interface and base operation of items that that can be
16314 * dragged or can be drop targets. It was designed to be extended, overriding
16315 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16316 * Up to three html elements can be associated with a DragDrop instance:
16318 * <li>linked element: the element that is passed into the constructor.
16319 * This is the element which defines the boundaries for interaction with
16320 * other DragDrop objects.</li>
16321 * <li>handle element(s): The drag operation only occurs if the element that
16322 * was clicked matches a handle element. By default this is the linked
16323 * element, but there are times that you will want only a portion of the
16324 * linked element to initiate the drag operation, and the setHandleElId()
16325 * method provides a way to define this.</li>
16326 * <li>drag element: this represents the element that would be moved along
16327 * with the cursor during a drag operation. By default, this is the linked
16328 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16329 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16332 * This class should not be instantiated until the onload event to ensure that
16333 * the associated elements are available.
16334 * The following would define a DragDrop obj that would interact with any
16335 * other DragDrop obj in the "group1" group:
16337 * dd = new Roo.dd.DragDrop("div1", "group1");
16339 * Since none of the event handlers have been implemented, nothing would
16340 * actually happen if you were to run the code above. Normally you would
16341 * override this class or one of the default implementations, but you can
16342 * also override the methods you want on an instance of the class...
16344 * dd.onDragDrop = function(e, id) {
16345 * alert("dd was dropped on " + id);
16349 * @param {String} id of the element that is linked to this instance
16350 * @param {String} sGroup the group of related DragDrop objects
16351 * @param {object} config an object containing configurable attributes
16352 * Valid properties for DragDrop:
16353 * padding, isTarget, maintainOffset, primaryButtonOnly
16355 Roo.dd.DragDrop = function(id, sGroup, config) {
16357 this.init(id, sGroup, config);
16362 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16365 * The id of the element associated with this object. This is what we
16366 * refer to as the "linked element" because the size and position of
16367 * this element is used to determine when the drag and drop objects have
16375 * Configuration attributes passed into the constructor
16382 * The id of the element that will be dragged. By default this is same
16383 * as the linked element , but could be changed to another element. Ex:
16385 * @property dragElId
16392 * the id of the element that initiates the drag operation. By default
16393 * this is the linked element, but could be changed to be a child of this
16394 * element. This lets us do things like only starting the drag when the
16395 * header element within the linked html element is clicked.
16396 * @property handleElId
16403 * An associative array of HTML tags that will be ignored if clicked.
16404 * @property invalidHandleTypes
16405 * @type {string: string}
16407 invalidHandleTypes: null,
16410 * An associative array of ids for elements that will be ignored if clicked
16411 * @property invalidHandleIds
16412 * @type {string: string}
16414 invalidHandleIds: null,
16417 * An indexted array of css class names for elements that will be ignored
16419 * @property invalidHandleClasses
16422 invalidHandleClasses: null,
16425 * The linked element's absolute X position at the time the drag was
16427 * @property startPageX
16434 * The linked element's absolute X position at the time the drag was
16436 * @property startPageY
16443 * The group defines a logical collection of DragDrop objects that are
16444 * related. Instances only get events when interacting with other
16445 * DragDrop object in the same group. This lets us define multiple
16446 * groups using a single DragDrop subclass if we want.
16448 * @type {string: string}
16453 * Individual drag/drop instances can be locked. This will prevent
16454 * onmousedown start drag.
16462 * Lock this instance
16465 lock: function() { this.locked = true; },
16468 * Unlock this instace
16471 unlock: function() { this.locked = false; },
16474 * By default, all insances can be a drop target. This can be disabled by
16475 * setting isTarget to false.
16482 * The padding configured for this drag and drop object for calculating
16483 * the drop zone intersection with this object.
16490 * Cached reference to the linked element
16491 * @property _domRef
16497 * Internal typeof flag
16498 * @property __ygDragDrop
16501 __ygDragDrop: true,
16504 * Set to true when horizontal contraints are applied
16505 * @property constrainX
16512 * Set to true when vertical contraints are applied
16513 * @property constrainY
16520 * The left constraint
16528 * The right constraint
16536 * The up constraint
16545 * The down constraint
16553 * Maintain offsets when we resetconstraints. Set to true when you want
16554 * the position of the element relative to its parent to stay the same
16555 * when the page changes
16557 * @property maintainOffset
16560 maintainOffset: false,
16563 * Array of pixel locations the element will snap to if we specified a
16564 * horizontal graduation/interval. This array is generated automatically
16565 * when you define a tick interval.
16572 * Array of pixel locations the element will snap to if we specified a
16573 * vertical graduation/interval. This array is generated automatically
16574 * when you define a tick interval.
16581 * By default the drag and drop instance will only respond to the primary
16582 * button click (left button for a right-handed mouse). Set to true to
16583 * allow drag and drop to start with any mouse click that is propogated
16585 * @property primaryButtonOnly
16588 primaryButtonOnly: true,
16591 * The availabe property is false until the linked dom element is accessible.
16592 * @property available
16598 * By default, drags can only be initiated if the mousedown occurs in the
16599 * region the linked element is. This is done in part to work around a
16600 * bug in some browsers that mis-report the mousedown if the previous
16601 * mouseup happened outside of the window. This property is set to true
16602 * if outer handles are defined.
16604 * @property hasOuterHandles
16608 hasOuterHandles: false,
16611 * Code that executes immediately before the startDrag event
16612 * @method b4StartDrag
16615 b4StartDrag: function(x, y) { },
16618 * Abstract method called after a drag/drop object is clicked
16619 * and the drag or mousedown time thresholds have beeen met.
16620 * @method startDrag
16621 * @param {int} X click location
16622 * @param {int} Y click location
16624 startDrag: function(x, y) { /* override this */ },
16627 * Code that executes immediately before the onDrag event
16631 b4Drag: function(e) { },
16634 * Abstract method called during the onMouseMove event while dragging an
16637 * @param {Event} e the mousemove event
16639 onDrag: function(e) { /* override this */ },
16642 * Abstract method called when this element fist begins hovering over
16643 * another DragDrop obj
16644 * @method onDragEnter
16645 * @param {Event} e the mousemove event
16646 * @param {String|DragDrop[]} id In POINT mode, the element
16647 * id this is hovering over. In INTERSECT mode, an array of one or more
16648 * dragdrop items being hovered over.
16650 onDragEnter: function(e, id) { /* override this */ },
16653 * Code that executes immediately before the onDragOver event
16654 * @method b4DragOver
16657 b4DragOver: function(e) { },
16660 * Abstract method called when this element is hovering over another
16662 * @method onDragOver
16663 * @param {Event} e the mousemove event
16664 * @param {String|DragDrop[]} id In POINT mode, the element
16665 * id this is hovering over. In INTERSECT mode, an array of dd items
16666 * being hovered over.
16668 onDragOver: function(e, id) { /* override this */ },
16671 * Code that executes immediately before the onDragOut event
16672 * @method b4DragOut
16675 b4DragOut: function(e) { },
16678 * Abstract method called when we are no longer hovering over an element
16679 * @method onDragOut
16680 * @param {Event} e the mousemove event
16681 * @param {String|DragDrop[]} id In POINT mode, the element
16682 * id this was hovering over. In INTERSECT mode, an array of dd items
16683 * that the mouse is no longer over.
16685 onDragOut: function(e, id) { /* override this */ },
16688 * Code that executes immediately before the onDragDrop event
16689 * @method b4DragDrop
16692 b4DragDrop: function(e) { },
16695 * Abstract method called when this item is dropped on another DragDrop
16697 * @method onDragDrop
16698 * @param {Event} e the mouseup event
16699 * @param {String|DragDrop[]} id In POINT mode, the element
16700 * id this was dropped on. In INTERSECT mode, an array of dd items this
16703 onDragDrop: function(e, id) { /* override this */ },
16706 * Abstract method called when this item is dropped on an area with no
16708 * @method onInvalidDrop
16709 * @param {Event} e the mouseup event
16711 onInvalidDrop: function(e) { /* override this */ },
16714 * Code that executes immediately before the endDrag event
16715 * @method b4EndDrag
16718 b4EndDrag: function(e) { },
16721 * Fired when we are done dragging the object
16723 * @param {Event} e the mouseup event
16725 endDrag: function(e) { /* override this */ },
16728 * Code executed immediately before the onMouseDown event
16729 * @method b4MouseDown
16730 * @param {Event} e the mousedown event
16733 b4MouseDown: function(e) { },
16736 * Event handler that fires when a drag/drop obj gets a mousedown
16737 * @method onMouseDown
16738 * @param {Event} e the mousedown event
16740 onMouseDown: function(e) { /* override this */ },
16743 * Event handler that fires when a drag/drop obj gets a mouseup
16744 * @method onMouseUp
16745 * @param {Event} e the mouseup event
16747 onMouseUp: function(e) { /* override this */ },
16750 * Override the onAvailable method to do what is needed after the initial
16751 * position was determined.
16752 * @method onAvailable
16754 onAvailable: function () {
16758 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16761 defaultPadding : {left:0, right:0, top:0, bottom:0},
16764 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16768 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16769 { dragElId: "existingProxyDiv" });
16770 dd.startDrag = function(){
16771 this.constrainTo("parent-id");
16774 * Or you can initalize it using the {@link Roo.Element} object:
16776 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16777 startDrag : function(){
16778 this.constrainTo("parent-id");
16782 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16783 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16784 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16785 * an object containing the sides to pad. For example: {right:10, bottom:10}
16786 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16788 constrainTo : function(constrainTo, pad, inContent){
16789 if(typeof pad == "number"){
16790 pad = {left: pad, right:pad, top:pad, bottom:pad};
16792 pad = pad || this.defaultPadding;
16793 var b = Roo.get(this.getEl()).getBox();
16794 var ce = Roo.get(constrainTo);
16795 var s = ce.getScroll();
16796 var c, cd = ce.dom;
16797 if(cd == document.body){
16798 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16801 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16805 var topSpace = b.y - c.y;
16806 var leftSpace = b.x - c.x;
16808 this.resetConstraints();
16809 this.setXConstraint(leftSpace - (pad.left||0), // left
16810 c.width - leftSpace - b.width - (pad.right||0) //right
16812 this.setYConstraint(topSpace - (pad.top||0), //top
16813 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16818 * Returns a reference to the linked element
16820 * @return {HTMLElement} the html element
16822 getEl: function() {
16823 if (!this._domRef) {
16824 this._domRef = Roo.getDom(this.id);
16827 return this._domRef;
16831 * Returns a reference to the actual element to drag. By default this is
16832 * the same as the html element, but it can be assigned to another
16833 * element. An example of this can be found in Roo.dd.DDProxy
16834 * @method getDragEl
16835 * @return {HTMLElement} the html element
16837 getDragEl: function() {
16838 return Roo.getDom(this.dragElId);
16842 * Sets up the DragDrop object. Must be called in the constructor of any
16843 * Roo.dd.DragDrop subclass
16845 * @param id the id of the linked element
16846 * @param {String} sGroup the group of related items
16847 * @param {object} config configuration attributes
16849 init: function(id, sGroup, config) {
16850 this.initTarget(id, sGroup, config);
16851 if (!Roo.isTouch) {
16852 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16854 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16855 // Event.on(this.id, "selectstart", Event.preventDefault);
16859 * Initializes Targeting functionality only... the object does not
16860 * get a mousedown handler.
16861 * @method initTarget
16862 * @param id the id of the linked element
16863 * @param {String} sGroup the group of related items
16864 * @param {object} config configuration attributes
16866 initTarget: function(id, sGroup, config) {
16868 // configuration attributes
16869 this.config = config || {};
16871 // create a local reference to the drag and drop manager
16872 this.DDM = Roo.dd.DDM;
16873 // initialize the groups array
16876 // assume that we have an element reference instead of an id if the
16877 // parameter is not a string
16878 if (typeof id !== "string") {
16885 // add to an interaction group
16886 this.addToGroup((sGroup) ? sGroup : "default");
16888 // We don't want to register this as the handle with the manager
16889 // so we just set the id rather than calling the setter.
16890 this.handleElId = id;
16892 // the linked element is the element that gets dragged by default
16893 this.setDragElId(id);
16895 // by default, clicked anchors will not start drag operations.
16896 this.invalidHandleTypes = { A: "A" };
16897 this.invalidHandleIds = {};
16898 this.invalidHandleClasses = [];
16900 this.applyConfig();
16902 this.handleOnAvailable();
16906 * Applies the configuration parameters that were passed into the constructor.
16907 * This is supposed to happen at each level through the inheritance chain. So
16908 * a DDProxy implentation will execute apply config on DDProxy, DD, and
16909 * DragDrop in order to get all of the parameters that are available in
16911 * @method applyConfig
16913 applyConfig: function() {
16915 // configurable properties:
16916 // padding, isTarget, maintainOffset, primaryButtonOnly
16917 this.padding = this.config.padding || [0, 0, 0, 0];
16918 this.isTarget = (this.config.isTarget !== false);
16919 this.maintainOffset = (this.config.maintainOffset);
16920 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
16925 * Executed when the linked element is available
16926 * @method handleOnAvailable
16929 handleOnAvailable: function() {
16930 this.available = true;
16931 this.resetConstraints();
16932 this.onAvailable();
16936 * Configures the padding for the target zone in px. Effectively expands
16937 * (or reduces) the virtual object size for targeting calculations.
16938 * Supports css-style shorthand; if only one parameter is passed, all sides
16939 * will have that padding, and if only two are passed, the top and bottom
16940 * will have the first param, the left and right the second.
16941 * @method setPadding
16942 * @param {int} iTop Top pad
16943 * @param {int} iRight Right pad
16944 * @param {int} iBot Bot pad
16945 * @param {int} iLeft Left pad
16947 setPadding: function(iTop, iRight, iBot, iLeft) {
16948 // this.padding = [iLeft, iRight, iTop, iBot];
16949 if (!iRight && 0 !== iRight) {
16950 this.padding = [iTop, iTop, iTop, iTop];
16951 } else if (!iBot && 0 !== iBot) {
16952 this.padding = [iTop, iRight, iTop, iRight];
16954 this.padding = [iTop, iRight, iBot, iLeft];
16959 * Stores the initial placement of the linked element.
16960 * @method setInitialPosition
16961 * @param {int} diffX the X offset, default 0
16962 * @param {int} diffY the Y offset, default 0
16964 setInitPosition: function(diffX, diffY) {
16965 var el = this.getEl();
16967 if (!this.DDM.verifyEl(el)) {
16971 var dx = diffX || 0;
16972 var dy = diffY || 0;
16974 var p = Dom.getXY( el );
16976 this.initPageX = p[0] - dx;
16977 this.initPageY = p[1] - dy;
16979 this.lastPageX = p[0];
16980 this.lastPageY = p[1];
16983 this.setStartPosition(p);
16987 * Sets the start position of the element. This is set when the obj
16988 * is initialized, the reset when a drag is started.
16989 * @method setStartPosition
16990 * @param pos current position (from previous lookup)
16993 setStartPosition: function(pos) {
16994 var p = pos || Dom.getXY( this.getEl() );
16995 this.deltaSetXY = null;
16997 this.startPageX = p[0];
16998 this.startPageY = p[1];
17002 * Add this instance to a group of related drag/drop objects. All
17003 * instances belong to at least one group, and can belong to as many
17004 * groups as needed.
17005 * @method addToGroup
17006 * @param sGroup {string} the name of the group
17008 addToGroup: function(sGroup) {
17009 this.groups[sGroup] = true;
17010 this.DDM.regDragDrop(this, sGroup);
17014 * Remove's this instance from the supplied interaction group
17015 * @method removeFromGroup
17016 * @param {string} sGroup The group to drop
17018 removeFromGroup: function(sGroup) {
17019 if (this.groups[sGroup]) {
17020 delete this.groups[sGroup];
17023 this.DDM.removeDDFromGroup(this, sGroup);
17027 * Allows you to specify that an element other than the linked element
17028 * will be moved with the cursor during a drag
17029 * @method setDragElId
17030 * @param id {string} the id of the element that will be used to initiate the drag
17032 setDragElId: function(id) {
17033 this.dragElId = id;
17037 * Allows you to specify a child of the linked element that should be
17038 * used to initiate the drag operation. An example of this would be if
17039 * you have a content div with text and links. Clicking anywhere in the
17040 * content area would normally start the drag operation. Use this method
17041 * to specify that an element inside of the content div is the element
17042 * that starts the drag operation.
17043 * @method setHandleElId
17044 * @param id {string} the id of the element that will be used to
17045 * initiate the drag.
17047 setHandleElId: function(id) {
17048 if (typeof id !== "string") {
17051 this.handleElId = id;
17052 this.DDM.regHandle(this.id, id);
17056 * Allows you to set an element outside of the linked element as a drag
17058 * @method setOuterHandleElId
17059 * @param id the id of the element that will be used to initiate the drag
17061 setOuterHandleElId: function(id) {
17062 if (typeof id !== "string") {
17065 Event.on(id, "mousedown",
17066 this.handleMouseDown, this);
17067 this.setHandleElId(id);
17069 this.hasOuterHandles = true;
17073 * Remove all drag and drop hooks for this element
17076 unreg: function() {
17077 Event.un(this.id, "mousedown",
17078 this.handleMouseDown);
17079 Event.un(this.id, "touchstart",
17080 this.handleMouseDown);
17081 this._domRef = null;
17082 this.DDM._remove(this);
17085 destroy : function(){
17090 * Returns true if this instance is locked, or the drag drop mgr is locked
17091 * (meaning that all drag/drop is disabled on the page.)
17093 * @return {boolean} true if this obj or all drag/drop is locked, else
17096 isLocked: function() {
17097 return (this.DDM.isLocked() || this.locked);
17101 * Fired when this object is clicked
17102 * @method handleMouseDown
17104 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17107 handleMouseDown: function(e, oDD){
17109 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17110 //Roo.log('not touch/ button !=0');
17113 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17114 return; // double touch..
17118 if (this.isLocked()) {
17119 //Roo.log('locked');
17123 this.DDM.refreshCache(this.groups);
17124 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17125 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17126 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17127 //Roo.log('no outer handes or not over target');
17130 // Roo.log('check validator');
17131 if (this.clickValidator(e)) {
17132 // Roo.log('validate success');
17133 // set the initial element position
17134 this.setStartPosition();
17137 this.b4MouseDown(e);
17138 this.onMouseDown(e);
17140 this.DDM.handleMouseDown(e, this);
17142 this.DDM.stopEvent(e);
17150 clickValidator: function(e) {
17151 var target = e.getTarget();
17152 return ( this.isValidHandleChild(target) &&
17153 (this.id == this.handleElId ||
17154 this.DDM.handleWasClicked(target, this.id)) );
17158 * Allows you to specify a tag name that should not start a drag operation
17159 * when clicked. This is designed to facilitate embedding links within a
17160 * drag handle that do something other than start the drag.
17161 * @method addInvalidHandleType
17162 * @param {string} tagName the type of element to exclude
17164 addInvalidHandleType: function(tagName) {
17165 var type = tagName.toUpperCase();
17166 this.invalidHandleTypes[type] = type;
17170 * Lets you to specify an element id for a child of a drag handle
17171 * that should not initiate a drag
17172 * @method addInvalidHandleId
17173 * @param {string} id the element id of the element you wish to ignore
17175 addInvalidHandleId: function(id) {
17176 if (typeof id !== "string") {
17179 this.invalidHandleIds[id] = id;
17183 * Lets you specify a css class of elements that will not initiate a drag
17184 * @method addInvalidHandleClass
17185 * @param {string} cssClass the class of the elements you wish to ignore
17187 addInvalidHandleClass: function(cssClass) {
17188 this.invalidHandleClasses.push(cssClass);
17192 * Unsets an excluded tag name set by addInvalidHandleType
17193 * @method removeInvalidHandleType
17194 * @param {string} tagName the type of element to unexclude
17196 removeInvalidHandleType: function(tagName) {
17197 var type = tagName.toUpperCase();
17198 // this.invalidHandleTypes[type] = null;
17199 delete this.invalidHandleTypes[type];
17203 * Unsets an invalid handle id
17204 * @method removeInvalidHandleId
17205 * @param {string} id the id of the element to re-enable
17207 removeInvalidHandleId: function(id) {
17208 if (typeof id !== "string") {
17211 delete this.invalidHandleIds[id];
17215 * Unsets an invalid css class
17216 * @method removeInvalidHandleClass
17217 * @param {string} cssClass the class of the element(s) you wish to
17220 removeInvalidHandleClass: function(cssClass) {
17221 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17222 if (this.invalidHandleClasses[i] == cssClass) {
17223 delete this.invalidHandleClasses[i];
17229 * Checks the tag exclusion list to see if this click should be ignored
17230 * @method isValidHandleChild
17231 * @param {HTMLElement} node the HTMLElement to evaluate
17232 * @return {boolean} true if this is a valid tag type, false if not
17234 isValidHandleChild: function(node) {
17237 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17240 nodeName = node.nodeName.toUpperCase();
17242 nodeName = node.nodeName;
17244 valid = valid && !this.invalidHandleTypes[nodeName];
17245 valid = valid && !this.invalidHandleIds[node.id];
17247 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17248 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17257 * Create the array of horizontal tick marks if an interval was specified
17258 * in setXConstraint().
17259 * @method setXTicks
17262 setXTicks: function(iStartX, iTickSize) {
17264 this.xTickSize = iTickSize;
17268 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17270 this.xTicks[this.xTicks.length] = i;
17275 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17277 this.xTicks[this.xTicks.length] = i;
17282 this.xTicks.sort(this.DDM.numericSort) ;
17286 * Create the array of vertical tick marks if an interval was specified in
17287 * setYConstraint().
17288 * @method setYTicks
17291 setYTicks: function(iStartY, iTickSize) {
17293 this.yTickSize = iTickSize;
17297 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17299 this.yTicks[this.yTicks.length] = i;
17304 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17306 this.yTicks[this.yTicks.length] = i;
17311 this.yTicks.sort(this.DDM.numericSort) ;
17315 * By default, the element can be dragged any place on the screen. Use
17316 * this method to limit the horizontal travel of the element. Pass in
17317 * 0,0 for the parameters if you want to lock the drag to the y axis.
17318 * @method setXConstraint
17319 * @param {int} iLeft the number of pixels the element can move to the left
17320 * @param {int} iRight the number of pixels the element can move to the
17322 * @param {int} iTickSize optional parameter for specifying that the
17324 * should move iTickSize pixels at a time.
17326 setXConstraint: function(iLeft, iRight, iTickSize) {
17327 this.leftConstraint = iLeft;
17328 this.rightConstraint = iRight;
17330 this.minX = this.initPageX - iLeft;
17331 this.maxX = this.initPageX + iRight;
17332 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17334 this.constrainX = true;
17338 * Clears any constraints applied to this instance. Also clears ticks
17339 * since they can't exist independent of a constraint at this time.
17340 * @method clearConstraints
17342 clearConstraints: function() {
17343 this.constrainX = false;
17344 this.constrainY = false;
17349 * Clears any tick interval defined for this instance
17350 * @method clearTicks
17352 clearTicks: function() {
17353 this.xTicks = null;
17354 this.yTicks = null;
17355 this.xTickSize = 0;
17356 this.yTickSize = 0;
17360 * By default, the element can be dragged any place on the screen. Set
17361 * this to limit the vertical travel of the element. Pass in 0,0 for the
17362 * parameters if you want to lock the drag to the x axis.
17363 * @method setYConstraint
17364 * @param {int} iUp the number of pixels the element can move up
17365 * @param {int} iDown the number of pixels the element can move down
17366 * @param {int} iTickSize optional parameter for specifying that the
17367 * element should move iTickSize pixels at a time.
17369 setYConstraint: function(iUp, iDown, iTickSize) {
17370 this.topConstraint = iUp;
17371 this.bottomConstraint = iDown;
17373 this.minY = this.initPageY - iUp;
17374 this.maxY = this.initPageY + iDown;
17375 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17377 this.constrainY = true;
17382 * resetConstraints must be called if you manually reposition a dd element.
17383 * @method resetConstraints
17384 * @param {boolean} maintainOffset
17386 resetConstraints: function() {
17389 // Maintain offsets if necessary
17390 if (this.initPageX || this.initPageX === 0) {
17391 // figure out how much this thing has moved
17392 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17393 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17395 this.setInitPosition(dx, dy);
17397 // This is the first time we have detected the element's position
17399 this.setInitPosition();
17402 if (this.constrainX) {
17403 this.setXConstraint( this.leftConstraint,
17404 this.rightConstraint,
17408 if (this.constrainY) {
17409 this.setYConstraint( this.topConstraint,
17410 this.bottomConstraint,
17416 * Normally the drag element is moved pixel by pixel, but we can specify
17417 * that it move a number of pixels at a time. This method resolves the
17418 * location when we have it set up like this.
17420 * @param {int} val where we want to place the object
17421 * @param {int[]} tickArray sorted array of valid points
17422 * @return {int} the closest tick
17425 getTick: function(val, tickArray) {
17428 // If tick interval is not defined, it is effectively 1 pixel,
17429 // so we return the value passed to us.
17431 } else if (tickArray[0] >= val) {
17432 // The value is lower than the first tick, so we return the first
17434 return tickArray[0];
17436 for (var i=0, len=tickArray.length; i<len; ++i) {
17438 if (tickArray[next] && tickArray[next] >= val) {
17439 var diff1 = val - tickArray[i];
17440 var diff2 = tickArray[next] - val;
17441 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17445 // The value is larger than the last tick, so we return the last
17447 return tickArray[tickArray.length - 1];
17454 * @return {string} string representation of the dd obj
17456 toString: function() {
17457 return ("DragDrop " + this.id);
17465 * Ext JS Library 1.1.1
17466 * Copyright(c) 2006-2007, Ext JS, LLC.
17468 * Originally Released Under LGPL - original licence link has changed is not relivant.
17471 * <script type="text/javascript">
17476 * The drag and drop utility provides a framework for building drag and drop
17477 * applications. In addition to enabling drag and drop for specific elements,
17478 * the drag and drop elements are tracked by the manager class, and the
17479 * interactions between the various elements are tracked during the drag and
17480 * the implementing code is notified about these important moments.
17483 // Only load the library once. Rewriting the manager class would orphan
17484 // existing drag and drop instances.
17485 if (!Roo.dd.DragDropMgr) {
17488 * @class Roo.dd.DragDropMgr
17489 * DragDropMgr is a singleton that tracks the element interaction for
17490 * all DragDrop items in the window. Generally, you will not call
17491 * this class directly, but it does have helper methods that could
17492 * be useful in your DragDrop implementations.
17495 Roo.dd.DragDropMgr = function() {
17497 var Event = Roo.EventManager;
17502 * Two dimensional Array of registered DragDrop objects. The first
17503 * dimension is the DragDrop item group, the second the DragDrop
17506 * @type {string: string}
17513 * Array of element ids defined as drag handles. Used to determine
17514 * if the element that generated the mousedown event is actually the
17515 * handle and not the html element itself.
17516 * @property handleIds
17517 * @type {string: string}
17524 * the DragDrop object that is currently being dragged
17525 * @property dragCurrent
17533 * the DragDrop object(s) that are being hovered over
17534 * @property dragOvers
17542 * the X distance between the cursor and the object being dragged
17551 * the Y distance between the cursor and the object being dragged
17560 * Flag to determine if we should prevent the default behavior of the
17561 * events we define. By default this is true, but this can be set to
17562 * false if you need the default behavior (not recommended)
17563 * @property preventDefault
17567 preventDefault: true,
17570 * Flag to determine if we should stop the propagation of the events
17571 * we generate. This is true by default but you may want to set it to
17572 * false if the html element contains other features that require the
17574 * @property stopPropagation
17578 stopPropagation: true,
17581 * Internal flag that is set to true when drag and drop has been
17583 * @property initialized
17590 * All drag and drop can be disabled.
17598 * Called the first time an element is registered.
17604 this.initialized = true;
17608 * In point mode, drag and drop interaction is defined by the
17609 * location of the cursor during the drag/drop
17617 * In intersect mode, drag and drop interactio nis defined by the
17618 * overlap of two or more drag and drop objects.
17619 * @property INTERSECT
17626 * The current drag and drop mode. Default: POINT
17634 * Runs method on all drag and drop objects
17635 * @method _execOnAll
17639 _execOnAll: function(sMethod, args) {
17640 for (var i in this.ids) {
17641 for (var j in this.ids[i]) {
17642 var oDD = this.ids[i][j];
17643 if (! this.isTypeOfDD(oDD)) {
17646 oDD[sMethod].apply(oDD, args);
17652 * Drag and drop initialization. Sets up the global event handlers
17657 _onLoad: function() {
17661 if (!Roo.isTouch) {
17662 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17663 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17665 Event.on(document, "touchend", this.handleMouseUp, this, true);
17666 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17668 Event.on(window, "unload", this._onUnload, this, true);
17669 Event.on(window, "resize", this._onResize, this, true);
17670 // Event.on(window, "mouseout", this._test);
17675 * Reset constraints on all drag and drop objs
17676 * @method _onResize
17680 _onResize: function(e) {
17681 this._execOnAll("resetConstraints", []);
17685 * Lock all drag and drop functionality
17689 lock: function() { this.locked = true; },
17692 * Unlock all drag and drop functionality
17696 unlock: function() { this.locked = false; },
17699 * Is drag and drop locked?
17701 * @return {boolean} True if drag and drop is locked, false otherwise.
17704 isLocked: function() { return this.locked; },
17707 * Location cache that is set for all drag drop objects when a drag is
17708 * initiated, cleared when the drag is finished.
17709 * @property locationCache
17716 * Set useCache to false if you want to force object the lookup of each
17717 * drag and drop linked element constantly during a drag.
17718 * @property useCache
17725 * The number of pixels that the mouse needs to move after the
17726 * mousedown before the drag is initiated. Default=3;
17727 * @property clickPixelThresh
17731 clickPixelThresh: 3,
17734 * The number of milliseconds after the mousedown event to initiate the
17735 * drag if we don't get a mouseup event. Default=1000
17736 * @property clickTimeThresh
17740 clickTimeThresh: 350,
17743 * Flag that indicates that either the drag pixel threshold or the
17744 * mousdown time threshold has been met
17745 * @property dragThreshMet
17750 dragThreshMet: false,
17753 * Timeout used for the click time threshold
17754 * @property clickTimeout
17759 clickTimeout: null,
17762 * The X position of the mousedown event stored for later use when a
17763 * drag threshold is met.
17772 * The Y position of the mousedown event stored for later use when a
17773 * drag threshold is met.
17782 * Each DragDrop instance must be registered with the DragDropMgr.
17783 * This is executed in DragDrop.init()
17784 * @method regDragDrop
17785 * @param {DragDrop} oDD the DragDrop object to register
17786 * @param {String} sGroup the name of the group this element belongs to
17789 regDragDrop: function(oDD, sGroup) {
17790 if (!this.initialized) { this.init(); }
17792 if (!this.ids[sGroup]) {
17793 this.ids[sGroup] = {};
17795 this.ids[sGroup][oDD.id] = oDD;
17799 * Removes the supplied dd instance from the supplied group. Executed
17800 * by DragDrop.removeFromGroup, so don't call this function directly.
17801 * @method removeDDFromGroup
17805 removeDDFromGroup: function(oDD, sGroup) {
17806 if (!this.ids[sGroup]) {
17807 this.ids[sGroup] = {};
17810 var obj = this.ids[sGroup];
17811 if (obj && obj[oDD.id]) {
17812 delete obj[oDD.id];
17817 * Unregisters a drag and drop item. This is executed in
17818 * DragDrop.unreg, use that method instead of calling this directly.
17823 _remove: function(oDD) {
17824 for (var g in oDD.groups) {
17825 if (g && this.ids[g][oDD.id]) {
17826 delete this.ids[g][oDD.id];
17829 delete this.handleIds[oDD.id];
17833 * Each DragDrop handle element must be registered. This is done
17834 * automatically when executing DragDrop.setHandleElId()
17835 * @method regHandle
17836 * @param {String} sDDId the DragDrop id this element is a handle for
17837 * @param {String} sHandleId the id of the element that is the drag
17841 regHandle: function(sDDId, sHandleId) {
17842 if (!this.handleIds[sDDId]) {
17843 this.handleIds[sDDId] = {};
17845 this.handleIds[sDDId][sHandleId] = sHandleId;
17849 * Utility function to determine if a given element has been
17850 * registered as a drag drop item.
17851 * @method isDragDrop
17852 * @param {String} id the element id to check
17853 * @return {boolean} true if this element is a DragDrop item,
17857 isDragDrop: function(id) {
17858 return ( this.getDDById(id) ) ? true : false;
17862 * Returns the drag and drop instances that are in all groups the
17863 * passed in instance belongs to.
17864 * @method getRelated
17865 * @param {DragDrop} p_oDD the obj to get related data for
17866 * @param {boolean} bTargetsOnly if true, only return targetable objs
17867 * @return {DragDrop[]} the related instances
17870 getRelated: function(p_oDD, bTargetsOnly) {
17872 for (var i in p_oDD.groups) {
17873 for (j in this.ids[i]) {
17874 var dd = this.ids[i][j];
17875 if (! this.isTypeOfDD(dd)) {
17878 if (!bTargetsOnly || dd.isTarget) {
17879 oDDs[oDDs.length] = dd;
17888 * Returns true if the specified dd target is a legal target for
17889 * the specifice drag obj
17890 * @method isLegalTarget
17891 * @param {DragDrop} the drag obj
17892 * @param {DragDrop} the target
17893 * @return {boolean} true if the target is a legal target for the
17897 isLegalTarget: function (oDD, oTargetDD) {
17898 var targets = this.getRelated(oDD, true);
17899 for (var i=0, len=targets.length;i<len;++i) {
17900 if (targets[i].id == oTargetDD.id) {
17909 * My goal is to be able to transparently determine if an object is
17910 * typeof DragDrop, and the exact subclass of DragDrop. typeof
17911 * returns "object", oDD.constructor.toString() always returns
17912 * "DragDrop" and not the name of the subclass. So for now it just
17913 * evaluates a well-known variable in DragDrop.
17914 * @method isTypeOfDD
17915 * @param {Object} the object to evaluate
17916 * @return {boolean} true if typeof oDD = DragDrop
17919 isTypeOfDD: function (oDD) {
17920 return (oDD && oDD.__ygDragDrop);
17924 * Utility function to determine if a given element has been
17925 * registered as a drag drop handle for the given Drag Drop object.
17927 * @param {String} id the element id to check
17928 * @return {boolean} true if this element is a DragDrop handle, false
17932 isHandle: function(sDDId, sHandleId) {
17933 return ( this.handleIds[sDDId] &&
17934 this.handleIds[sDDId][sHandleId] );
17938 * Returns the DragDrop instance for a given id
17939 * @method getDDById
17940 * @param {String} id the id of the DragDrop object
17941 * @return {DragDrop} the drag drop object, null if it is not found
17944 getDDById: function(id) {
17945 for (var i in this.ids) {
17946 if (this.ids[i][id]) {
17947 return this.ids[i][id];
17954 * Fired after a registered DragDrop object gets the mousedown event.
17955 * Sets up the events required to track the object being dragged
17956 * @method handleMouseDown
17957 * @param {Event} e the event
17958 * @param oDD the DragDrop object being dragged
17962 handleMouseDown: function(e, oDD) {
17964 Roo.QuickTips.disable();
17966 this.currentTarget = e.getTarget();
17968 this.dragCurrent = oDD;
17970 var el = oDD.getEl();
17972 // track start position
17973 this.startX = e.getPageX();
17974 this.startY = e.getPageY();
17976 this.deltaX = this.startX - el.offsetLeft;
17977 this.deltaY = this.startY - el.offsetTop;
17979 this.dragThreshMet = false;
17981 this.clickTimeout = setTimeout(
17983 var DDM = Roo.dd.DDM;
17984 DDM.startDrag(DDM.startX, DDM.startY);
17986 this.clickTimeThresh );
17990 * Fired when either the drag pixel threshol or the mousedown hold
17991 * time threshold has been met.
17992 * @method startDrag
17993 * @param x {int} the X position of the original mousedown
17994 * @param y {int} the Y position of the original mousedown
17997 startDrag: function(x, y) {
17998 clearTimeout(this.clickTimeout);
17999 if (this.dragCurrent) {
18000 this.dragCurrent.b4StartDrag(x, y);
18001 this.dragCurrent.startDrag(x, y);
18003 this.dragThreshMet = true;
18007 * Internal function to handle the mouseup event. Will be invoked
18008 * from the context of the document.
18009 * @method handleMouseUp
18010 * @param {Event} e the event
18014 handleMouseUp: function(e) {
18017 Roo.QuickTips.enable();
18019 if (! this.dragCurrent) {
18023 clearTimeout(this.clickTimeout);
18025 if (this.dragThreshMet) {
18026 this.fireEvents(e, true);
18036 * Utility to stop event propagation and event default, if these
18037 * features are turned on.
18038 * @method stopEvent
18039 * @param {Event} e the event as returned by this.getEvent()
18042 stopEvent: function(e){
18043 if(this.stopPropagation) {
18044 e.stopPropagation();
18047 if (this.preventDefault) {
18048 e.preventDefault();
18053 * Internal function to clean up event handlers after the drag
18054 * operation is complete
18056 * @param {Event} e the event
18060 stopDrag: function(e) {
18061 // Fire the drag end event for the item that was dragged
18062 if (this.dragCurrent) {
18063 if (this.dragThreshMet) {
18064 this.dragCurrent.b4EndDrag(e);
18065 this.dragCurrent.endDrag(e);
18068 this.dragCurrent.onMouseUp(e);
18071 this.dragCurrent = null;
18072 this.dragOvers = {};
18076 * Internal function to handle the mousemove event. Will be invoked
18077 * from the context of the html element.
18079 * @TODO figure out what we can do about mouse events lost when the
18080 * user drags objects beyond the window boundary. Currently we can
18081 * detect this in internet explorer by verifying that the mouse is
18082 * down during the mousemove event. Firefox doesn't give us the
18083 * button state on the mousemove event.
18084 * @method handleMouseMove
18085 * @param {Event} e the event
18089 handleMouseMove: function(e) {
18090 if (! this.dragCurrent) {
18094 // var button = e.which || e.button;
18096 // check for IE mouseup outside of page boundary
18097 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18099 return this.handleMouseUp(e);
18102 if (!this.dragThreshMet) {
18103 var diffX = Math.abs(this.startX - e.getPageX());
18104 var diffY = Math.abs(this.startY - e.getPageY());
18105 if (diffX > this.clickPixelThresh ||
18106 diffY > this.clickPixelThresh) {
18107 this.startDrag(this.startX, this.startY);
18111 if (this.dragThreshMet) {
18112 this.dragCurrent.b4Drag(e);
18113 this.dragCurrent.onDrag(e);
18114 if(!this.dragCurrent.moveOnly){
18115 this.fireEvents(e, false);
18125 * Iterates over all of the DragDrop elements to find ones we are
18126 * hovering over or dropping on
18127 * @method fireEvents
18128 * @param {Event} e the event
18129 * @param {boolean} isDrop is this a drop op or a mouseover op?
18133 fireEvents: function(e, isDrop) {
18134 var dc = this.dragCurrent;
18136 // If the user did the mouse up outside of the window, we could
18137 // get here even though we have ended the drag.
18138 if (!dc || dc.isLocked()) {
18142 var pt = e.getPoint();
18144 // cache the previous dragOver array
18150 var enterEvts = [];
18152 // Check to see if the object(s) we were hovering over is no longer
18153 // being hovered over so we can fire the onDragOut event
18154 for (var i in this.dragOvers) {
18156 var ddo = this.dragOvers[i];
18158 if (! this.isTypeOfDD(ddo)) {
18162 if (! this.isOverTarget(pt, ddo, this.mode)) {
18163 outEvts.push( ddo );
18166 oldOvers[i] = true;
18167 delete this.dragOvers[i];
18170 for (var sGroup in dc.groups) {
18172 if ("string" != typeof sGroup) {
18176 for (i in this.ids[sGroup]) {
18177 var oDD = this.ids[sGroup][i];
18178 if (! this.isTypeOfDD(oDD)) {
18182 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18183 if (this.isOverTarget(pt, oDD, this.mode)) {
18184 // look for drop interactions
18186 dropEvts.push( oDD );
18187 // look for drag enter and drag over interactions
18190 // initial drag over: dragEnter fires
18191 if (!oldOvers[oDD.id]) {
18192 enterEvts.push( oDD );
18193 // subsequent drag overs: dragOver fires
18195 overEvts.push( oDD );
18198 this.dragOvers[oDD.id] = oDD;
18206 if (outEvts.length) {
18207 dc.b4DragOut(e, outEvts);
18208 dc.onDragOut(e, outEvts);
18211 if (enterEvts.length) {
18212 dc.onDragEnter(e, enterEvts);
18215 if (overEvts.length) {
18216 dc.b4DragOver(e, overEvts);
18217 dc.onDragOver(e, overEvts);
18220 if (dropEvts.length) {
18221 dc.b4DragDrop(e, dropEvts);
18222 dc.onDragDrop(e, dropEvts);
18226 // fire dragout events
18228 for (i=0, len=outEvts.length; i<len; ++i) {
18229 dc.b4DragOut(e, outEvts[i].id);
18230 dc.onDragOut(e, outEvts[i].id);
18233 // fire enter events
18234 for (i=0,len=enterEvts.length; i<len; ++i) {
18235 // dc.b4DragEnter(e, oDD.id);
18236 dc.onDragEnter(e, enterEvts[i].id);
18239 // fire over events
18240 for (i=0,len=overEvts.length; i<len; ++i) {
18241 dc.b4DragOver(e, overEvts[i].id);
18242 dc.onDragOver(e, overEvts[i].id);
18245 // fire drop events
18246 for (i=0, len=dropEvts.length; i<len; ++i) {
18247 dc.b4DragDrop(e, dropEvts[i].id);
18248 dc.onDragDrop(e, dropEvts[i].id);
18253 // notify about a drop that did not find a target
18254 if (isDrop && !dropEvts.length) {
18255 dc.onInvalidDrop(e);
18261 * Helper function for getting the best match from the list of drag
18262 * and drop objects returned by the drag and drop events when we are
18263 * in INTERSECT mode. It returns either the first object that the
18264 * cursor is over, or the object that has the greatest overlap with
18265 * the dragged element.
18266 * @method getBestMatch
18267 * @param {DragDrop[]} dds The array of drag and drop objects
18269 * @return {DragDrop} The best single match
18272 getBestMatch: function(dds) {
18274 // Return null if the input is not what we expect
18275 //if (!dds || !dds.length || dds.length == 0) {
18277 // If there is only one item, it wins
18278 //} else if (dds.length == 1) {
18280 var len = dds.length;
18285 // Loop through the targeted items
18286 for (var i=0; i<len; ++i) {
18288 // If the cursor is over the object, it wins. If the
18289 // cursor is over multiple matches, the first one we come
18291 if (dd.cursorIsOver) {
18294 // Otherwise the object with the most overlap wins
18297 winner.overlap.getArea() < dd.overlap.getArea()) {
18308 * Refreshes the cache of the top-left and bottom-right points of the
18309 * drag and drop objects in the specified group(s). This is in the
18310 * format that is stored in the drag and drop instance, so typical
18313 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18317 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18319 * @TODO this really should be an indexed array. Alternatively this
18320 * method could accept both.
18321 * @method refreshCache
18322 * @param {Object} groups an associative array of groups to refresh
18325 refreshCache: function(groups) {
18326 for (var sGroup in groups) {
18327 if ("string" != typeof sGroup) {
18330 for (var i in this.ids[sGroup]) {
18331 var oDD = this.ids[sGroup][i];
18333 if (this.isTypeOfDD(oDD)) {
18334 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18335 var loc = this.getLocation(oDD);
18337 this.locationCache[oDD.id] = loc;
18339 delete this.locationCache[oDD.id];
18340 // this will unregister the drag and drop object if
18341 // the element is not in a usable state
18350 * This checks to make sure an element exists and is in the DOM. The
18351 * main purpose is to handle cases where innerHTML is used to remove
18352 * drag and drop objects from the DOM. IE provides an 'unspecified
18353 * error' when trying to access the offsetParent of such an element
18355 * @param {HTMLElement} el the element to check
18356 * @return {boolean} true if the element looks usable
18359 verifyEl: function(el) {
18364 parent = el.offsetParent;
18367 parent = el.offsetParent;
18378 * Returns a Region object containing the drag and drop element's position
18379 * and size, including the padding configured for it
18380 * @method getLocation
18381 * @param {DragDrop} oDD the drag and drop object to get the
18383 * @return {Roo.lib.Region} a Region object representing the total area
18384 * the element occupies, including any padding
18385 * the instance is configured for.
18388 getLocation: function(oDD) {
18389 if (! this.isTypeOfDD(oDD)) {
18393 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18396 pos= Roo.lib.Dom.getXY(el);
18404 x2 = x1 + el.offsetWidth;
18406 y2 = y1 + el.offsetHeight;
18408 t = y1 - oDD.padding[0];
18409 r = x2 + oDD.padding[1];
18410 b = y2 + oDD.padding[2];
18411 l = x1 - oDD.padding[3];
18413 return new Roo.lib.Region( t, r, b, l );
18417 * Checks the cursor location to see if it over the target
18418 * @method isOverTarget
18419 * @param {Roo.lib.Point} pt The point to evaluate
18420 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18421 * @return {boolean} true if the mouse is over the target
18425 isOverTarget: function(pt, oTarget, intersect) {
18426 // use cache if available
18427 var loc = this.locationCache[oTarget.id];
18428 if (!loc || !this.useCache) {
18429 loc = this.getLocation(oTarget);
18430 this.locationCache[oTarget.id] = loc;
18438 oTarget.cursorIsOver = loc.contains( pt );
18440 // DragDrop is using this as a sanity check for the initial mousedown
18441 // in this case we are done. In POINT mode, if the drag obj has no
18442 // contraints, we are also done. Otherwise we need to evaluate the
18443 // location of the target as related to the actual location of the
18444 // dragged element.
18445 var dc = this.dragCurrent;
18446 if (!dc || !dc.getTargetCoord ||
18447 (!intersect && !dc.constrainX && !dc.constrainY)) {
18448 return oTarget.cursorIsOver;
18451 oTarget.overlap = null;
18453 // Get the current location of the drag element, this is the
18454 // location of the mouse event less the delta that represents
18455 // where the original mousedown happened on the element. We
18456 // need to consider constraints and ticks as well.
18457 var pos = dc.getTargetCoord(pt.x, pt.y);
18459 var el = dc.getDragEl();
18460 var curRegion = new Roo.lib.Region( pos.y,
18461 pos.x + el.offsetWidth,
18462 pos.y + el.offsetHeight,
18465 var overlap = curRegion.intersect(loc);
18468 oTarget.overlap = overlap;
18469 return (intersect) ? true : oTarget.cursorIsOver;
18476 * unload event handler
18477 * @method _onUnload
18481 _onUnload: function(e, me) {
18482 Roo.dd.DragDropMgr.unregAll();
18486 * Cleans up the drag and drop events and objects.
18491 unregAll: function() {
18493 if (this.dragCurrent) {
18495 this.dragCurrent = null;
18498 this._execOnAll("unreg", []);
18500 for (i in this.elementCache) {
18501 delete this.elementCache[i];
18504 this.elementCache = {};
18509 * A cache of DOM elements
18510 * @property elementCache
18517 * Get the wrapper for the DOM element specified
18518 * @method getElWrapper
18519 * @param {String} id the id of the element to get
18520 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18522 * @deprecated This wrapper isn't that useful
18525 getElWrapper: function(id) {
18526 var oWrapper = this.elementCache[id];
18527 if (!oWrapper || !oWrapper.el) {
18528 oWrapper = this.elementCache[id] =
18529 new this.ElementWrapper(Roo.getDom(id));
18535 * Returns the actual DOM element
18536 * @method getElement
18537 * @param {String} id the id of the elment to get
18538 * @return {Object} The element
18539 * @deprecated use Roo.getDom instead
18542 getElement: function(id) {
18543 return Roo.getDom(id);
18547 * Returns the style property for the DOM element (i.e.,
18548 * document.getElById(id).style)
18550 * @param {String} id the id of the elment to get
18551 * @return {Object} The style property of the element
18552 * @deprecated use Roo.getDom instead
18555 getCss: function(id) {
18556 var el = Roo.getDom(id);
18557 return (el) ? el.style : null;
18561 * Inner class for cached elements
18562 * @class DragDropMgr.ElementWrapper
18567 ElementWrapper: function(el) {
18572 this.el = el || null;
18577 this.id = this.el && el.id;
18579 * A reference to the style property
18582 this.css = this.el && el.style;
18586 * Returns the X position of an html element
18588 * @param el the element for which to get the position
18589 * @return {int} the X coordinate
18591 * @deprecated use Roo.lib.Dom.getX instead
18594 getPosX: function(el) {
18595 return Roo.lib.Dom.getX(el);
18599 * Returns the Y position of an html element
18601 * @param el the element for which to get the position
18602 * @return {int} the Y coordinate
18603 * @deprecated use Roo.lib.Dom.getY instead
18606 getPosY: function(el) {
18607 return Roo.lib.Dom.getY(el);
18611 * Swap two nodes. In IE, we use the native method, for others we
18612 * emulate the IE behavior
18614 * @param n1 the first node to swap
18615 * @param n2 the other node to swap
18618 swapNode: function(n1, n2) {
18622 var p = n2.parentNode;
18623 var s = n2.nextSibling;
18626 p.insertBefore(n1, n2);
18627 } else if (n2 == n1.nextSibling) {
18628 p.insertBefore(n2, n1);
18630 n1.parentNode.replaceChild(n2, n1);
18631 p.insertBefore(n1, s);
18637 * Returns the current scroll position
18638 * @method getScroll
18642 getScroll: function () {
18643 var t, l, dde=document.documentElement, db=document.body;
18644 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18646 l = dde.scrollLeft;
18653 return { top: t, left: l };
18657 * Returns the specified element style property
18659 * @param {HTMLElement} el the element
18660 * @param {string} styleProp the style property
18661 * @return {string} The value of the style property
18662 * @deprecated use Roo.lib.Dom.getStyle
18665 getStyle: function(el, styleProp) {
18666 return Roo.fly(el).getStyle(styleProp);
18670 * Gets the scrollTop
18671 * @method getScrollTop
18672 * @return {int} the document's scrollTop
18675 getScrollTop: function () { return this.getScroll().top; },
18678 * Gets the scrollLeft
18679 * @method getScrollLeft
18680 * @return {int} the document's scrollTop
18683 getScrollLeft: function () { return this.getScroll().left; },
18686 * Sets the x/y position of an element to the location of the
18689 * @param {HTMLElement} moveEl The element to move
18690 * @param {HTMLElement} targetEl The position reference element
18693 moveToEl: function (moveEl, targetEl) {
18694 var aCoord = Roo.lib.Dom.getXY(targetEl);
18695 Roo.lib.Dom.setXY(moveEl, aCoord);
18699 * Numeric array sort function
18700 * @method numericSort
18703 numericSort: function(a, b) { return (a - b); },
18707 * @property _timeoutCount
18714 * Trying to make the load order less important. Without this we get
18715 * an error if this file is loaded before the Event Utility.
18716 * @method _addListeners
18720 _addListeners: function() {
18721 var DDM = Roo.dd.DDM;
18722 if ( Roo.lib.Event && document ) {
18725 if (DDM._timeoutCount > 2000) {
18727 setTimeout(DDM._addListeners, 10);
18728 if (document && document.body) {
18729 DDM._timeoutCount += 1;
18736 * Recursively searches the immediate parent and all child nodes for
18737 * the handle element in order to determine wheter or not it was
18739 * @method handleWasClicked
18740 * @param node the html element to inspect
18743 handleWasClicked: function(node, id) {
18744 if (this.isHandle(id, node.id)) {
18747 // check to see if this is a text node child of the one we want
18748 var p = node.parentNode;
18751 if (this.isHandle(id, p.id)) {
18766 // shorter alias, save a few bytes
18767 Roo.dd.DDM = Roo.dd.DragDropMgr;
18768 Roo.dd.DDM._addListeners();
18772 * Ext JS Library 1.1.1
18773 * Copyright(c) 2006-2007, Ext JS, LLC.
18775 * Originally Released Under LGPL - original licence link has changed is not relivant.
18778 * <script type="text/javascript">
18783 * A DragDrop implementation where the linked element follows the
18784 * mouse cursor during a drag.
18785 * @extends Roo.dd.DragDrop
18787 * @param {String} id the id of the linked element
18788 * @param {String} sGroup the group of related DragDrop items
18789 * @param {object} config an object containing configurable attributes
18790 * Valid properties for DD:
18793 Roo.dd.DD = function(id, sGroup, config) {
18795 this.init(id, sGroup, config);
18799 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18802 * When set to true, the utility automatically tries to scroll the browser
18803 * window wehn a drag and drop element is dragged near the viewport boundary.
18804 * Defaults to true.
18811 * Sets the pointer offset to the distance between the linked element's top
18812 * left corner and the location the element was clicked
18813 * @method autoOffset
18814 * @param {int} iPageX the X coordinate of the click
18815 * @param {int} iPageY the Y coordinate of the click
18817 autoOffset: function(iPageX, iPageY) {
18818 var x = iPageX - this.startPageX;
18819 var y = iPageY - this.startPageY;
18820 this.setDelta(x, y);
18824 * Sets the pointer offset. You can call this directly to force the
18825 * offset to be in a particular location (e.g., pass in 0,0 to set it
18826 * to the center of the object)
18828 * @param {int} iDeltaX the distance from the left
18829 * @param {int} iDeltaY the distance from the top
18831 setDelta: function(iDeltaX, iDeltaY) {
18832 this.deltaX = iDeltaX;
18833 this.deltaY = iDeltaY;
18837 * Sets the drag element to the location of the mousedown or click event,
18838 * maintaining the cursor location relative to the location on the element
18839 * that was clicked. Override this if you want to place the element in a
18840 * location other than where the cursor is.
18841 * @method setDragElPos
18842 * @param {int} iPageX the X coordinate of the mousedown or drag event
18843 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18845 setDragElPos: function(iPageX, iPageY) {
18846 // the first time we do this, we are going to check to make sure
18847 // the element has css positioning
18849 var el = this.getDragEl();
18850 this.alignElWithMouse(el, iPageX, iPageY);
18854 * Sets the element to the location of the mousedown or click event,
18855 * maintaining the cursor location relative to the location on the element
18856 * that was clicked. Override this if you want to place the element in a
18857 * location other than where the cursor is.
18858 * @method alignElWithMouse
18859 * @param {HTMLElement} el the element to move
18860 * @param {int} iPageX the X coordinate of the mousedown or drag event
18861 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18863 alignElWithMouse: function(el, iPageX, iPageY) {
18864 var oCoord = this.getTargetCoord(iPageX, iPageY);
18865 var fly = el.dom ? el : Roo.fly(el);
18866 if (!this.deltaSetXY) {
18867 var aCoord = [oCoord.x, oCoord.y];
18869 var newLeft = fly.getLeft(true);
18870 var newTop = fly.getTop(true);
18871 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18873 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18876 this.cachePosition(oCoord.x, oCoord.y);
18877 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18882 * Saves the most recent position so that we can reset the constraints and
18883 * tick marks on-demand. We need to know this so that we can calculate the
18884 * number of pixels the element is offset from its original position.
18885 * @method cachePosition
18886 * @param iPageX the current x position (optional, this just makes it so we
18887 * don't have to look it up again)
18888 * @param iPageY the current y position (optional, this just makes it so we
18889 * don't have to look it up again)
18891 cachePosition: function(iPageX, iPageY) {
18893 this.lastPageX = iPageX;
18894 this.lastPageY = iPageY;
18896 var aCoord = Roo.lib.Dom.getXY(this.getEl());
18897 this.lastPageX = aCoord[0];
18898 this.lastPageY = aCoord[1];
18903 * Auto-scroll the window if the dragged object has been moved beyond the
18904 * visible window boundary.
18905 * @method autoScroll
18906 * @param {int} x the drag element's x position
18907 * @param {int} y the drag element's y position
18908 * @param {int} h the height of the drag element
18909 * @param {int} w the width of the drag element
18912 autoScroll: function(x, y, h, w) {
18915 // The client height
18916 var clientH = Roo.lib.Dom.getViewWidth();
18918 // The client width
18919 var clientW = Roo.lib.Dom.getViewHeight();
18921 // The amt scrolled down
18922 var st = this.DDM.getScrollTop();
18924 // The amt scrolled right
18925 var sl = this.DDM.getScrollLeft();
18927 // Location of the bottom of the element
18930 // Location of the right of the element
18933 // The distance from the cursor to the bottom of the visible area,
18934 // adjusted so that we don't scroll if the cursor is beyond the
18935 // element drag constraints
18936 var toBot = (clientH + st - y - this.deltaY);
18938 // The distance from the cursor to the right of the visible area
18939 var toRight = (clientW + sl - x - this.deltaX);
18942 // How close to the edge the cursor must be before we scroll
18943 // var thresh = (document.all) ? 100 : 40;
18946 // How many pixels to scroll per autoscroll op. This helps to reduce
18947 // clunky scrolling. IE is more sensitive about this ... it needs this
18948 // value to be higher.
18949 var scrAmt = (document.all) ? 80 : 30;
18951 // Scroll down if we are near the bottom of the visible page and the
18952 // obj extends below the crease
18953 if ( bot > clientH && toBot < thresh ) {
18954 window.scrollTo(sl, st + scrAmt);
18957 // Scroll up if the window is scrolled down and the top of the object
18958 // goes above the top border
18959 if ( y < st && st > 0 && y - st < thresh ) {
18960 window.scrollTo(sl, st - scrAmt);
18963 // Scroll right if the obj is beyond the right border and the cursor is
18964 // near the border.
18965 if ( right > clientW && toRight < thresh ) {
18966 window.scrollTo(sl + scrAmt, st);
18969 // Scroll left if the window has been scrolled to the right and the obj
18970 // extends past the left border
18971 if ( x < sl && sl > 0 && x - sl < thresh ) {
18972 window.scrollTo(sl - scrAmt, st);
18978 * Finds the location the element should be placed if we want to move
18979 * it to where the mouse location less the click offset would place us.
18980 * @method getTargetCoord
18981 * @param {int} iPageX the X coordinate of the click
18982 * @param {int} iPageY the Y coordinate of the click
18983 * @return an object that contains the coordinates (Object.x and Object.y)
18986 getTargetCoord: function(iPageX, iPageY) {
18989 var x = iPageX - this.deltaX;
18990 var y = iPageY - this.deltaY;
18992 if (this.constrainX) {
18993 if (x < this.minX) { x = this.minX; }
18994 if (x > this.maxX) { x = this.maxX; }
18997 if (this.constrainY) {
18998 if (y < this.minY) { y = this.minY; }
18999 if (y > this.maxY) { y = this.maxY; }
19002 x = this.getTick(x, this.xTicks);
19003 y = this.getTick(y, this.yTicks);
19010 * Sets up config options specific to this class. Overrides
19011 * Roo.dd.DragDrop, but all versions of this method through the
19012 * inheritance chain are called
19014 applyConfig: function() {
19015 Roo.dd.DD.superclass.applyConfig.call(this);
19016 this.scroll = (this.config.scroll !== false);
19020 * Event that fires prior to the onMouseDown event. Overrides
19023 b4MouseDown: function(e) {
19024 // this.resetConstraints();
19025 this.autoOffset(e.getPageX(),
19030 * Event that fires prior to the onDrag event. Overrides
19033 b4Drag: function(e) {
19034 this.setDragElPos(e.getPageX(),
19038 toString: function() {
19039 return ("DD " + this.id);
19042 //////////////////////////////////////////////////////////////////////////
19043 // Debugging ygDragDrop events that can be overridden
19044 //////////////////////////////////////////////////////////////////////////
19046 startDrag: function(x, y) {
19049 onDrag: function(e) {
19052 onDragEnter: function(e, id) {
19055 onDragOver: function(e, id) {
19058 onDragOut: function(e, id) {
19061 onDragDrop: function(e, id) {
19064 endDrag: function(e) {
19071 * Ext JS Library 1.1.1
19072 * Copyright(c) 2006-2007, Ext JS, LLC.
19074 * Originally Released Under LGPL - original licence link has changed is not relivant.
19077 * <script type="text/javascript">
19081 * @class Roo.dd.DDProxy
19082 * A DragDrop implementation that inserts an empty, bordered div into
19083 * the document that follows the cursor during drag operations. At the time of
19084 * the click, the frame div is resized to the dimensions of the linked html
19085 * element, and moved to the exact location of the linked element.
19087 * References to the "frame" element refer to the single proxy element that
19088 * was created to be dragged in place of all DDProxy elements on the
19091 * @extends Roo.dd.DD
19093 * @param {String} id the id of the linked html element
19094 * @param {String} sGroup the group of related DragDrop objects
19095 * @param {object} config an object containing configurable attributes
19096 * Valid properties for DDProxy in addition to those in DragDrop:
19097 * resizeFrame, centerFrame, dragElId
19099 Roo.dd.DDProxy = function(id, sGroup, config) {
19101 this.init(id, sGroup, config);
19107 * The default drag frame div id
19108 * @property Roo.dd.DDProxy.dragElId
19112 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19114 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19117 * By default we resize the drag frame to be the same size as the element
19118 * we want to drag (this is to get the frame effect). We can turn it off
19119 * if we want a different behavior.
19120 * @property resizeFrame
19126 * By default the frame is positioned exactly where the drag element is, so
19127 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19128 * you do not have constraints on the obj is to have the drag frame centered
19129 * around the cursor. Set centerFrame to true for this effect.
19130 * @property centerFrame
19133 centerFrame: false,
19136 * Creates the proxy element if it does not yet exist
19137 * @method createFrame
19139 createFrame: function() {
19141 var body = document.body;
19143 if (!body || !body.firstChild) {
19144 setTimeout( function() { self.createFrame(); }, 50 );
19148 var div = this.getDragEl();
19151 div = document.createElement("div");
19152 div.id = this.dragElId;
19155 s.position = "absolute";
19156 s.visibility = "hidden";
19158 s.border = "2px solid #aaa";
19161 // appendChild can blow up IE if invoked prior to the window load event
19162 // while rendering a table. It is possible there are other scenarios
19163 // that would cause this to happen as well.
19164 body.insertBefore(div, body.firstChild);
19169 * Initialization for the drag frame element. Must be called in the
19170 * constructor of all subclasses
19171 * @method initFrame
19173 initFrame: function() {
19174 this.createFrame();
19177 applyConfig: function() {
19178 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19180 this.resizeFrame = (this.config.resizeFrame !== false);
19181 this.centerFrame = (this.config.centerFrame);
19182 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19186 * Resizes the drag frame to the dimensions of the clicked object, positions
19187 * it over the object, and finally displays it
19188 * @method showFrame
19189 * @param {int} iPageX X click position
19190 * @param {int} iPageY Y click position
19193 showFrame: function(iPageX, iPageY) {
19194 var el = this.getEl();
19195 var dragEl = this.getDragEl();
19196 var s = dragEl.style;
19198 this._resizeProxy();
19200 if (this.centerFrame) {
19201 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19202 Math.round(parseInt(s.height, 10)/2) );
19205 this.setDragElPos(iPageX, iPageY);
19207 Roo.fly(dragEl).show();
19211 * The proxy is automatically resized to the dimensions of the linked
19212 * element when a drag is initiated, unless resizeFrame is set to false
19213 * @method _resizeProxy
19216 _resizeProxy: function() {
19217 if (this.resizeFrame) {
19218 var el = this.getEl();
19219 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19223 // overrides Roo.dd.DragDrop
19224 b4MouseDown: function(e) {
19225 var x = e.getPageX();
19226 var y = e.getPageY();
19227 this.autoOffset(x, y);
19228 this.setDragElPos(x, y);
19231 // overrides Roo.dd.DragDrop
19232 b4StartDrag: function(x, y) {
19233 // show the drag frame
19234 this.showFrame(x, y);
19237 // overrides Roo.dd.DragDrop
19238 b4EndDrag: function(e) {
19239 Roo.fly(this.getDragEl()).hide();
19242 // overrides Roo.dd.DragDrop
19243 // By default we try to move the element to the last location of the frame.
19244 // This is so that the default behavior mirrors that of Roo.dd.DD.
19245 endDrag: function(e) {
19247 var lel = this.getEl();
19248 var del = this.getDragEl();
19250 // Show the drag frame briefly so we can get its position
19251 del.style.visibility = "";
19254 // Hide the linked element before the move to get around a Safari
19256 lel.style.visibility = "hidden";
19257 Roo.dd.DDM.moveToEl(lel, del);
19258 del.style.visibility = "hidden";
19259 lel.style.visibility = "";
19264 beforeMove : function(){
19268 afterDrag : function(){
19272 toString: function() {
19273 return ("DDProxy " + this.id);
19279 * Ext JS Library 1.1.1
19280 * Copyright(c) 2006-2007, Ext JS, LLC.
19282 * Originally Released Under LGPL - original licence link has changed is not relivant.
19285 * <script type="text/javascript">
19289 * @class Roo.dd.DDTarget
19290 * A DragDrop implementation that does not move, but can be a drop
19291 * target. You would get the same result by simply omitting implementation
19292 * for the event callbacks, but this way we reduce the processing cost of the
19293 * event listener and the callbacks.
19294 * @extends Roo.dd.DragDrop
19296 * @param {String} id the id of the element that is a drop target
19297 * @param {String} sGroup the group of related DragDrop objects
19298 * @param {object} config an object containing configurable attributes
19299 * Valid properties for DDTarget in addition to those in
19303 Roo.dd.DDTarget = function(id, sGroup, config) {
19305 this.initTarget(id, sGroup, config);
19307 if (config.listeners || config.events) {
19308 Roo.dd.DragDrop.superclass.constructor.call(this, {
19309 listeners : config.listeners || {},
19310 events : config.events || {}
19315 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19316 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19317 toString: function() {
19318 return ("DDTarget " + this.id);
19323 * Ext JS Library 1.1.1
19324 * Copyright(c) 2006-2007, Ext JS, LLC.
19326 * Originally Released Under LGPL - original licence link has changed is not relivant.
19329 * <script type="text/javascript">
19334 * @class Roo.dd.ScrollManager
19335 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19336 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19339 Roo.dd.ScrollManager = function(){
19340 var ddm = Roo.dd.DragDropMgr;
19347 var onStop = function(e){
19352 var triggerRefresh = function(){
19353 if(ddm.dragCurrent){
19354 ddm.refreshCache(ddm.dragCurrent.groups);
19358 var doScroll = function(){
19359 if(ddm.dragCurrent){
19360 var dds = Roo.dd.ScrollManager;
19362 if(proc.el.scroll(proc.dir, dds.increment)){
19366 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19371 var clearProc = function(){
19373 clearInterval(proc.id);
19380 var startProc = function(el, dir){
19381 Roo.log('scroll startproc');
19385 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19388 var onFire = function(e, isDrop){
19390 if(isDrop || !ddm.dragCurrent){ return; }
19391 var dds = Roo.dd.ScrollManager;
19392 if(!dragEl || dragEl != ddm.dragCurrent){
19393 dragEl = ddm.dragCurrent;
19394 // refresh regions on drag start
19395 dds.refreshCache();
19398 var xy = Roo.lib.Event.getXY(e);
19399 var pt = new Roo.lib.Point(xy[0], xy[1]);
19400 for(var id in els){
19401 var el = els[id], r = el._region;
19402 if(r && r.contains(pt) && el.isScrollable()){
19403 if(r.bottom - pt.y <= dds.thresh){
19405 startProc(el, "down");
19408 }else if(r.right - pt.x <= dds.thresh){
19410 startProc(el, "left");
19413 }else if(pt.y - r.top <= dds.thresh){
19415 startProc(el, "up");
19418 }else if(pt.x - r.left <= dds.thresh){
19420 startProc(el, "right");
19429 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19430 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19434 * Registers new overflow element(s) to auto scroll
19435 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19437 register : function(el){
19438 if(el instanceof Array){
19439 for(var i = 0, len = el.length; i < len; i++) {
19440 this.register(el[i]);
19446 Roo.dd.ScrollManager.els = els;
19450 * Unregisters overflow element(s) so they are no longer scrolled
19451 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19453 unregister : function(el){
19454 if(el instanceof Array){
19455 for(var i = 0, len = el.length; i < len; i++) {
19456 this.unregister(el[i]);
19465 * The number of pixels from the edge of a container the pointer needs to be to
19466 * trigger scrolling (defaults to 25)
19472 * The number of pixels to scroll in each scroll increment (defaults to 50)
19478 * The frequency of scrolls in milliseconds (defaults to 500)
19484 * True to animate the scroll (defaults to true)
19490 * The animation duration in seconds -
19491 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19497 * Manually trigger a cache refresh.
19499 refreshCache : function(){
19500 for(var id in els){
19501 if(typeof els[id] == 'object'){ // for people extending the object prototype
19502 els[id]._region = els[id].getRegion();
19509 * Ext JS Library 1.1.1
19510 * Copyright(c) 2006-2007, Ext JS, LLC.
19512 * Originally Released Under LGPL - original licence link has changed is not relivant.
19515 * <script type="text/javascript">
19520 * @class Roo.dd.Registry
19521 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19522 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19525 Roo.dd.Registry = function(){
19528 var autoIdSeed = 0;
19530 var getId = function(el, autogen){
19531 if(typeof el == "string"){
19535 if(!id && autogen !== false){
19536 id = "roodd-" + (++autoIdSeed);
19544 * Register a drag drop element
19545 * @param {String|HTMLElement} element The id or DOM node to register
19546 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19547 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19548 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19549 * populated in the data object (if applicable):
19551 Value Description<br />
19552 --------- ------------------------------------------<br />
19553 handles Array of DOM nodes that trigger dragging<br />
19554 for the element being registered<br />
19555 isHandle True if the element passed in triggers<br />
19556 dragging itself, else false
19559 register : function(el, data){
19561 if(typeof el == "string"){
19562 el = document.getElementById(el);
19565 elements[getId(el)] = data;
19566 if(data.isHandle !== false){
19567 handles[data.ddel.id] = data;
19570 var hs = data.handles;
19571 for(var i = 0, len = hs.length; i < len; i++){
19572 handles[getId(hs[i])] = data;
19578 * Unregister a drag drop element
19579 * @param {String|HTMLElement} element The id or DOM node to unregister
19581 unregister : function(el){
19582 var id = getId(el, false);
19583 var data = elements[id];
19585 delete elements[id];
19587 var hs = data.handles;
19588 for(var i = 0, len = hs.length; i < len; i++){
19589 delete handles[getId(hs[i], false)];
19596 * Returns the handle registered for a DOM Node by id
19597 * @param {String|HTMLElement} id The DOM node or id to look up
19598 * @return {Object} handle The custom handle data
19600 getHandle : function(id){
19601 if(typeof id != "string"){ // must be element?
19604 return handles[id];
19608 * Returns the handle that is registered for the DOM node that is the target of the event
19609 * @param {Event} e The event
19610 * @return {Object} handle The custom handle data
19612 getHandleFromEvent : function(e){
19613 var t = Roo.lib.Event.getTarget(e);
19614 return t ? handles[t.id] : null;
19618 * Returns a custom data object that is registered for a DOM node by id
19619 * @param {String|HTMLElement} id The DOM node or id to look up
19620 * @return {Object} data The custom data
19622 getTarget : function(id){
19623 if(typeof id != "string"){ // must be element?
19626 return elements[id];
19630 * Returns a custom data object that is registered for the DOM node that is the target of the event
19631 * @param {Event} e The event
19632 * @return {Object} data The custom data
19634 getTargetFromEvent : function(e){
19635 var t = Roo.lib.Event.getTarget(e);
19636 return t ? elements[t.id] || handles[t.id] : null;
19641 * Ext JS Library 1.1.1
19642 * Copyright(c) 2006-2007, Ext JS, LLC.
19644 * Originally Released Under LGPL - original licence link has changed is not relivant.
19647 * <script type="text/javascript">
19652 * @class Roo.dd.StatusProxy
19653 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19654 * default drag proxy used by all Roo.dd components.
19656 * @param {Object} config
19658 Roo.dd.StatusProxy = function(config){
19659 Roo.apply(this, config);
19660 this.id = this.id || Roo.id();
19661 this.el = new Roo.Layer({
19663 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19664 {tag: "div", cls: "x-dd-drop-icon"},
19665 {tag: "div", cls: "x-dd-drag-ghost"}
19668 shadow: !config || config.shadow !== false
19670 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19671 this.dropStatus = this.dropNotAllowed;
19674 Roo.dd.StatusProxy.prototype = {
19676 * @cfg {String} dropAllowed
19677 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19679 dropAllowed : "x-dd-drop-ok",
19681 * @cfg {String} dropNotAllowed
19682 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19684 dropNotAllowed : "x-dd-drop-nodrop",
19687 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19688 * over the current target element.
19689 * @param {String} cssClass The css class for the new drop status indicator image
19691 setStatus : function(cssClass){
19692 cssClass = cssClass || this.dropNotAllowed;
19693 if(this.dropStatus != cssClass){
19694 this.el.replaceClass(this.dropStatus, cssClass);
19695 this.dropStatus = cssClass;
19700 * Resets the status indicator to the default dropNotAllowed value
19701 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19703 reset : function(clearGhost){
19704 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19705 this.dropStatus = this.dropNotAllowed;
19707 this.ghost.update("");
19712 * Updates the contents of the ghost element
19713 * @param {String} html The html that will replace the current innerHTML of the ghost element
19715 update : function(html){
19716 if(typeof html == "string"){
19717 this.ghost.update(html);
19719 this.ghost.update("");
19720 html.style.margin = "0";
19721 this.ghost.dom.appendChild(html);
19723 // ensure float = none set?? cant remember why though.
19724 var el = this.ghost.dom.firstChild;
19726 Roo.fly(el).setStyle('float', 'none');
19731 * Returns the underlying proxy {@link Roo.Layer}
19732 * @return {Roo.Layer} el
19734 getEl : function(){
19739 * Returns the ghost element
19740 * @return {Roo.Element} el
19742 getGhost : function(){
19748 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19750 hide : function(clear){
19758 * Stops the repair animation if it's currently running
19761 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19767 * Displays this proxy
19774 * Force the Layer to sync its shadow and shim positions to the element
19781 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19782 * invalid drop operation by the item being dragged.
19783 * @param {Array} xy The XY position of the element ([x, y])
19784 * @param {Function} callback The function to call after the repair is complete
19785 * @param {Object} scope The scope in which to execute the callback
19787 repair : function(xy, callback, scope){
19788 this.callback = callback;
19789 this.scope = scope;
19790 if(xy && this.animRepair !== false){
19791 this.el.addClass("x-dd-drag-repair");
19792 this.el.hideUnders(true);
19793 this.anim = this.el.shift({
19794 duration: this.repairDuration || .5,
19798 callback: this.afterRepair,
19802 this.afterRepair();
19807 afterRepair : function(){
19809 if(typeof this.callback == "function"){
19810 this.callback.call(this.scope || this);
19812 this.callback = null;
19817 * Ext JS Library 1.1.1
19818 * Copyright(c) 2006-2007, Ext JS, LLC.
19820 * Originally Released Under LGPL - original licence link has changed is not relivant.
19823 * <script type="text/javascript">
19827 * @class Roo.dd.DragSource
19828 * @extends Roo.dd.DDProxy
19829 * A simple class that provides the basic implementation needed to make any element draggable.
19831 * @param {String/HTMLElement/Element} el The container element
19832 * @param {Object} config
19834 Roo.dd.DragSource = function(el, config){
19835 this.el = Roo.get(el);
19836 this.dragData = {};
19838 Roo.apply(this, config);
19841 this.proxy = new Roo.dd.StatusProxy();
19844 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19845 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19847 this.dragging = false;
19850 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19852 * @cfg {String} dropAllowed
19853 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19855 dropAllowed : "x-dd-drop-ok",
19857 * @cfg {String} dropNotAllowed
19858 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19860 dropNotAllowed : "x-dd-drop-nodrop",
19863 * Returns the data object associated with this drag source
19864 * @return {Object} data An object containing arbitrary data
19866 getDragData : function(e){
19867 return this.dragData;
19871 onDragEnter : function(e, id){
19872 var target = Roo.dd.DragDropMgr.getDDById(id);
19873 this.cachedTarget = target;
19874 if(this.beforeDragEnter(target, e, id) !== false){
19875 if(target.isNotifyTarget){
19876 var status = target.notifyEnter(this, e, this.dragData);
19877 this.proxy.setStatus(status);
19879 this.proxy.setStatus(this.dropAllowed);
19882 if(this.afterDragEnter){
19884 * An empty function by default, but provided so that you can perform a custom action
19885 * when the dragged item enters the drop target by providing an implementation.
19886 * @param {Roo.dd.DragDrop} target The drop target
19887 * @param {Event} e The event object
19888 * @param {String} id The id of the dragged element
19889 * @method afterDragEnter
19891 this.afterDragEnter(target, e, id);
19897 * An empty function by default, but provided so that you can perform a custom action
19898 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
19899 * @param {Roo.dd.DragDrop} target The drop target
19900 * @param {Event} e The event object
19901 * @param {String} id The id of the dragged element
19902 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19904 beforeDragEnter : function(target, e, id){
19909 alignElWithMouse: function() {
19910 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
19915 onDragOver : function(e, id){
19916 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19917 if(this.beforeDragOver(target, e, id) !== false){
19918 if(target.isNotifyTarget){
19919 var status = target.notifyOver(this, e, this.dragData);
19920 this.proxy.setStatus(status);
19923 if(this.afterDragOver){
19925 * An empty function by default, but provided so that you can perform a custom action
19926 * while the dragged item is over the drop target by providing an implementation.
19927 * @param {Roo.dd.DragDrop} target The drop target
19928 * @param {Event} e The event object
19929 * @param {String} id The id of the dragged element
19930 * @method afterDragOver
19932 this.afterDragOver(target, e, id);
19938 * An empty function by default, but provided so that you can perform a custom action
19939 * while the dragged item is over the drop target and optionally cancel the onDragOver.
19940 * @param {Roo.dd.DragDrop} target The drop target
19941 * @param {Event} e The event object
19942 * @param {String} id The id of the dragged element
19943 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19945 beforeDragOver : function(target, e, id){
19950 onDragOut : function(e, id){
19951 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19952 if(this.beforeDragOut(target, e, id) !== false){
19953 if(target.isNotifyTarget){
19954 target.notifyOut(this, e, this.dragData);
19956 this.proxy.reset();
19957 if(this.afterDragOut){
19959 * An empty function by default, but provided so that you can perform a custom action
19960 * after the dragged item is dragged out of the target without dropping.
19961 * @param {Roo.dd.DragDrop} target The drop target
19962 * @param {Event} e The event object
19963 * @param {String} id The id of the dragged element
19964 * @method afterDragOut
19966 this.afterDragOut(target, e, id);
19969 this.cachedTarget = null;
19973 * An empty function by default, but provided so that you can perform a custom action before the dragged
19974 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
19975 * @param {Roo.dd.DragDrop} target The drop target
19976 * @param {Event} e The event object
19977 * @param {String} id The id of the dragged element
19978 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19980 beforeDragOut : function(target, e, id){
19985 onDragDrop : function(e, id){
19986 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19987 if(this.beforeDragDrop(target, e, id) !== false){
19988 if(target.isNotifyTarget){
19989 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
19990 this.onValidDrop(target, e, id);
19992 this.onInvalidDrop(target, e, id);
19995 this.onValidDrop(target, e, id);
19998 if(this.afterDragDrop){
20000 * An empty function by default, but provided so that you can perform a custom action
20001 * after a valid drag drop has occurred by providing an implementation.
20002 * @param {Roo.dd.DragDrop} target The drop target
20003 * @param {Event} e The event object
20004 * @param {String} id The id of the dropped element
20005 * @method afterDragDrop
20007 this.afterDragDrop(target, e, id);
20010 delete this.cachedTarget;
20014 * An empty function by default, but provided so that you can perform a custom action before the dragged
20015 * item is dropped onto the target and optionally cancel the onDragDrop.
20016 * @param {Roo.dd.DragDrop} target The drop target
20017 * @param {Event} e The event object
20018 * @param {String} id The id of the dragged element
20019 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20021 beforeDragDrop : function(target, e, id){
20026 onValidDrop : function(target, e, id){
20028 if(this.afterValidDrop){
20030 * An empty function by default, but provided so that you can perform a custom action
20031 * after a valid drop has occurred by providing an implementation.
20032 * @param {Object} target The target DD
20033 * @param {Event} e The event object
20034 * @param {String} id The id of the dropped element
20035 * @method afterInvalidDrop
20037 this.afterValidDrop(target, e, id);
20042 getRepairXY : function(e, data){
20043 return this.el.getXY();
20047 onInvalidDrop : function(target, e, id){
20048 this.beforeInvalidDrop(target, e, id);
20049 if(this.cachedTarget){
20050 if(this.cachedTarget.isNotifyTarget){
20051 this.cachedTarget.notifyOut(this, e, this.dragData);
20053 this.cacheTarget = null;
20055 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20057 if(this.afterInvalidDrop){
20059 * An empty function by default, but provided so that you can perform a custom action
20060 * after an invalid drop has occurred by providing an implementation.
20061 * @param {Event} e The event object
20062 * @param {String} id The id of the dropped element
20063 * @method afterInvalidDrop
20065 this.afterInvalidDrop(e, id);
20070 afterRepair : function(){
20072 this.el.highlight(this.hlColor || "c3daf9");
20074 this.dragging = false;
20078 * An empty function by default, but provided so that you can perform a custom action after an invalid
20079 * drop has occurred.
20080 * @param {Roo.dd.DragDrop} target The drop target
20081 * @param {Event} e The event object
20082 * @param {String} id The id of the dragged element
20083 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20085 beforeInvalidDrop : function(target, e, id){
20090 handleMouseDown : function(e){
20091 if(this.dragging) {
20094 var data = this.getDragData(e);
20095 if(data && this.onBeforeDrag(data, e) !== false){
20096 this.dragData = data;
20098 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20103 * An empty function by default, but provided so that you can perform a custom action before the initial
20104 * drag event begins and optionally cancel it.
20105 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20106 * @param {Event} e The event object
20107 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20109 onBeforeDrag : function(data, e){
20114 * An empty function by default, but provided so that you can perform a custom action once the initial
20115 * drag event has begun. The drag cannot be canceled from this function.
20116 * @param {Number} x The x position of the click on the dragged object
20117 * @param {Number} y The y position of the click on the dragged object
20119 onStartDrag : Roo.emptyFn,
20121 // private - YUI override
20122 startDrag : function(x, y){
20123 this.proxy.reset();
20124 this.dragging = true;
20125 this.proxy.update("");
20126 this.onInitDrag(x, y);
20131 onInitDrag : function(x, y){
20132 var clone = this.el.dom.cloneNode(true);
20133 clone.id = Roo.id(); // prevent duplicate ids
20134 this.proxy.update(clone);
20135 this.onStartDrag(x, y);
20140 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20141 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20143 getProxy : function(){
20148 * Hides the drag source's {@link Roo.dd.StatusProxy}
20150 hideProxy : function(){
20152 this.proxy.reset(true);
20153 this.dragging = false;
20157 triggerCacheRefresh : function(){
20158 Roo.dd.DDM.refreshCache(this.groups);
20161 // private - override to prevent hiding
20162 b4EndDrag: function(e) {
20165 // private - override to prevent moving
20166 endDrag : function(e){
20167 this.onEndDrag(this.dragData, e);
20171 onEndDrag : function(data, e){
20174 // private - pin to cursor
20175 autoOffset : function(x, y) {
20176 this.setDelta(-12, -20);
20180 * Ext JS Library 1.1.1
20181 * Copyright(c) 2006-2007, Ext JS, LLC.
20183 * Originally Released Under LGPL - original licence link has changed is not relivant.
20186 * <script type="text/javascript">
20191 * @class Roo.dd.DropTarget
20192 * @extends Roo.dd.DDTarget
20193 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20194 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20196 * @param {String/HTMLElement/Element} el The container element
20197 * @param {Object} config
20199 Roo.dd.DropTarget = function(el, config){
20200 this.el = Roo.get(el);
20202 var listeners = false; ;
20203 if (config && config.listeners) {
20204 listeners= config.listeners;
20205 delete config.listeners;
20207 Roo.apply(this, config);
20209 if(this.containerScroll){
20210 Roo.dd.ScrollManager.register(this.el);
20214 * @scope Roo.dd.DropTarget
20219 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20220 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20221 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20223 * IMPORTANT : it should set this.overClass and this.dropAllowed
20225 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20226 * @param {Event} e The event
20227 * @param {Object} data An object containing arbitrary data supplied by the drag source
20233 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20234 * This method will be called on every mouse movement while the drag source is over the drop target.
20235 * This default implementation simply returns the dropAllowed config value.
20237 * IMPORTANT : it should set this.dropAllowed
20239 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20240 * @param {Event} e The event
20241 * @param {Object} data An object containing arbitrary data supplied by the drag source
20247 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20248 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20249 * overClass (if any) from the drop element.
20251 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20252 * @param {Event} e The event
20253 * @param {Object} data An object containing arbitrary data supplied by the drag source
20259 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20260 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20261 * implementation that does something to process the drop event and returns true so that the drag source's
20262 * repair action does not run.
20264 * IMPORTANT : it should set this.success
20266 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20267 * @param {Event} e The event
20268 * @param {Object} data An object containing arbitrary data supplied by the drag source
20274 Roo.dd.DropTarget.superclass.constructor.call( this,
20276 this.ddGroup || this.group,
20279 listeners : listeners || {}
20287 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20289 * @cfg {String} overClass
20290 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20293 * @cfg {String} ddGroup
20294 * The drag drop group to handle drop events for
20298 * @cfg {String} dropAllowed
20299 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20301 dropAllowed : "x-dd-drop-ok",
20303 * @cfg {String} dropNotAllowed
20304 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20306 dropNotAllowed : "x-dd-drop-nodrop",
20308 * @cfg {boolean} success
20309 * set this after drop listener..
20313 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20314 * if the drop point is valid for over/enter..
20321 isNotifyTarget : true,
20326 notifyEnter : function(dd, e, data)
20329 this.fireEvent('enter', dd, e, data);
20330 if(this.overClass){
20331 this.el.addClass(this.overClass);
20333 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20334 this.valid ? this.dropAllowed : this.dropNotAllowed
20341 notifyOver : function(dd, e, data)
20344 this.fireEvent('over', dd, e, data);
20345 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20346 this.valid ? this.dropAllowed : this.dropNotAllowed
20353 notifyOut : function(dd, e, data)
20355 this.fireEvent('out', dd, e, data);
20356 if(this.overClass){
20357 this.el.removeClass(this.overClass);
20364 notifyDrop : function(dd, e, data)
20366 this.success = false;
20367 this.fireEvent('drop', dd, e, data);
20368 return this.success;
20372 * Ext JS Library 1.1.1
20373 * Copyright(c) 2006-2007, Ext JS, LLC.
20375 * Originally Released Under LGPL - original licence link has changed is not relivant.
20378 * <script type="text/javascript">
20383 * @class Roo.dd.DragZone
20384 * @extends Roo.dd.DragSource
20385 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20386 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20388 * @param {String/HTMLElement/Element} el The container element
20389 * @param {Object} config
20391 Roo.dd.DragZone = function(el, config){
20392 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20393 if(this.containerScroll){
20394 Roo.dd.ScrollManager.register(this.el);
20398 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20400 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20401 * for auto scrolling during drag operations.
20404 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20405 * method after a failed drop (defaults to "c3daf9" - light blue)
20409 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20410 * for a valid target to drag based on the mouse down. Override this method
20411 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20412 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20413 * @param {EventObject} e The mouse down event
20414 * @return {Object} The dragData
20416 getDragData : function(e){
20417 return Roo.dd.Registry.getHandleFromEvent(e);
20421 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20422 * this.dragData.ddel
20423 * @param {Number} x The x position of the click on the dragged object
20424 * @param {Number} y The y position of the click on the dragged object
20425 * @return {Boolean} true to continue the drag, false to cancel
20427 onInitDrag : function(x, y){
20428 this.proxy.update(this.dragData.ddel.cloneNode(true));
20429 this.onStartDrag(x, y);
20434 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20436 afterRepair : function(){
20438 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20440 this.dragging = false;
20444 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20445 * the XY of this.dragData.ddel
20446 * @param {EventObject} e The mouse up event
20447 * @return {Array} The xy location (e.g. [100, 200])
20449 getRepairXY : function(e){
20450 return Roo.Element.fly(this.dragData.ddel).getXY();
20454 * Ext JS Library 1.1.1
20455 * Copyright(c) 2006-2007, Ext JS, LLC.
20457 * Originally Released Under LGPL - original licence link has changed is not relivant.
20460 * <script type="text/javascript">
20463 * @class Roo.dd.DropZone
20464 * @extends Roo.dd.DropTarget
20465 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20466 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20468 * @param {String/HTMLElement/Element} el The container element
20469 * @param {Object} config
20471 Roo.dd.DropZone = function(el, config){
20472 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20475 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20477 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20478 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20479 * provide your own custom lookup.
20480 * @param {Event} e The event
20481 * @return {Object} data The custom data
20483 getTargetFromEvent : function(e){
20484 return Roo.dd.Registry.getTargetFromEvent(e);
20488 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20489 * that it has registered. This method has no default implementation and should be overridden to provide
20490 * node-specific processing if necessary.
20491 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20492 * {@link #getTargetFromEvent} for this node)
20493 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20494 * @param {Event} e The event
20495 * @param {Object} data An object containing arbitrary data supplied by the drag source
20497 onNodeEnter : function(n, dd, e, data){
20502 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20503 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20504 * overridden to provide the proper feedback.
20505 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20506 * {@link #getTargetFromEvent} for this node)
20507 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20508 * @param {Event} e The event
20509 * @param {Object} data An object containing arbitrary data supplied by the drag source
20510 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20511 * underlying {@link Roo.dd.StatusProxy} can be updated
20513 onNodeOver : function(n, dd, e, data){
20514 return this.dropAllowed;
20518 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20519 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20520 * node-specific processing if necessary.
20521 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20522 * {@link #getTargetFromEvent} for this node)
20523 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20524 * @param {Event} e The event
20525 * @param {Object} data An object containing arbitrary data supplied by the drag source
20527 onNodeOut : function(n, dd, e, data){
20532 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20533 * the drop node. The default implementation returns false, so it should be overridden to provide the
20534 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20535 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20536 * {@link #getTargetFromEvent} for this node)
20537 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20538 * @param {Event} e The event
20539 * @param {Object} data An object containing arbitrary data supplied by the drag source
20540 * @return {Boolean} True if the drop was valid, else false
20542 onNodeDrop : function(n, dd, e, data){
20547 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20548 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20549 * it should be overridden to provide the proper feedback if necessary.
20550 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20551 * @param {Event} e The event
20552 * @param {Object} data An object containing arbitrary data supplied by the drag source
20553 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20554 * underlying {@link Roo.dd.StatusProxy} can be updated
20556 onContainerOver : function(dd, e, data){
20557 return this.dropNotAllowed;
20561 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20562 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20563 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20564 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20565 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20566 * @param {Event} e The event
20567 * @param {Object} data An object containing arbitrary data supplied by the drag source
20568 * @return {Boolean} True if the drop was valid, else false
20570 onContainerDrop : function(dd, e, data){
20575 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20576 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20577 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20578 * you should override this method and provide a custom implementation.
20579 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20580 * @param {Event} e The event
20581 * @param {Object} data An object containing arbitrary data supplied by the drag source
20582 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20583 * underlying {@link Roo.dd.StatusProxy} can be updated
20585 notifyEnter : function(dd, e, data){
20586 return this.dropNotAllowed;
20590 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20591 * This method will be called on every mouse movement while the drag source is over the drop zone.
20592 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20593 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20594 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20595 * registered node, it will call {@link #onContainerOver}.
20596 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20597 * @param {Event} e The event
20598 * @param {Object} data An object containing arbitrary data supplied by the drag source
20599 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20600 * underlying {@link Roo.dd.StatusProxy} can be updated
20602 notifyOver : function(dd, e, data){
20603 var n = this.getTargetFromEvent(e);
20604 if(!n){ // not over valid drop target
20605 if(this.lastOverNode){
20606 this.onNodeOut(this.lastOverNode, dd, e, data);
20607 this.lastOverNode = null;
20609 return this.onContainerOver(dd, e, data);
20611 if(this.lastOverNode != n){
20612 if(this.lastOverNode){
20613 this.onNodeOut(this.lastOverNode, dd, e, data);
20615 this.onNodeEnter(n, dd, e, data);
20616 this.lastOverNode = n;
20618 return this.onNodeOver(n, dd, e, data);
20622 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20623 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20624 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20625 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20626 * @param {Event} e The event
20627 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20629 notifyOut : function(dd, e, data){
20630 if(this.lastOverNode){
20631 this.onNodeOut(this.lastOverNode, dd, e, data);
20632 this.lastOverNode = null;
20637 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20638 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20639 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20640 * otherwise it will call {@link #onContainerDrop}.
20641 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20642 * @param {Event} e The event
20643 * @param {Object} data An object containing arbitrary data supplied by the drag source
20644 * @return {Boolean} True if the drop was valid, else false
20646 notifyDrop : function(dd, e, data){
20647 if(this.lastOverNode){
20648 this.onNodeOut(this.lastOverNode, dd, e, data);
20649 this.lastOverNode = null;
20651 var n = this.getTargetFromEvent(e);
20653 this.onNodeDrop(n, dd, e, data) :
20654 this.onContainerDrop(dd, e, data);
20658 triggerCacheRefresh : function(){
20659 Roo.dd.DDM.refreshCache(this.groups);
20663 * Ext JS Library 1.1.1
20664 * Copyright(c) 2006-2007, Ext JS, LLC.
20666 * Originally Released Under LGPL - original licence link has changed is not relivant.
20669 * <script type="text/javascript">
20674 * @class Roo.data.SortTypes
20676 * Defines the default sorting (casting?) comparison functions used when sorting data.
20678 Roo.data.SortTypes = {
20680 * Default sort that does nothing
20681 * @param {Mixed} s The value being converted
20682 * @return {Mixed} The comparison value
20684 none : function(s){
20689 * The regular expression used to strip tags
20693 stripTagsRE : /<\/?[^>]+>/gi,
20696 * Strips all HTML tags to sort on text only
20697 * @param {Mixed} s The value being converted
20698 * @return {String} The comparison value
20700 asText : function(s){
20701 return String(s).replace(this.stripTagsRE, "");
20705 * Strips all HTML tags to sort on text only - Case insensitive
20706 * @param {Mixed} s The value being converted
20707 * @return {String} The comparison value
20709 asUCText : function(s){
20710 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20714 * Case insensitive string
20715 * @param {Mixed} s The value being converted
20716 * @return {String} The comparison value
20718 asUCString : function(s) {
20719 return String(s).toUpperCase();
20724 * @param {Mixed} s The value being converted
20725 * @return {Number} The comparison value
20727 asDate : function(s) {
20731 if(s instanceof Date){
20732 return s.getTime();
20734 return Date.parse(String(s));
20739 * @param {Mixed} s The value being converted
20740 * @return {Float} The comparison value
20742 asFloat : function(s) {
20743 var val = parseFloat(String(s).replace(/,/g, ""));
20744 if(isNaN(val)) val = 0;
20750 * @param {Mixed} s The value being converted
20751 * @return {Number} The comparison value
20753 asInt : function(s) {
20754 var val = parseInt(String(s).replace(/,/g, ""));
20755 if(isNaN(val)) val = 0;
20760 * Ext JS Library 1.1.1
20761 * Copyright(c) 2006-2007, Ext JS, LLC.
20763 * Originally Released Under LGPL - original licence link has changed is not relivant.
20766 * <script type="text/javascript">
20770 * @class Roo.data.Record
20771 * Instances of this class encapsulate both record <em>definition</em> information, and record
20772 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20773 * to access Records cached in an {@link Roo.data.Store} object.<br>
20775 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20776 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20779 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20781 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20782 * {@link #create}. The parameters are the same.
20783 * @param {Array} data An associative Array of data values keyed by the field name.
20784 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20785 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20786 * not specified an integer id is generated.
20788 Roo.data.Record = function(data, id){
20789 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20794 * Generate a constructor for a specific record layout.
20795 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20796 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20797 * Each field definition object may contain the following properties: <ul>
20798 * <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,
20799 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20800 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20801 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20802 * is being used, then this is a string containing the javascript expression to reference the data relative to
20803 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20804 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20805 * this may be omitted.</p></li>
20806 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20807 * <ul><li>auto (Default, implies no conversion)</li>
20812 * <li>date</li></ul></p></li>
20813 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20814 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20815 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20816 * by the Reader into an object that will be stored in the Record. It is passed the
20817 * following parameters:<ul>
20818 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20820 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20822 * <br>usage:<br><pre><code>
20823 var TopicRecord = Roo.data.Record.create(
20824 {name: 'title', mapping: 'topic_title'},
20825 {name: 'author', mapping: 'username'},
20826 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20827 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20828 {name: 'lastPoster', mapping: 'user2'},
20829 {name: 'excerpt', mapping: 'post_text'}
20832 var myNewRecord = new TopicRecord({
20833 title: 'Do my job please',
20836 lastPost: new Date(),
20837 lastPoster: 'Animal',
20838 excerpt: 'No way dude!'
20840 myStore.add(myNewRecord);
20845 Roo.data.Record.create = function(o){
20846 var f = function(){
20847 f.superclass.constructor.apply(this, arguments);
20849 Roo.extend(f, Roo.data.Record);
20850 var p = f.prototype;
20851 p.fields = new Roo.util.MixedCollection(false, function(field){
20854 for(var i = 0, len = o.length; i < len; i++){
20855 p.fields.add(new Roo.data.Field(o[i]));
20857 f.getField = function(name){
20858 return p.fields.get(name);
20863 Roo.data.Record.AUTO_ID = 1000;
20864 Roo.data.Record.EDIT = 'edit';
20865 Roo.data.Record.REJECT = 'reject';
20866 Roo.data.Record.COMMIT = 'commit';
20868 Roo.data.Record.prototype = {
20870 * Readonly flag - true if this record has been modified.
20879 join : function(store){
20880 this.store = store;
20884 * Set the named field to the specified value.
20885 * @param {String} name The name of the field to set.
20886 * @param {Object} value The value to set the field to.
20888 set : function(name, value){
20889 if(this.data[name] == value){
20893 if(!this.modified){
20894 this.modified = {};
20896 if(typeof this.modified[name] == 'undefined'){
20897 this.modified[name] = this.data[name];
20899 this.data[name] = value;
20900 if(!this.editing && this.store){
20901 this.store.afterEdit(this);
20906 * Get the value of the named field.
20907 * @param {String} name The name of the field to get the value of.
20908 * @return {Object} The value of the field.
20910 get : function(name){
20911 return this.data[name];
20915 beginEdit : function(){
20916 this.editing = true;
20917 this.modified = {};
20921 cancelEdit : function(){
20922 this.editing = false;
20923 delete this.modified;
20927 endEdit : function(){
20928 this.editing = false;
20929 if(this.dirty && this.store){
20930 this.store.afterEdit(this);
20935 * Usually called by the {@link Roo.data.Store} which owns the Record.
20936 * Rejects all changes made to the Record since either creation, or the last commit operation.
20937 * Modified fields are reverted to their original values.
20939 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20940 * of reject operations.
20942 reject : function(){
20943 var m = this.modified;
20945 if(typeof m[n] != "function"){
20946 this.data[n] = m[n];
20949 this.dirty = false;
20950 delete this.modified;
20951 this.editing = false;
20953 this.store.afterReject(this);
20958 * Usually called by the {@link Roo.data.Store} which owns the Record.
20959 * Commits all changes made to the Record since either creation, or the last commit operation.
20961 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20962 * of commit operations.
20964 commit : function(){
20965 this.dirty = false;
20966 delete this.modified;
20967 this.editing = false;
20969 this.store.afterCommit(this);
20974 hasError : function(){
20975 return this.error != null;
20979 clearError : function(){
20984 * Creates a copy of this record.
20985 * @param {String} id (optional) A new record id if you don't want to use this record's id
20988 copy : function(newId) {
20989 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
20993 * Ext JS Library 1.1.1
20994 * Copyright(c) 2006-2007, Ext JS, LLC.
20996 * Originally Released Under LGPL - original licence link has changed is not relivant.
20999 * <script type="text/javascript">
21005 * @class Roo.data.Store
21006 * @extends Roo.util.Observable
21007 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21008 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21010 * 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
21011 * has no knowledge of the format of the data returned by the Proxy.<br>
21013 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21014 * instances from the data object. These records are cached and made available through accessor functions.
21016 * Creates a new Store.
21017 * @param {Object} config A config object containing the objects needed for the Store to access data,
21018 * and read the data into Records.
21020 Roo.data.Store = function(config){
21021 this.data = new Roo.util.MixedCollection(false);
21022 this.data.getKey = function(o){
21025 this.baseParams = {};
21027 this.paramNames = {
21032 "multisort" : "_multisort"
21035 if(config && config.data){
21036 this.inlineData = config.data;
21037 delete config.data;
21040 Roo.apply(this, config);
21042 if(this.reader){ // reader passed
21043 this.reader = Roo.factory(this.reader, Roo.data);
21044 this.reader.xmodule = this.xmodule || false;
21045 if(!this.recordType){
21046 this.recordType = this.reader.recordType;
21048 if(this.reader.onMetaChange){
21049 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21053 if(this.recordType){
21054 this.fields = this.recordType.prototype.fields;
21056 this.modified = [];
21060 * @event datachanged
21061 * Fires when the data cache has changed, and a widget which is using this Store
21062 * as a Record cache should refresh its view.
21063 * @param {Store} this
21065 datachanged : true,
21067 * @event metachange
21068 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21069 * @param {Store} this
21070 * @param {Object} meta The JSON metadata
21075 * Fires when Records have been added to the Store
21076 * @param {Store} this
21077 * @param {Roo.data.Record[]} records The array of Records added
21078 * @param {Number} index The index at which the record(s) were added
21083 * Fires when a Record has been removed from the Store
21084 * @param {Store} this
21085 * @param {Roo.data.Record} record The Record that was removed
21086 * @param {Number} index The index at which the record was removed
21091 * Fires when a Record has been updated
21092 * @param {Store} this
21093 * @param {Roo.data.Record} record The Record that was updated
21094 * @param {String} operation The update operation being performed. Value may be one of:
21096 Roo.data.Record.EDIT
21097 Roo.data.Record.REJECT
21098 Roo.data.Record.COMMIT
21104 * Fires when the data cache has been cleared.
21105 * @param {Store} this
21109 * @event beforeload
21110 * Fires before a request is made for a new data object. If the beforeload handler returns false
21111 * the load action will be canceled.
21112 * @param {Store} this
21113 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21117 * @event beforeloadadd
21118 * Fires after a new set of Records has been loaded.
21119 * @param {Store} this
21120 * @param {Roo.data.Record[]} records The Records that were loaded
21121 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21123 beforeloadadd : true,
21126 * Fires after a new set of Records has been loaded, before they are added to the store.
21127 * @param {Store} this
21128 * @param {Roo.data.Record[]} records The Records that were loaded
21129 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21130 * @params {Object} return from reader
21134 * @event loadexception
21135 * Fires if an exception occurs in the Proxy during loading.
21136 * Called with the signature of the Proxy's "loadexception" event.
21137 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21140 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21141 * @param {Object} load options
21142 * @param {Object} jsonData from your request (normally this contains the Exception)
21144 loadexception : true
21148 this.proxy = Roo.factory(this.proxy, Roo.data);
21149 this.proxy.xmodule = this.xmodule || false;
21150 this.relayEvents(this.proxy, ["loadexception"]);
21152 this.sortToggle = {};
21153 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21155 Roo.data.Store.superclass.constructor.call(this);
21157 if(this.inlineData){
21158 this.loadData(this.inlineData);
21159 delete this.inlineData;
21163 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21165 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21166 * without a remote query - used by combo/forms at present.
21170 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21173 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21176 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21177 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21180 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21181 * on any HTTP request
21184 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21187 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21191 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21192 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21194 remoteSort : false,
21197 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21198 * loaded or when a record is removed. (defaults to false).
21200 pruneModifiedRecords : false,
21203 lastOptions : null,
21206 * Add Records to the Store and fires the add event.
21207 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21209 add : function(records){
21210 records = [].concat(records);
21211 for(var i = 0, len = records.length; i < len; i++){
21212 records[i].join(this);
21214 var index = this.data.length;
21215 this.data.addAll(records);
21216 this.fireEvent("add", this, records, index);
21220 * Remove a Record from the Store and fires the remove event.
21221 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21223 remove : function(record){
21224 var index = this.data.indexOf(record);
21225 this.data.removeAt(index);
21226 if(this.pruneModifiedRecords){
21227 this.modified.remove(record);
21229 this.fireEvent("remove", this, record, index);
21233 * Remove all Records from the Store and fires the clear event.
21235 removeAll : function(){
21237 if(this.pruneModifiedRecords){
21238 this.modified = [];
21240 this.fireEvent("clear", this);
21244 * Inserts Records to the Store at the given index and fires the add event.
21245 * @param {Number} index The start index at which to insert the passed Records.
21246 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21248 insert : function(index, records){
21249 records = [].concat(records);
21250 for(var i = 0, len = records.length; i < len; i++){
21251 this.data.insert(index, records[i]);
21252 records[i].join(this);
21254 this.fireEvent("add", this, records, index);
21258 * Get the index within the cache of the passed Record.
21259 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21260 * @return {Number} The index of the passed Record. Returns -1 if not found.
21262 indexOf : function(record){
21263 return this.data.indexOf(record);
21267 * Get the index within the cache of the Record with the passed id.
21268 * @param {String} id The id of the Record to find.
21269 * @return {Number} The index of the Record. Returns -1 if not found.
21271 indexOfId : function(id){
21272 return this.data.indexOfKey(id);
21276 * Get the Record with the specified id.
21277 * @param {String} id The id of the Record to find.
21278 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21280 getById : function(id){
21281 return this.data.key(id);
21285 * Get the Record at the specified index.
21286 * @param {Number} index The index of the Record to find.
21287 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21289 getAt : function(index){
21290 return this.data.itemAt(index);
21294 * Returns a range of Records between specified indices.
21295 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21296 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21297 * @return {Roo.data.Record[]} An array of Records
21299 getRange : function(start, end){
21300 return this.data.getRange(start, end);
21304 storeOptions : function(o){
21305 o = Roo.apply({}, o);
21308 this.lastOptions = o;
21312 * Loads the Record cache from the configured Proxy using the configured Reader.
21314 * If using remote paging, then the first load call must specify the <em>start</em>
21315 * and <em>limit</em> properties in the options.params property to establish the initial
21316 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21318 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21319 * and this call will return before the new data has been loaded. Perform any post-processing
21320 * in a callback function, or in a "load" event handler.</strong>
21322 * @param {Object} options An object containing properties which control loading options:<ul>
21323 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21324 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21325 * passed the following arguments:<ul>
21326 * <li>r : Roo.data.Record[]</li>
21327 * <li>options: Options object from the load call</li>
21328 * <li>success: Boolean success indicator</li></ul></li>
21329 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21330 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21333 load : function(options){
21334 options = options || {};
21335 if(this.fireEvent("beforeload", this, options) !== false){
21336 this.storeOptions(options);
21337 var p = Roo.apply(options.params || {}, this.baseParams);
21338 // if meta was not loaded from remote source.. try requesting it.
21339 if (!this.reader.metaFromRemote) {
21340 p._requestMeta = 1;
21342 if(this.sortInfo && this.remoteSort){
21343 var pn = this.paramNames;
21344 p[pn["sort"]] = this.sortInfo.field;
21345 p[pn["dir"]] = this.sortInfo.direction;
21347 if (this.multiSort) {
21348 var pn = this.paramNames;
21349 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21352 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21357 * Reloads the Record cache from the configured Proxy using the configured Reader and
21358 * the options from the last load operation performed.
21359 * @param {Object} options (optional) An object containing properties which may override the options
21360 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21361 * the most recently used options are reused).
21363 reload : function(options){
21364 this.load(Roo.applyIf(options||{}, this.lastOptions));
21368 // Called as a callback by the Reader during a load operation.
21369 loadRecords : function(o, options, success){
21370 if(!o || success === false){
21371 if(success !== false){
21372 this.fireEvent("load", this, [], options, o);
21374 if(options.callback){
21375 options.callback.call(options.scope || this, [], options, false);
21379 // if data returned failure - throw an exception.
21380 if (o.success === false) {
21381 // show a message if no listener is registered.
21382 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21383 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21385 // loadmask wil be hooked into this..
21386 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21389 var r = o.records, t = o.totalRecords || r.length;
21391 this.fireEvent("beforeloadadd", this, r, options, o);
21393 if(!options || options.add !== true){
21394 if(this.pruneModifiedRecords){
21395 this.modified = [];
21397 for(var i = 0, len = r.length; i < len; i++){
21401 this.data = this.snapshot;
21402 delete this.snapshot;
21405 this.data.addAll(r);
21406 this.totalLength = t;
21408 this.fireEvent("datachanged", this);
21410 this.totalLength = Math.max(t, this.data.length+r.length);
21413 this.fireEvent("load", this, r, options, o);
21414 if(options.callback){
21415 options.callback.call(options.scope || this, r, options, true);
21421 * Loads data from a passed data block. A Reader which understands the format of the data
21422 * must have been configured in the constructor.
21423 * @param {Object} data The data block from which to read the Records. The format of the data expected
21424 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21425 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21427 loadData : function(o, append){
21428 var r = this.reader.readRecords(o);
21429 this.loadRecords(r, {add: append}, true);
21433 * Gets the number of cached records.
21435 * <em>If using paging, this may not be the total size of the dataset. If the data object
21436 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21437 * the data set size</em>
21439 getCount : function(){
21440 return this.data.length || 0;
21444 * Gets the total number of records in the dataset as returned by the server.
21446 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21447 * the dataset size</em>
21449 getTotalCount : function(){
21450 return this.totalLength || 0;
21454 * Returns the sort state of the Store as an object with two properties:
21456 field {String} The name of the field by which the Records are sorted
21457 direction {String} The sort order, "ASC" or "DESC"
21460 getSortState : function(){
21461 return this.sortInfo;
21465 applySort : function(){
21466 if(this.sortInfo && !this.remoteSort){
21467 var s = this.sortInfo, f = s.field;
21468 var st = this.fields.get(f).sortType;
21469 var fn = function(r1, r2){
21470 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21471 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21473 this.data.sort(s.direction, fn);
21474 if(this.snapshot && this.snapshot != this.data){
21475 this.snapshot.sort(s.direction, fn);
21481 * Sets the default sort column and order to be used by the next load operation.
21482 * @param {String} fieldName The name of the field to sort by.
21483 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21485 setDefaultSort : function(field, dir){
21486 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21490 * Sort the Records.
21491 * If remote sorting is used, the sort is performed on the server, and the cache is
21492 * reloaded. If local sorting is used, the cache is sorted internally.
21493 * @param {String} fieldName The name of the field to sort by.
21494 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21496 sort : function(fieldName, dir){
21497 var f = this.fields.get(fieldName);
21499 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21501 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21502 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21507 this.sortToggle[f.name] = dir;
21508 this.sortInfo = {field: f.name, direction: dir};
21509 if(!this.remoteSort){
21511 this.fireEvent("datachanged", this);
21513 this.load(this.lastOptions);
21518 * Calls the specified function for each of the Records in the cache.
21519 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21520 * Returning <em>false</em> aborts and exits the iteration.
21521 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21523 each : function(fn, scope){
21524 this.data.each(fn, scope);
21528 * Gets all records modified since the last commit. Modified records are persisted across load operations
21529 * (e.g., during paging).
21530 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21532 getModifiedRecords : function(){
21533 return this.modified;
21537 createFilterFn : function(property, value, anyMatch){
21538 if(!value.exec){ // not a regex
21539 value = String(value);
21540 if(value.length == 0){
21543 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21545 return function(r){
21546 return value.test(r.data[property]);
21551 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21552 * @param {String} property A field on your records
21553 * @param {Number} start The record index to start at (defaults to 0)
21554 * @param {Number} end The last record index to include (defaults to length - 1)
21555 * @return {Number} The sum
21557 sum : function(property, start, end){
21558 var rs = this.data.items, v = 0;
21559 start = start || 0;
21560 end = (end || end === 0) ? end : rs.length-1;
21562 for(var i = start; i <= end; i++){
21563 v += (rs[i].data[property] || 0);
21569 * Filter the records by a specified property.
21570 * @param {String} field A field on your records
21571 * @param {String/RegExp} value Either a string that the field
21572 * should start with or a RegExp to test against the field
21573 * @param {Boolean} anyMatch True to match any part not just the beginning
21575 filter : function(property, value, anyMatch){
21576 var fn = this.createFilterFn(property, value, anyMatch);
21577 return fn ? this.filterBy(fn) : this.clearFilter();
21581 * Filter by a function. The specified function will be called with each
21582 * record in this data source. If the function returns true the record is included,
21583 * otherwise it is filtered.
21584 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21585 * @param {Object} scope (optional) The scope of the function (defaults to this)
21587 filterBy : function(fn, scope){
21588 this.snapshot = this.snapshot || this.data;
21589 this.data = this.queryBy(fn, scope||this);
21590 this.fireEvent("datachanged", this);
21594 * Query the records by a specified property.
21595 * @param {String} field A field on your records
21596 * @param {String/RegExp} value Either a string that the field
21597 * should start with or a RegExp to test against the field
21598 * @param {Boolean} anyMatch True to match any part not just the beginning
21599 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21601 query : function(property, value, anyMatch){
21602 var fn = this.createFilterFn(property, value, anyMatch);
21603 return fn ? this.queryBy(fn) : this.data.clone();
21607 * Query by a function. The specified function will be called with each
21608 * record in this data source. If the function returns true the record is included
21610 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21611 * @param {Object} scope (optional) The scope of the function (defaults to this)
21612 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21614 queryBy : function(fn, scope){
21615 var data = this.snapshot || this.data;
21616 return data.filterBy(fn, scope||this);
21620 * Collects unique values for a particular dataIndex from this store.
21621 * @param {String} dataIndex The property to collect
21622 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21623 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21624 * @return {Array} An array of the unique values
21626 collect : function(dataIndex, allowNull, bypassFilter){
21627 var d = (bypassFilter === true && this.snapshot) ?
21628 this.snapshot.items : this.data.items;
21629 var v, sv, r = [], l = {};
21630 for(var i = 0, len = d.length; i < len; i++){
21631 v = d[i].data[dataIndex];
21633 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21642 * Revert to a view of the Record cache with no filtering applied.
21643 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21645 clearFilter : function(suppressEvent){
21646 if(this.snapshot && this.snapshot != this.data){
21647 this.data = this.snapshot;
21648 delete this.snapshot;
21649 if(suppressEvent !== true){
21650 this.fireEvent("datachanged", this);
21656 afterEdit : function(record){
21657 if(this.modified.indexOf(record) == -1){
21658 this.modified.push(record);
21660 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21664 afterReject : function(record){
21665 this.modified.remove(record);
21666 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21670 afterCommit : function(record){
21671 this.modified.remove(record);
21672 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21676 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21677 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21679 commitChanges : function(){
21680 var m = this.modified.slice(0);
21681 this.modified = [];
21682 for(var i = 0, len = m.length; i < len; i++){
21688 * Cancel outstanding changes on all changed records.
21690 rejectChanges : function(){
21691 var m = this.modified.slice(0);
21692 this.modified = [];
21693 for(var i = 0, len = m.length; i < len; i++){
21698 onMetaChange : function(meta, rtype, o){
21699 this.recordType = rtype;
21700 this.fields = rtype.prototype.fields;
21701 delete this.snapshot;
21702 this.sortInfo = meta.sortInfo || this.sortInfo;
21703 this.modified = [];
21704 this.fireEvent('metachange', this, this.reader.meta);
21708 * Ext JS Library 1.1.1
21709 * Copyright(c) 2006-2007, Ext JS, LLC.
21711 * Originally Released Under LGPL - original licence link has changed is not relivant.
21714 * <script type="text/javascript">
21718 * @class Roo.data.SimpleStore
21719 * @extends Roo.data.Store
21720 * Small helper class to make creating Stores from Array data easier.
21721 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21722 * @cfg {Array} fields An array of field definition objects, or field name strings.
21723 * @cfg {Array} data The multi-dimensional array of data
21725 * @param {Object} config
21727 Roo.data.SimpleStore = function(config){
21728 Roo.data.SimpleStore.superclass.constructor.call(this, {
21730 reader: new Roo.data.ArrayReader({
21733 Roo.data.Record.create(config.fields)
21735 proxy : new Roo.data.MemoryProxy(config.data)
21739 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21741 * Ext JS Library 1.1.1
21742 * Copyright(c) 2006-2007, Ext JS, LLC.
21744 * Originally Released Under LGPL - original licence link has changed is not relivant.
21747 * <script type="text/javascript">
21752 * @extends Roo.data.Store
21753 * @class Roo.data.JsonStore
21754 * Small helper class to make creating Stores for JSON data easier. <br/>
21756 var store = new Roo.data.JsonStore({
21757 url: 'get-images.php',
21759 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21762 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21763 * JsonReader and HttpProxy (unless inline data is provided).</b>
21764 * @cfg {Array} fields An array of field definition objects, or field name strings.
21766 * @param {Object} config
21768 Roo.data.JsonStore = function(c){
21769 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21770 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21771 reader: new Roo.data.JsonReader(c, c.fields)
21774 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21776 * Ext JS Library 1.1.1
21777 * Copyright(c) 2006-2007, Ext JS, LLC.
21779 * Originally Released Under LGPL - original licence link has changed is not relivant.
21782 * <script type="text/javascript">
21786 Roo.data.Field = function(config){
21787 if(typeof config == "string"){
21788 config = {name: config};
21790 Roo.apply(this, config);
21793 this.type = "auto";
21796 var st = Roo.data.SortTypes;
21797 // named sortTypes are supported, here we look them up
21798 if(typeof this.sortType == "string"){
21799 this.sortType = st[this.sortType];
21802 // set default sortType for strings and dates
21803 if(!this.sortType){
21806 this.sortType = st.asUCString;
21809 this.sortType = st.asDate;
21812 this.sortType = st.none;
21817 var stripRe = /[\$,%]/g;
21819 // prebuilt conversion function for this field, instead of
21820 // switching every time we're reading a value
21822 var cv, dateFormat = this.dateFormat;
21827 cv = function(v){ return v; };
21830 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21834 return v !== undefined && v !== null && v !== '' ?
21835 parseInt(String(v).replace(stripRe, ""), 10) : '';
21840 return v !== undefined && v !== null && v !== '' ?
21841 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21846 cv = function(v){ return v === true || v === "true" || v == 1; };
21853 if(v instanceof Date){
21857 if(dateFormat == "timestamp"){
21858 return new Date(v*1000);
21860 return Date.parseDate(v, dateFormat);
21862 var parsed = Date.parse(v);
21863 return parsed ? new Date(parsed) : null;
21872 Roo.data.Field.prototype = {
21880 * Ext JS Library 1.1.1
21881 * Copyright(c) 2006-2007, Ext JS, LLC.
21883 * Originally Released Under LGPL - original licence link has changed is not relivant.
21886 * <script type="text/javascript">
21889 // Base class for reading structured data from a data source. This class is intended to be
21890 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
21893 * @class Roo.data.DataReader
21894 * Base class for reading structured data from a data source. This class is intended to be
21895 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
21898 Roo.data.DataReader = function(meta, recordType){
21902 this.recordType = recordType instanceof Array ?
21903 Roo.data.Record.create(recordType) : recordType;
21906 Roo.data.DataReader.prototype = {
21908 * Create an empty record
21909 * @param {Object} data (optional) - overlay some values
21910 * @return {Roo.data.Record} record created.
21912 newRow : function(d) {
21914 this.recordType.prototype.fields.each(function(c) {
21916 case 'int' : da[c.name] = 0; break;
21917 case 'date' : da[c.name] = new Date(); break;
21918 case 'float' : da[c.name] = 0.0; break;
21919 case 'boolean' : da[c.name] = false; break;
21920 default : da[c.name] = ""; break;
21924 return new this.recordType(Roo.apply(da, d));
21929 * Ext JS Library 1.1.1
21930 * Copyright(c) 2006-2007, Ext JS, LLC.
21932 * Originally Released Under LGPL - original licence link has changed is not relivant.
21935 * <script type="text/javascript">
21939 * @class Roo.data.DataProxy
21940 * @extends Roo.data.Observable
21941 * This class is an abstract base class for implementations which provide retrieval of
21942 * unformatted data objects.<br>
21944 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
21945 * (of the appropriate type which knows how to parse the data object) to provide a block of
21946 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
21948 * Custom implementations must implement the load method as described in
21949 * {@link Roo.data.HttpProxy#load}.
21951 Roo.data.DataProxy = function(){
21954 * @event beforeload
21955 * Fires before a network request is made to retrieve a data object.
21956 * @param {Object} This DataProxy object.
21957 * @param {Object} params The params parameter to the load function.
21962 * Fires before the load method's callback is called.
21963 * @param {Object} This DataProxy object.
21964 * @param {Object} o The data object.
21965 * @param {Object} arg The callback argument object passed to the load function.
21969 * @event loadexception
21970 * Fires if an Exception occurs during data retrieval.
21971 * @param {Object} This DataProxy object.
21972 * @param {Object} o The data object.
21973 * @param {Object} arg The callback argument object passed to the load function.
21974 * @param {Object} e The Exception.
21976 loadexception : true
21978 Roo.data.DataProxy.superclass.constructor.call(this);
21981 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
21984 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
21988 * Ext JS Library 1.1.1
21989 * Copyright(c) 2006-2007, Ext JS, LLC.
21991 * Originally Released Under LGPL - original licence link has changed is not relivant.
21994 * <script type="text/javascript">
21997 * @class Roo.data.MemoryProxy
21998 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
21999 * to the Reader when its load method is called.
22001 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22003 Roo.data.MemoryProxy = function(data){
22007 Roo.data.MemoryProxy.superclass.constructor.call(this);
22011 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22013 * Load data from the requested source (in this case an in-memory
22014 * data object passed to the constructor), read the data object into
22015 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22016 * process that block using the passed callback.
22017 * @param {Object} params This parameter is not used by the MemoryProxy class.
22018 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22019 * object into a block of Roo.data.Records.
22020 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22021 * The function must be passed <ul>
22022 * <li>The Record block object</li>
22023 * <li>The "arg" argument from the load function</li>
22024 * <li>A boolean success indicator</li>
22026 * @param {Object} scope The scope in which to call the callback
22027 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22029 load : function(params, reader, callback, scope, arg){
22030 params = params || {};
22033 result = reader.readRecords(this.data);
22035 this.fireEvent("loadexception", this, arg, null, e);
22036 callback.call(scope, null, arg, false);
22039 callback.call(scope, result, arg, true);
22043 update : function(params, records){
22048 * Ext JS Library 1.1.1
22049 * Copyright(c) 2006-2007, Ext JS, LLC.
22051 * Originally Released Under LGPL - original licence link has changed is not relivant.
22054 * <script type="text/javascript">
22057 * @class Roo.data.HttpProxy
22058 * @extends Roo.data.DataProxy
22059 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22060 * configured to reference a certain URL.<br><br>
22062 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22063 * from which the running page was served.<br><br>
22065 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22067 * Be aware that to enable the browser to parse an XML document, the server must set
22068 * the Content-Type header in the HTTP response to "text/xml".
22070 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22071 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22072 * will be used to make the request.
22074 Roo.data.HttpProxy = function(conn){
22075 Roo.data.HttpProxy.superclass.constructor.call(this);
22076 // is conn a conn config or a real conn?
22078 this.useAjax = !conn || !conn.events;
22082 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22083 // thse are take from connection...
22086 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22089 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22090 * extra parameters to each request made by this object. (defaults to undefined)
22093 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22094 * to each request made by this object. (defaults to undefined)
22097 * @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)
22100 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22103 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22109 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22113 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22114 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22115 * a finer-grained basis than the DataProxy events.
22117 getConnection : function(){
22118 return this.useAjax ? Roo.Ajax : this.conn;
22122 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22123 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22124 * process that block using the passed callback.
22125 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22126 * for the request to the remote server.
22127 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22128 * object into a block of Roo.data.Records.
22129 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22130 * The function must be passed <ul>
22131 * <li>The Record block object</li>
22132 * <li>The "arg" argument from the load function</li>
22133 * <li>A boolean success indicator</li>
22135 * @param {Object} scope The scope in which to call the callback
22136 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22138 load : function(params, reader, callback, scope, arg){
22139 if(this.fireEvent("beforeload", this, params) !== false){
22141 params : params || {},
22143 callback : callback,
22148 callback : this.loadResponse,
22152 Roo.applyIf(o, this.conn);
22153 if(this.activeRequest){
22154 Roo.Ajax.abort(this.activeRequest);
22156 this.activeRequest = Roo.Ajax.request(o);
22158 this.conn.request(o);
22161 callback.call(scope||this, null, arg, false);
22166 loadResponse : function(o, success, response){
22167 delete this.activeRequest;
22169 this.fireEvent("loadexception", this, o, response);
22170 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22175 result = o.reader.read(response);
22177 this.fireEvent("loadexception", this, o, response, e);
22178 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22182 this.fireEvent("load", this, o, o.request.arg);
22183 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22187 update : function(dataSet){
22192 updateResponse : function(dataSet){
22197 * Ext JS Library 1.1.1
22198 * Copyright(c) 2006-2007, Ext JS, LLC.
22200 * Originally Released Under LGPL - original licence link has changed is not relivant.
22203 * <script type="text/javascript">
22207 * @class Roo.data.ScriptTagProxy
22208 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22209 * other than the originating domain of the running page.<br><br>
22211 * <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
22212 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22214 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22215 * source code that is used as the source inside a <script> tag.<br><br>
22217 * In order for the browser to process the returned data, the server must wrap the data object
22218 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22219 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22220 * depending on whether the callback name was passed:
22223 boolean scriptTag = false;
22224 String cb = request.getParameter("callback");
22227 response.setContentType("text/javascript");
22229 response.setContentType("application/x-json");
22231 Writer out = response.getWriter();
22233 out.write(cb + "(");
22235 out.print(dataBlock.toJsonString());
22242 * @param {Object} config A configuration object.
22244 Roo.data.ScriptTagProxy = function(config){
22245 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22246 Roo.apply(this, config);
22247 this.head = document.getElementsByTagName("head")[0];
22250 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22252 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22254 * @cfg {String} url The URL from which to request the data object.
22257 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22261 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22262 * the server the name of the callback function set up by the load call to process the returned data object.
22263 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22264 * javascript output which calls this named function passing the data object as its only parameter.
22266 callbackParam : "callback",
22268 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22269 * name to the request.
22274 * Load data from the configured URL, read the data object into
22275 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22276 * process that block using the passed callback.
22277 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22278 * for the request to the remote server.
22279 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22280 * object into a block of Roo.data.Records.
22281 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22282 * The function must be passed <ul>
22283 * <li>The Record block object</li>
22284 * <li>The "arg" argument from the load function</li>
22285 * <li>A boolean success indicator</li>
22287 * @param {Object} scope The scope in which to call the callback
22288 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22290 load : function(params, reader, callback, scope, arg){
22291 if(this.fireEvent("beforeload", this, params) !== false){
22293 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22295 var url = this.url;
22296 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22298 url += "&_dc=" + (new Date().getTime());
22300 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22303 cb : "stcCallback"+transId,
22304 scriptId : "stcScript"+transId,
22308 callback : callback,
22314 window[trans.cb] = function(o){
22315 conn.handleResponse(o, trans);
22318 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22320 if(this.autoAbort !== false){
22324 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22326 var script = document.createElement("script");
22327 script.setAttribute("src", url);
22328 script.setAttribute("type", "text/javascript");
22329 script.setAttribute("id", trans.scriptId);
22330 this.head.appendChild(script);
22332 this.trans = trans;
22334 callback.call(scope||this, null, arg, false);
22339 isLoading : function(){
22340 return this.trans ? true : false;
22344 * Abort the current server request.
22346 abort : function(){
22347 if(this.isLoading()){
22348 this.destroyTrans(this.trans);
22353 destroyTrans : function(trans, isLoaded){
22354 this.head.removeChild(document.getElementById(trans.scriptId));
22355 clearTimeout(trans.timeoutId);
22357 window[trans.cb] = undefined;
22359 delete window[trans.cb];
22362 // if hasn't been loaded, wait for load to remove it to prevent script error
22363 window[trans.cb] = function(){
22364 window[trans.cb] = undefined;
22366 delete window[trans.cb];
22373 handleResponse : function(o, trans){
22374 this.trans = false;
22375 this.destroyTrans(trans, true);
22378 result = trans.reader.readRecords(o);
22380 this.fireEvent("loadexception", this, o, trans.arg, e);
22381 trans.callback.call(trans.scope||window, null, trans.arg, false);
22384 this.fireEvent("load", this, o, trans.arg);
22385 trans.callback.call(trans.scope||window, result, trans.arg, true);
22389 handleFailure : function(trans){
22390 this.trans = false;
22391 this.destroyTrans(trans, false);
22392 this.fireEvent("loadexception", this, null, trans.arg);
22393 trans.callback.call(trans.scope||window, null, trans.arg, false);
22397 * Ext JS Library 1.1.1
22398 * Copyright(c) 2006-2007, Ext JS, LLC.
22400 * Originally Released Under LGPL - original licence link has changed is not relivant.
22403 * <script type="text/javascript">
22407 * @class Roo.data.JsonReader
22408 * @extends Roo.data.DataReader
22409 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22410 * based on mappings in a provided Roo.data.Record constructor.
22412 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22413 * in the reply previously.
22418 var RecordDef = Roo.data.Record.create([
22419 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22420 {name: 'occupation'} // This field will use "occupation" as the mapping.
22422 var myReader = new Roo.data.JsonReader({
22423 totalProperty: "results", // The property which contains the total dataset size (optional)
22424 root: "rows", // The property which contains an Array of row objects
22425 id: "id" // The property within each row object that provides an ID for the record (optional)
22429 * This would consume a JSON file like this:
22431 { 'results': 2, 'rows': [
22432 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22433 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22436 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22437 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22438 * paged from the remote server.
22439 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22440 * @cfg {String} root name of the property which contains the Array of row objects.
22441 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22443 * Create a new JsonReader
22444 * @param {Object} meta Metadata configuration options
22445 * @param {Object} recordType Either an Array of field definition objects,
22446 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22448 Roo.data.JsonReader = function(meta, recordType){
22451 // set some defaults:
22452 Roo.applyIf(meta, {
22453 totalProperty: 'total',
22454 successProperty : 'success',
22459 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22461 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22464 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22465 * Used by Store query builder to append _requestMeta to params.
22468 metaFromRemote : false,
22470 * This method is only used by a DataProxy which has retrieved data from a remote server.
22471 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22472 * @return {Object} data A data block which is used by an Roo.data.Store object as
22473 * a cache of Roo.data.Records.
22475 read : function(response){
22476 var json = response.responseText;
22478 var o = /* eval:var:o */ eval("("+json+")");
22480 throw {message: "JsonReader.read: Json object not found"};
22486 this.metaFromRemote = true;
22487 this.meta = o.metaData;
22488 this.recordType = Roo.data.Record.create(o.metaData.fields);
22489 this.onMetaChange(this.meta, this.recordType, o);
22491 return this.readRecords(o);
22494 // private function a store will implement
22495 onMetaChange : function(meta, recordType, o){
22502 simpleAccess: function(obj, subsc) {
22509 getJsonAccessor: function(){
22511 return function(expr) {
22513 return(re.test(expr))
22514 ? new Function("obj", "return obj." + expr)
22519 return Roo.emptyFn;
22524 * Create a data block containing Roo.data.Records from an XML document.
22525 * @param {Object} o An object which contains an Array of row objects in the property specified
22526 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22527 * which contains the total size of the dataset.
22528 * @return {Object} data A data block which is used by an Roo.data.Store object as
22529 * a cache of Roo.data.Records.
22531 readRecords : function(o){
22533 * After any data loads, the raw JSON data is available for further custom processing.
22537 var s = this.meta, Record = this.recordType,
22538 f = Record.prototype.fields, fi = f.items, fl = f.length;
22540 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22542 if(s.totalProperty) {
22543 this.getTotal = this.getJsonAccessor(s.totalProperty);
22545 if(s.successProperty) {
22546 this.getSuccess = this.getJsonAccessor(s.successProperty);
22548 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22550 var g = this.getJsonAccessor(s.id);
22551 this.getId = function(rec) {
22553 return (r === undefined || r === "") ? null : r;
22556 this.getId = function(){return null;};
22559 for(var jj = 0; jj < fl; jj++){
22561 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22562 this.ef[jj] = this.getJsonAccessor(map);
22566 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22567 if(s.totalProperty){
22568 var vt = parseInt(this.getTotal(o), 10);
22573 if(s.successProperty){
22574 var vs = this.getSuccess(o);
22575 if(vs === false || vs === 'false'){
22580 for(var i = 0; i < c; i++){
22583 var id = this.getId(n);
22584 for(var j = 0; j < fl; j++){
22586 var v = this.ef[j](n);
22588 Roo.log('missing convert for ' + f.name);
22592 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22594 var record = new Record(values, id);
22596 records[i] = record;
22602 totalRecords : totalRecords
22607 * Ext JS Library 1.1.1
22608 * Copyright(c) 2006-2007, Ext JS, LLC.
22610 * Originally Released Under LGPL - original licence link has changed is not relivant.
22613 * <script type="text/javascript">
22617 * @class Roo.data.XmlReader
22618 * @extends Roo.data.DataReader
22619 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22620 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22622 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22623 * header in the HTTP response must be set to "text/xml".</em>
22627 var RecordDef = Roo.data.Record.create([
22628 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22629 {name: 'occupation'} // This field will use "occupation" as the mapping.
22631 var myReader = new Roo.data.XmlReader({
22632 totalRecords: "results", // The element which contains the total dataset size (optional)
22633 record: "row", // The repeated element which contains row information
22634 id: "id" // The element within the row that provides an ID for the record (optional)
22638 * This would consume an XML file like this:
22642 <results>2</results>
22645 <name>Bill</name>
22646 <occupation>Gardener</occupation>
22650 <name>Ben</name>
22651 <occupation>Horticulturalist</occupation>
22655 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22656 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22657 * paged from the remote server.
22658 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22659 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22660 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22661 * a record identifier value.
22663 * Create a new XmlReader
22664 * @param {Object} meta Metadata configuration options
22665 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22666 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22667 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22669 Roo.data.XmlReader = function(meta, recordType){
22671 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22673 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22675 * This method is only used by a DataProxy which has retrieved data from a remote server.
22676 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22677 * to contain a method called 'responseXML' that returns an XML document object.
22678 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22679 * a cache of Roo.data.Records.
22681 read : function(response){
22682 var doc = response.responseXML;
22684 throw {message: "XmlReader.read: XML Document not available"};
22686 return this.readRecords(doc);
22690 * Create a data block containing Roo.data.Records from an XML document.
22691 * @param {Object} doc A parsed XML document.
22692 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22693 * a cache of Roo.data.Records.
22695 readRecords : function(doc){
22697 * After any data loads/reads, the raw XML Document is available for further custom processing.
22698 * @type XMLDocument
22700 this.xmlData = doc;
22701 var root = doc.documentElement || doc;
22702 var q = Roo.DomQuery;
22703 var recordType = this.recordType, fields = recordType.prototype.fields;
22704 var sid = this.meta.id;
22705 var totalRecords = 0, success = true;
22706 if(this.meta.totalRecords){
22707 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22710 if(this.meta.success){
22711 var sv = q.selectValue(this.meta.success, root, true);
22712 success = sv !== false && sv !== 'false';
22715 var ns = q.select(this.meta.record, root);
22716 for(var i = 0, len = ns.length; i < len; i++) {
22719 var id = sid ? q.selectValue(sid, n) : undefined;
22720 for(var j = 0, jlen = fields.length; j < jlen; j++){
22721 var f = fields.items[j];
22722 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22724 values[f.name] = v;
22726 var record = new recordType(values, id);
22728 records[records.length] = record;
22734 totalRecords : totalRecords || records.length
22739 * Ext JS Library 1.1.1
22740 * Copyright(c) 2006-2007, Ext JS, LLC.
22742 * Originally Released Under LGPL - original licence link has changed is not relivant.
22745 * <script type="text/javascript">
22749 * @class Roo.data.ArrayReader
22750 * @extends Roo.data.DataReader
22751 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22752 * Each element of that Array represents a row of data fields. The
22753 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22754 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22758 var RecordDef = Roo.data.Record.create([
22759 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22760 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22762 var myReader = new Roo.data.ArrayReader({
22763 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22767 * This would consume an Array like this:
22769 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22771 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22773 * Create a new JsonReader
22774 * @param {Object} meta Metadata configuration options.
22775 * @param {Object} recordType Either an Array of field definition objects
22776 * as specified to {@link Roo.data.Record#create},
22777 * or an {@link Roo.data.Record} object
22778 * created using {@link Roo.data.Record#create}.
22780 Roo.data.ArrayReader = function(meta, recordType){
22781 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22784 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22786 * Create a data block containing Roo.data.Records from an XML document.
22787 * @param {Object} o An Array of row objects which represents the dataset.
22788 * @return {Object} data A data block which is used by an Roo.data.Store object as
22789 * a cache of Roo.data.Records.
22791 readRecords : function(o){
22792 var sid = this.meta ? this.meta.id : null;
22793 var recordType = this.recordType, fields = recordType.prototype.fields;
22796 for(var i = 0; i < root.length; i++){
22799 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22800 for(var j = 0, jlen = fields.length; j < jlen; j++){
22801 var f = fields.items[j];
22802 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22803 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22805 values[f.name] = v;
22807 var record = new recordType(values, id);
22809 records[records.length] = record;
22813 totalRecords : records.length
22818 * Ext JS Library 1.1.1
22819 * Copyright(c) 2006-2007, Ext JS, LLC.
22821 * Originally Released Under LGPL - original licence link has changed is not relivant.
22824 * <script type="text/javascript">
22829 * @class Roo.data.Tree
22830 * @extends Roo.util.Observable
22831 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22832 * in the tree have most standard DOM functionality.
22834 * @param {Node} root (optional) The root node
22836 Roo.data.Tree = function(root){
22837 this.nodeHash = {};
22839 * The root node for this tree
22844 this.setRootNode(root);
22849 * Fires when a new child node is appended to a node in this tree.
22850 * @param {Tree} tree The owner tree
22851 * @param {Node} parent The parent node
22852 * @param {Node} node The newly appended node
22853 * @param {Number} index The index of the newly appended node
22858 * Fires when a child node is removed from a node in this tree.
22859 * @param {Tree} tree The owner tree
22860 * @param {Node} parent The parent node
22861 * @param {Node} node The child node removed
22866 * Fires when a node is moved to a new location in the tree
22867 * @param {Tree} tree The owner tree
22868 * @param {Node} node The node moved
22869 * @param {Node} oldParent The old parent of this node
22870 * @param {Node} newParent The new parent of this node
22871 * @param {Number} index The index it was moved to
22876 * Fires when a new child node is inserted in a node in this tree.
22877 * @param {Tree} tree The owner tree
22878 * @param {Node} parent The parent node
22879 * @param {Node} node The child node inserted
22880 * @param {Node} refNode The child node the node was inserted before
22884 * @event beforeappend
22885 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
22886 * @param {Tree} tree The owner tree
22887 * @param {Node} parent The parent node
22888 * @param {Node} node The child node to be appended
22890 "beforeappend" : true,
22892 * @event beforeremove
22893 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
22894 * @param {Tree} tree The owner tree
22895 * @param {Node} parent The parent node
22896 * @param {Node} node The child node to be removed
22898 "beforeremove" : true,
22900 * @event beforemove
22901 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
22902 * @param {Tree} tree The owner tree
22903 * @param {Node} node The node being moved
22904 * @param {Node} oldParent The parent of the node
22905 * @param {Node} newParent The new parent the node is moving to
22906 * @param {Number} index The index it is being moved to
22908 "beforemove" : true,
22910 * @event beforeinsert
22911 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
22912 * @param {Tree} tree The owner tree
22913 * @param {Node} parent The parent node
22914 * @param {Node} node The child node to be inserted
22915 * @param {Node} refNode The child node the node is being inserted before
22917 "beforeinsert" : true
22920 Roo.data.Tree.superclass.constructor.call(this);
22923 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
22924 pathSeparator: "/",
22926 proxyNodeEvent : function(){
22927 return this.fireEvent.apply(this, arguments);
22931 * Returns the root node for this tree.
22934 getRootNode : function(){
22939 * Sets the root node for this tree.
22940 * @param {Node} node
22943 setRootNode : function(node){
22945 node.ownerTree = this;
22946 node.isRoot = true;
22947 this.registerNode(node);
22952 * Gets a node in this tree by its id.
22953 * @param {String} id
22956 getNodeById : function(id){
22957 return this.nodeHash[id];
22960 registerNode : function(node){
22961 this.nodeHash[node.id] = node;
22964 unregisterNode : function(node){
22965 delete this.nodeHash[node.id];
22968 toString : function(){
22969 return "[Tree"+(this.id?" "+this.id:"")+"]";
22974 * @class Roo.data.Node
22975 * @extends Roo.util.Observable
22976 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
22977 * @cfg {String} id The id for this node. If one is not specified, one is generated.
22979 * @param {Object} attributes The attributes/config for the node
22981 Roo.data.Node = function(attributes){
22983 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
22986 this.attributes = attributes || {};
22987 this.leaf = this.attributes.leaf;
22989 * The node id. @type String
22991 this.id = this.attributes.id;
22993 this.id = Roo.id(null, "ynode-");
22994 this.attributes.id = this.id;
22999 * All child nodes of this node. @type Array
23001 this.childNodes = [];
23002 if(!this.childNodes.indexOf){ // indexOf is a must
23003 this.childNodes.indexOf = function(o){
23004 for(var i = 0, len = this.length; i < len; i++){
23013 * The parent node for this node. @type Node
23015 this.parentNode = null;
23017 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23019 this.firstChild = null;
23021 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23023 this.lastChild = null;
23025 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23027 this.previousSibling = null;
23029 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23031 this.nextSibling = null;
23036 * Fires when a new child node is appended
23037 * @param {Tree} tree The owner tree
23038 * @param {Node} this This node
23039 * @param {Node} node The newly appended node
23040 * @param {Number} index The index of the newly appended node
23045 * Fires when a child node is removed
23046 * @param {Tree} tree The owner tree
23047 * @param {Node} this This node
23048 * @param {Node} node The removed node
23053 * Fires when this node is moved to a new location in the tree
23054 * @param {Tree} tree The owner tree
23055 * @param {Node} this This node
23056 * @param {Node} oldParent The old parent of this node
23057 * @param {Node} newParent The new parent of this node
23058 * @param {Number} index The index it was moved to
23063 * Fires when a new child node is inserted.
23064 * @param {Tree} tree The owner tree
23065 * @param {Node} this This node
23066 * @param {Node} node The child node inserted
23067 * @param {Node} refNode The child node the node was inserted before
23071 * @event beforeappend
23072 * Fires before a new child is appended, return false to cancel the append.
23073 * @param {Tree} tree The owner tree
23074 * @param {Node} this This node
23075 * @param {Node} node The child node to be appended
23077 "beforeappend" : true,
23079 * @event beforeremove
23080 * Fires before a child is removed, return false to cancel the remove.
23081 * @param {Tree} tree The owner tree
23082 * @param {Node} this This node
23083 * @param {Node} node The child node to be removed
23085 "beforeremove" : true,
23087 * @event beforemove
23088 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23089 * @param {Tree} tree The owner tree
23090 * @param {Node} this This node
23091 * @param {Node} oldParent The parent of this node
23092 * @param {Node} newParent The new parent this node is moving to
23093 * @param {Number} index The index it is being moved to
23095 "beforemove" : true,
23097 * @event beforeinsert
23098 * Fires before a new child is inserted, return false to cancel the insert.
23099 * @param {Tree} tree The owner tree
23100 * @param {Node} this This node
23101 * @param {Node} node The child node to be inserted
23102 * @param {Node} refNode The child node the node is being inserted before
23104 "beforeinsert" : true
23106 this.listeners = this.attributes.listeners;
23107 Roo.data.Node.superclass.constructor.call(this);
23110 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23111 fireEvent : function(evtName){
23112 // first do standard event for this node
23113 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23116 // then bubble it up to the tree if the event wasn't cancelled
23117 var ot = this.getOwnerTree();
23119 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23127 * Returns true if this node is a leaf
23128 * @return {Boolean}
23130 isLeaf : function(){
23131 return this.leaf === true;
23135 setFirstChild : function(node){
23136 this.firstChild = node;
23140 setLastChild : function(node){
23141 this.lastChild = node;
23146 * Returns true if this node is the last child of its parent
23147 * @return {Boolean}
23149 isLast : function(){
23150 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23154 * Returns true if this node is the first child of its parent
23155 * @return {Boolean}
23157 isFirst : function(){
23158 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23161 hasChildNodes : function(){
23162 return !this.isLeaf() && this.childNodes.length > 0;
23166 * Insert node(s) as the last child node of this node.
23167 * @param {Node/Array} node The node or Array of nodes to append
23168 * @return {Node} The appended node if single append, or null if an array was passed
23170 appendChild : function(node){
23172 if(node instanceof Array){
23174 }else if(arguments.length > 1){
23177 // if passed an array or multiple args do them one by one
23179 for(var i = 0, len = multi.length; i < len; i++) {
23180 this.appendChild(multi[i]);
23183 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23186 var index = this.childNodes.length;
23187 var oldParent = node.parentNode;
23188 // it's a move, make sure we move it cleanly
23190 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23193 oldParent.removeChild(node);
23195 index = this.childNodes.length;
23197 this.setFirstChild(node);
23199 this.childNodes.push(node);
23200 node.parentNode = this;
23201 var ps = this.childNodes[index-1];
23203 node.previousSibling = ps;
23204 ps.nextSibling = node;
23206 node.previousSibling = null;
23208 node.nextSibling = null;
23209 this.setLastChild(node);
23210 node.setOwnerTree(this.getOwnerTree());
23211 this.fireEvent("append", this.ownerTree, this, node, index);
23213 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23220 * Removes a child node from this node.
23221 * @param {Node} node The node to remove
23222 * @return {Node} The removed node
23224 removeChild : function(node){
23225 var index = this.childNodes.indexOf(node);
23229 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23233 // remove it from childNodes collection
23234 this.childNodes.splice(index, 1);
23237 if(node.previousSibling){
23238 node.previousSibling.nextSibling = node.nextSibling;
23240 if(node.nextSibling){
23241 node.nextSibling.previousSibling = node.previousSibling;
23244 // update child refs
23245 if(this.firstChild == node){
23246 this.setFirstChild(node.nextSibling);
23248 if(this.lastChild == node){
23249 this.setLastChild(node.previousSibling);
23252 node.setOwnerTree(null);
23253 // clear any references from the node
23254 node.parentNode = null;
23255 node.previousSibling = null;
23256 node.nextSibling = null;
23257 this.fireEvent("remove", this.ownerTree, this, node);
23262 * Inserts the first node before the second node in this nodes childNodes collection.
23263 * @param {Node} node The node to insert
23264 * @param {Node} refNode The node to insert before (if null the node is appended)
23265 * @return {Node} The inserted node
23267 insertBefore : function(node, refNode){
23268 if(!refNode){ // like standard Dom, refNode can be null for append
23269 return this.appendChild(node);
23272 if(node == refNode){
23276 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23279 var index = this.childNodes.indexOf(refNode);
23280 var oldParent = node.parentNode;
23281 var refIndex = index;
23283 // when moving internally, indexes will change after remove
23284 if(oldParent == this && this.childNodes.indexOf(node) < index){
23288 // it's a move, make sure we move it cleanly
23290 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23293 oldParent.removeChild(node);
23296 this.setFirstChild(node);
23298 this.childNodes.splice(refIndex, 0, node);
23299 node.parentNode = this;
23300 var ps = this.childNodes[refIndex-1];
23302 node.previousSibling = ps;
23303 ps.nextSibling = node;
23305 node.previousSibling = null;
23307 node.nextSibling = refNode;
23308 refNode.previousSibling = node;
23309 node.setOwnerTree(this.getOwnerTree());
23310 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23312 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23318 * Returns the child node at the specified index.
23319 * @param {Number} index
23322 item : function(index){
23323 return this.childNodes[index];
23327 * Replaces one child node in this node with another.
23328 * @param {Node} newChild The replacement node
23329 * @param {Node} oldChild The node to replace
23330 * @return {Node} The replaced node
23332 replaceChild : function(newChild, oldChild){
23333 this.insertBefore(newChild, oldChild);
23334 this.removeChild(oldChild);
23339 * Returns the index of a child node
23340 * @param {Node} node
23341 * @return {Number} The index of the node or -1 if it was not found
23343 indexOf : function(child){
23344 return this.childNodes.indexOf(child);
23348 * Returns the tree this node is in.
23351 getOwnerTree : function(){
23352 // if it doesn't have one, look for one
23353 if(!this.ownerTree){
23357 this.ownerTree = p.ownerTree;
23363 return this.ownerTree;
23367 * Returns depth of this node (the root node has a depth of 0)
23370 getDepth : function(){
23373 while(p.parentNode){
23381 setOwnerTree : function(tree){
23382 // if it's move, we need to update everyone
23383 if(tree != this.ownerTree){
23384 if(this.ownerTree){
23385 this.ownerTree.unregisterNode(this);
23387 this.ownerTree = tree;
23388 var cs = this.childNodes;
23389 for(var i = 0, len = cs.length; i < len; i++) {
23390 cs[i].setOwnerTree(tree);
23393 tree.registerNode(this);
23399 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23400 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23401 * @return {String} The path
23403 getPath : function(attr){
23404 attr = attr || "id";
23405 var p = this.parentNode;
23406 var b = [this.attributes[attr]];
23408 b.unshift(p.attributes[attr]);
23411 var sep = this.getOwnerTree().pathSeparator;
23412 return sep + b.join(sep);
23416 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23417 * function call will be the scope provided or the current node. The arguments to the function
23418 * will be the args provided or the current node. If the function returns false at any point,
23419 * the bubble is stopped.
23420 * @param {Function} fn The function to call
23421 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23422 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23424 bubble : function(fn, scope, args){
23427 if(fn.call(scope || p, args || p) === false){
23435 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23436 * function call will be the scope provided or the current node. The arguments to the function
23437 * will be the args provided or the current node. If the function returns false at any point,
23438 * the cascade is stopped on that branch.
23439 * @param {Function} fn The function to call
23440 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23441 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23443 cascade : function(fn, scope, args){
23444 if(fn.call(scope || this, args || this) !== false){
23445 var cs = this.childNodes;
23446 for(var i = 0, len = cs.length; i < len; i++) {
23447 cs[i].cascade(fn, scope, args);
23453 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23454 * function call will be the scope provided or the current node. The arguments to the function
23455 * will be the args provided or the current node. If the function returns false at any point,
23456 * the iteration stops.
23457 * @param {Function} fn The function to call
23458 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23459 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23461 eachChild : function(fn, scope, args){
23462 var cs = this.childNodes;
23463 for(var i = 0, len = cs.length; i < len; i++) {
23464 if(fn.call(scope || this, args || cs[i]) === false){
23471 * Finds the first child that has the attribute with the specified value.
23472 * @param {String} attribute The attribute name
23473 * @param {Mixed} value The value to search for
23474 * @return {Node} The found child or null if none was found
23476 findChild : function(attribute, value){
23477 var cs = this.childNodes;
23478 for(var i = 0, len = cs.length; i < len; i++) {
23479 if(cs[i].attributes[attribute] == value){
23487 * Finds the first child by a custom function. The child matches if the function passed
23489 * @param {Function} fn
23490 * @param {Object} scope (optional)
23491 * @return {Node} The found child or null if none was found
23493 findChildBy : function(fn, scope){
23494 var cs = this.childNodes;
23495 for(var i = 0, len = cs.length; i < len; i++) {
23496 if(fn.call(scope||cs[i], cs[i]) === true){
23504 * Sorts this nodes children using the supplied sort function
23505 * @param {Function} fn
23506 * @param {Object} scope (optional)
23508 sort : function(fn, scope){
23509 var cs = this.childNodes;
23510 var len = cs.length;
23512 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23514 for(var i = 0; i < len; i++){
23516 n.previousSibling = cs[i-1];
23517 n.nextSibling = cs[i+1];
23519 this.setFirstChild(n);
23522 this.setLastChild(n);
23529 * Returns true if this node is an ancestor (at any point) of the passed node.
23530 * @param {Node} node
23531 * @return {Boolean}
23533 contains : function(node){
23534 return node.isAncestor(this);
23538 * Returns true if the passed node is an ancestor (at any point) of this node.
23539 * @param {Node} node
23540 * @return {Boolean}
23542 isAncestor : function(node){
23543 var p = this.parentNode;
23553 toString : function(){
23554 return "[Node"+(this.id?" "+this.id:"")+"]";
23558 * Ext JS Library 1.1.1
23559 * Copyright(c) 2006-2007, Ext JS, LLC.
23561 * Originally Released Under LGPL - original licence link has changed is not relivant.
23564 * <script type="text/javascript">
23569 * @extends Roo.Element
23570 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23571 * automatic maintaining of shadow/shim positions.
23572 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23573 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23574 * you can pass a string with a CSS class name. False turns off the shadow.
23575 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23576 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23577 * @cfg {String} cls CSS class to add to the element
23578 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23579 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23581 * @param {Object} config An object with config options.
23582 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23585 Roo.Layer = function(config, existingEl){
23586 config = config || {};
23587 var dh = Roo.DomHelper;
23588 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23590 this.dom = Roo.getDom(existingEl);
23593 var o = config.dh || {tag: "div", cls: "x-layer"};
23594 this.dom = dh.append(pel, o);
23597 this.addClass(config.cls);
23599 this.constrain = config.constrain !== false;
23600 this.visibilityMode = Roo.Element.VISIBILITY;
23602 this.id = this.dom.id = config.id;
23604 this.id = Roo.id(this.dom);
23606 this.zindex = config.zindex || this.getZIndex();
23607 this.position("absolute", this.zindex);
23609 this.shadowOffset = config.shadowOffset || 4;
23610 this.shadow = new Roo.Shadow({
23611 offset : this.shadowOffset,
23612 mode : config.shadow
23615 this.shadowOffset = 0;
23617 this.useShim = config.shim !== false && Roo.useShims;
23618 this.useDisplay = config.useDisplay;
23622 var supr = Roo.Element.prototype;
23624 // shims are shared among layer to keep from having 100 iframes
23627 Roo.extend(Roo.Layer, Roo.Element, {
23629 getZIndex : function(){
23630 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23633 getShim : function(){
23640 var shim = shims.shift();
23642 shim = this.createShim();
23643 shim.enableDisplayMode('block');
23644 shim.dom.style.display = 'none';
23645 shim.dom.style.visibility = 'visible';
23647 var pn = this.dom.parentNode;
23648 if(shim.dom.parentNode != pn){
23649 pn.insertBefore(shim.dom, this.dom);
23651 shim.setStyle('z-index', this.getZIndex()-2);
23656 hideShim : function(){
23658 this.shim.setDisplayed(false);
23659 shims.push(this.shim);
23664 disableShadow : function(){
23666 this.shadowDisabled = true;
23667 this.shadow.hide();
23668 this.lastShadowOffset = this.shadowOffset;
23669 this.shadowOffset = 0;
23673 enableShadow : function(show){
23675 this.shadowDisabled = false;
23676 this.shadowOffset = this.lastShadowOffset;
23677 delete this.lastShadowOffset;
23685 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23686 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23687 sync : function(doShow){
23688 var sw = this.shadow;
23689 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23690 var sh = this.getShim();
23692 var w = this.getWidth(),
23693 h = this.getHeight();
23695 var l = this.getLeft(true),
23696 t = this.getTop(true);
23698 if(sw && !this.shadowDisabled){
23699 if(doShow && !sw.isVisible()){
23702 sw.realign(l, t, w, h);
23708 // fit the shim behind the shadow, so it is shimmed too
23709 var a = sw.adjusts, s = sh.dom.style;
23710 s.left = (Math.min(l, l+a.l))+"px";
23711 s.top = (Math.min(t, t+a.t))+"px";
23712 s.width = (w+a.w)+"px";
23713 s.height = (h+a.h)+"px";
23720 sh.setLeftTop(l, t);
23727 destroy : function(){
23730 this.shadow.hide();
23732 this.removeAllListeners();
23733 var pn = this.dom.parentNode;
23735 pn.removeChild(this.dom);
23737 Roo.Element.uncache(this.id);
23740 remove : function(){
23745 beginUpdate : function(){
23746 this.updating = true;
23750 endUpdate : function(){
23751 this.updating = false;
23756 hideUnders : function(negOffset){
23758 this.shadow.hide();
23764 constrainXY : function(){
23765 if(this.constrain){
23766 var vw = Roo.lib.Dom.getViewWidth(),
23767 vh = Roo.lib.Dom.getViewHeight();
23768 var s = Roo.get(document).getScroll();
23770 var xy = this.getXY();
23771 var x = xy[0], y = xy[1];
23772 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23773 // only move it if it needs it
23775 // first validate right/bottom
23776 if((x + w) > vw+s.left){
23777 x = vw - w - this.shadowOffset;
23780 if((y + h) > vh+s.top){
23781 y = vh - h - this.shadowOffset;
23784 // then make sure top/left isn't negative
23795 var ay = this.avoidY;
23796 if(y <= ay && (y+h) >= ay){
23802 supr.setXY.call(this, xy);
23808 isVisible : function(){
23809 return this.visible;
23813 showAction : function(){
23814 this.visible = true; // track visibility to prevent getStyle calls
23815 if(this.useDisplay === true){
23816 this.setDisplayed("");
23817 }else if(this.lastXY){
23818 supr.setXY.call(this, this.lastXY);
23819 }else if(this.lastLT){
23820 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23825 hideAction : function(){
23826 this.visible = false;
23827 if(this.useDisplay === true){
23828 this.setDisplayed(false);
23830 this.setLeftTop(-10000,-10000);
23834 // overridden Element method
23835 setVisible : function(v, a, d, c, e){
23840 var cb = function(){
23845 }.createDelegate(this);
23846 supr.setVisible.call(this, true, true, d, cb, e);
23849 this.hideUnders(true);
23858 }.createDelegate(this);
23860 supr.setVisible.call(this, v, a, d, cb, e);
23869 storeXY : function(xy){
23870 delete this.lastLT;
23874 storeLeftTop : function(left, top){
23875 delete this.lastXY;
23876 this.lastLT = [left, top];
23880 beforeFx : function(){
23881 this.beforeAction();
23882 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23886 afterFx : function(){
23887 Roo.Layer.superclass.afterFx.apply(this, arguments);
23888 this.sync(this.isVisible());
23892 beforeAction : function(){
23893 if(!this.updating && this.shadow){
23894 this.shadow.hide();
23898 // overridden Element method
23899 setLeft : function(left){
23900 this.storeLeftTop(left, this.getTop(true));
23901 supr.setLeft.apply(this, arguments);
23905 setTop : function(top){
23906 this.storeLeftTop(this.getLeft(true), top);
23907 supr.setTop.apply(this, arguments);
23911 setLeftTop : function(left, top){
23912 this.storeLeftTop(left, top);
23913 supr.setLeftTop.apply(this, arguments);
23917 setXY : function(xy, a, d, c, e){
23919 this.beforeAction();
23921 var cb = this.createCB(c);
23922 supr.setXY.call(this, xy, a, d, cb, e);
23929 createCB : function(c){
23940 // overridden Element method
23941 setX : function(x, a, d, c, e){
23942 this.setXY([x, this.getY()], a, d, c, e);
23945 // overridden Element method
23946 setY : function(y, a, d, c, e){
23947 this.setXY([this.getX(), y], a, d, c, e);
23950 // overridden Element method
23951 setSize : function(w, h, a, d, c, e){
23952 this.beforeAction();
23953 var cb = this.createCB(c);
23954 supr.setSize.call(this, w, h, a, d, cb, e);
23960 // overridden Element method
23961 setWidth : function(w, a, d, c, e){
23962 this.beforeAction();
23963 var cb = this.createCB(c);
23964 supr.setWidth.call(this, w, a, d, cb, e);
23970 // overridden Element method
23971 setHeight : function(h, a, d, c, e){
23972 this.beforeAction();
23973 var cb = this.createCB(c);
23974 supr.setHeight.call(this, h, a, d, cb, e);
23980 // overridden Element method
23981 setBounds : function(x, y, w, h, a, d, c, e){
23982 this.beforeAction();
23983 var cb = this.createCB(c);
23985 this.storeXY([x, y]);
23986 supr.setXY.call(this, [x, y]);
23987 supr.setSize.call(this, w, h, a, d, cb, e);
23990 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
23996 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
23997 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
23998 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
23999 * @param {Number} zindex The new z-index to set
24000 * @return {this} The Layer
24002 setZIndex : function(zindex){
24003 this.zindex = zindex;
24004 this.setStyle("z-index", zindex + 2);
24006 this.shadow.setZIndex(zindex + 1);
24009 this.shim.setStyle("z-index", zindex);
24015 * Ext JS Library 1.1.1
24016 * Copyright(c) 2006-2007, Ext JS, LLC.
24018 * Originally Released Under LGPL - original licence link has changed is not relivant.
24021 * <script type="text/javascript">
24026 * @class Roo.Shadow
24027 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24028 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24029 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24031 * Create a new Shadow
24032 * @param {Object} config The config object
24034 Roo.Shadow = function(config){
24035 Roo.apply(this, config);
24036 if(typeof this.mode != "string"){
24037 this.mode = this.defaultMode;
24039 var o = this.offset, a = {h: 0};
24040 var rad = Math.floor(this.offset/2);
24041 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24047 a.l -= this.offset + rad;
24048 a.t -= this.offset + rad;
24059 a.l -= (this.offset - rad);
24060 a.t -= this.offset + rad;
24062 a.w -= (this.offset - rad)*2;
24073 a.l -= (this.offset - rad);
24074 a.t -= (this.offset - rad);
24076 a.w -= (this.offset + rad + 1);
24077 a.h -= (this.offset + rad);
24086 Roo.Shadow.prototype = {
24088 * @cfg {String} mode
24089 * The shadow display mode. Supports the following options:<br />
24090 * sides: Shadow displays on both sides and bottom only<br />
24091 * frame: Shadow displays equally on all four sides<br />
24092 * drop: Traditional bottom-right drop shadow (default)
24095 * @cfg {String} offset
24096 * The number of pixels to offset the shadow from the element (defaults to 4)
24101 defaultMode: "drop",
24104 * Displays the shadow under the target element
24105 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24107 show : function(target){
24108 target = Roo.get(target);
24110 this.el = Roo.Shadow.Pool.pull();
24111 if(this.el.dom.nextSibling != target.dom){
24112 this.el.insertBefore(target);
24115 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24117 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24120 target.getLeft(true),
24121 target.getTop(true),
24125 this.el.dom.style.display = "block";
24129 * Returns true if the shadow is visible, else false
24131 isVisible : function(){
24132 return this.el ? true : false;
24136 * Direct alignment when values are already available. Show must be called at least once before
24137 * calling this method to ensure it is initialized.
24138 * @param {Number} left The target element left position
24139 * @param {Number} top The target element top position
24140 * @param {Number} width The target element width
24141 * @param {Number} height The target element height
24143 realign : function(l, t, w, h){
24147 var a = this.adjusts, d = this.el.dom, s = d.style;
24149 s.left = (l+a.l)+"px";
24150 s.top = (t+a.t)+"px";
24151 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24153 if(s.width != sws || s.height != shs){
24157 var cn = d.childNodes;
24158 var sww = Math.max(0, (sw-12))+"px";
24159 cn[0].childNodes[1].style.width = sww;
24160 cn[1].childNodes[1].style.width = sww;
24161 cn[2].childNodes[1].style.width = sww;
24162 cn[1].style.height = Math.max(0, (sh-12))+"px";
24168 * Hides this shadow
24172 this.el.dom.style.display = "none";
24173 Roo.Shadow.Pool.push(this.el);
24179 * Adjust the z-index of this shadow
24180 * @param {Number} zindex The new z-index
24182 setZIndex : function(z){
24185 this.el.setStyle("z-index", z);
24190 // Private utility class that manages the internal Shadow cache
24191 Roo.Shadow.Pool = function(){
24193 var markup = Roo.isIE ?
24194 '<div class="x-ie-shadow"></div>' :
24195 '<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>';
24198 var sh = p.shift();
24200 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24201 sh.autoBoxAdjust = false;
24206 push : function(sh){
24212 * Ext JS Library 1.1.1
24213 * Copyright(c) 2006-2007, Ext JS, LLC.
24215 * Originally Released Under LGPL - original licence link has changed is not relivant.
24218 * <script type="text/javascript">
24223 * @class Roo.SplitBar
24224 * @extends Roo.util.Observable
24225 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24229 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24230 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24231 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24232 split.minSize = 100;
24233 split.maxSize = 600;
24234 split.animate = true;
24235 split.on('moved', splitterMoved);
24238 * Create a new SplitBar
24239 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24240 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24241 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24242 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24243 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24244 position of the SplitBar).
24246 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24249 this.el = Roo.get(dragElement, true);
24250 this.el.dom.unselectable = "on";
24252 this.resizingEl = Roo.get(resizingElement, true);
24256 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24257 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24260 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24263 * The minimum size of the resizing element. (Defaults to 0)
24269 * The maximum size of the resizing element. (Defaults to 2000)
24272 this.maxSize = 2000;
24275 * Whether to animate the transition to the new size
24278 this.animate = false;
24281 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24284 this.useShim = false;
24289 if(!existingProxy){
24291 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24293 this.proxy = Roo.get(existingProxy).dom;
24296 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24299 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24302 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24305 this.dragSpecs = {};
24308 * @private The adapter to use to positon and resize elements
24310 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24311 this.adapter.init(this);
24313 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24315 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24316 this.el.addClass("x-splitbar-h");
24319 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24320 this.el.addClass("x-splitbar-v");
24326 * Fires when the splitter is moved (alias for {@link #event-moved})
24327 * @param {Roo.SplitBar} this
24328 * @param {Number} newSize the new width or height
24333 * Fires when the splitter is moved
24334 * @param {Roo.SplitBar} this
24335 * @param {Number} newSize the new width or height
24339 * @event beforeresize
24340 * Fires before the splitter is dragged
24341 * @param {Roo.SplitBar} this
24343 "beforeresize" : true,
24345 "beforeapply" : true
24348 Roo.util.Observable.call(this);
24351 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24352 onStartProxyDrag : function(x, y){
24353 this.fireEvent("beforeresize", this);
24355 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24357 o.enableDisplayMode("block");
24358 // all splitbars share the same overlay
24359 Roo.SplitBar.prototype.overlay = o;
24361 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24362 this.overlay.show();
24363 Roo.get(this.proxy).setDisplayed("block");
24364 var size = this.adapter.getElementSize(this);
24365 this.activeMinSize = this.getMinimumSize();;
24366 this.activeMaxSize = this.getMaximumSize();;
24367 var c1 = size - this.activeMinSize;
24368 var c2 = Math.max(this.activeMaxSize - size, 0);
24369 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24370 this.dd.resetConstraints();
24371 this.dd.setXConstraint(
24372 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24373 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24375 this.dd.setYConstraint(0, 0);
24377 this.dd.resetConstraints();
24378 this.dd.setXConstraint(0, 0);
24379 this.dd.setYConstraint(
24380 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24381 this.placement == Roo.SplitBar.TOP ? c2 : c1
24384 this.dragSpecs.startSize = size;
24385 this.dragSpecs.startPoint = [x, y];
24386 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24390 * @private Called after the drag operation by the DDProxy
24392 onEndProxyDrag : function(e){
24393 Roo.get(this.proxy).setDisplayed(false);
24394 var endPoint = Roo.lib.Event.getXY(e);
24396 this.overlay.hide();
24399 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24400 newSize = this.dragSpecs.startSize +
24401 (this.placement == Roo.SplitBar.LEFT ?
24402 endPoint[0] - this.dragSpecs.startPoint[0] :
24403 this.dragSpecs.startPoint[0] - endPoint[0]
24406 newSize = this.dragSpecs.startSize +
24407 (this.placement == Roo.SplitBar.TOP ?
24408 endPoint[1] - this.dragSpecs.startPoint[1] :
24409 this.dragSpecs.startPoint[1] - endPoint[1]
24412 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24413 if(newSize != this.dragSpecs.startSize){
24414 if(this.fireEvent('beforeapply', this, newSize) !== false){
24415 this.adapter.setElementSize(this, newSize);
24416 this.fireEvent("moved", this, newSize);
24417 this.fireEvent("resize", this, newSize);
24423 * Get the adapter this SplitBar uses
24424 * @return The adapter object
24426 getAdapter : function(){
24427 return this.adapter;
24431 * Set the adapter this SplitBar uses
24432 * @param {Object} adapter A SplitBar adapter object
24434 setAdapter : function(adapter){
24435 this.adapter = adapter;
24436 this.adapter.init(this);
24440 * Gets the minimum size for the resizing element
24441 * @return {Number} The minimum size
24443 getMinimumSize : function(){
24444 return this.minSize;
24448 * Sets the minimum size for the resizing element
24449 * @param {Number} minSize The minimum size
24451 setMinimumSize : function(minSize){
24452 this.minSize = minSize;
24456 * Gets the maximum size for the resizing element
24457 * @return {Number} The maximum size
24459 getMaximumSize : function(){
24460 return this.maxSize;
24464 * Sets the maximum size for the resizing element
24465 * @param {Number} maxSize The maximum size
24467 setMaximumSize : function(maxSize){
24468 this.maxSize = maxSize;
24472 * Sets the initialize size for the resizing element
24473 * @param {Number} size The initial size
24475 setCurrentSize : function(size){
24476 var oldAnimate = this.animate;
24477 this.animate = false;
24478 this.adapter.setElementSize(this, size);
24479 this.animate = oldAnimate;
24483 * Destroy this splitbar.
24484 * @param {Boolean} removeEl True to remove the element
24486 destroy : function(removeEl){
24488 this.shim.remove();
24491 this.proxy.parentNode.removeChild(this.proxy);
24499 * @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.
24501 Roo.SplitBar.createProxy = function(dir){
24502 var proxy = new Roo.Element(document.createElement("div"));
24503 proxy.unselectable();
24504 var cls = 'x-splitbar-proxy';
24505 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24506 document.body.appendChild(proxy.dom);
24511 * @class Roo.SplitBar.BasicLayoutAdapter
24512 * Default Adapter. It assumes the splitter and resizing element are not positioned
24513 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24515 Roo.SplitBar.BasicLayoutAdapter = function(){
24518 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24519 // do nothing for now
24520 init : function(s){
24524 * Called before drag operations to get the current size of the resizing element.
24525 * @param {Roo.SplitBar} s The SplitBar using this adapter
24527 getElementSize : function(s){
24528 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24529 return s.resizingEl.getWidth();
24531 return s.resizingEl.getHeight();
24536 * Called after drag operations to set the size of the resizing element.
24537 * @param {Roo.SplitBar} s The SplitBar using this adapter
24538 * @param {Number} newSize The new size to set
24539 * @param {Function} onComplete A function to be invoked when resizing is complete
24541 setElementSize : function(s, newSize, onComplete){
24542 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24544 s.resizingEl.setWidth(newSize);
24546 onComplete(s, newSize);
24549 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24554 s.resizingEl.setHeight(newSize);
24556 onComplete(s, newSize);
24559 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24566 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24567 * @extends Roo.SplitBar.BasicLayoutAdapter
24568 * Adapter that moves the splitter element to align with the resized sizing element.
24569 * Used with an absolute positioned SplitBar.
24570 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24571 * document.body, make sure you assign an id to the body element.
24573 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24574 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24575 this.container = Roo.get(container);
24578 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24579 init : function(s){
24580 this.basic.init(s);
24583 getElementSize : function(s){
24584 return this.basic.getElementSize(s);
24587 setElementSize : function(s, newSize, onComplete){
24588 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24591 moveSplitter : function(s){
24592 var yes = Roo.SplitBar;
24593 switch(s.placement){
24595 s.el.setX(s.resizingEl.getRight());
24598 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24601 s.el.setY(s.resizingEl.getBottom());
24604 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24611 * Orientation constant - Create a vertical SplitBar
24615 Roo.SplitBar.VERTICAL = 1;
24618 * Orientation constant - Create a horizontal SplitBar
24622 Roo.SplitBar.HORIZONTAL = 2;
24625 * Placement constant - The resizing element is to the left of the splitter element
24629 Roo.SplitBar.LEFT = 1;
24632 * Placement constant - The resizing element is to the right of the splitter element
24636 Roo.SplitBar.RIGHT = 2;
24639 * Placement constant - The resizing element is positioned above the splitter element
24643 Roo.SplitBar.TOP = 3;
24646 * Placement constant - The resizing element is positioned under splitter element
24650 Roo.SplitBar.BOTTOM = 4;
24653 * Ext JS Library 1.1.1
24654 * Copyright(c) 2006-2007, Ext JS, LLC.
24656 * Originally Released Under LGPL - original licence link has changed is not relivant.
24659 * <script type="text/javascript">
24664 * @extends Roo.util.Observable
24665 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24666 * This class also supports single and multi selection modes. <br>
24667 * Create a data model bound view:
24669 var store = new Roo.data.Store(...);
24671 var view = new Roo.View({
24673 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24675 singleSelect: true,
24676 selectedClass: "ydataview-selected",
24680 // listen for node click?
24681 view.on("click", function(vw, index, node, e){
24682 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24686 dataModel.load("foobar.xml");
24688 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24690 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24691 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24693 * Note: old style constructor is still suported (container, template, config)
24696 * Create a new View
24697 * @param {Object} config The config object
24700 Roo.View = function(config, depreciated_tpl, depreciated_config){
24702 if (typeof(depreciated_tpl) == 'undefined') {
24703 // new way.. - universal constructor.
24704 Roo.apply(this, config);
24705 this.el = Roo.get(this.el);
24708 this.el = Roo.get(config);
24709 this.tpl = depreciated_tpl;
24710 Roo.apply(this, depreciated_config);
24712 this.wrapEl = this.el.wrap().wrap();
24713 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24716 if(typeof(this.tpl) == "string"){
24717 this.tpl = new Roo.Template(this.tpl);
24719 // support xtype ctors..
24720 this.tpl = new Roo.factory(this.tpl, Roo);
24724 this.tpl.compile();
24732 * @event beforeclick
24733 * Fires before a click is processed. Returns false to cancel the default action.
24734 * @param {Roo.View} this
24735 * @param {Number} index The index of the target node
24736 * @param {HTMLElement} node The target node
24737 * @param {Roo.EventObject} e The raw event object
24739 "beforeclick" : true,
24742 * Fires when a template node is clicked.
24743 * @param {Roo.View} this
24744 * @param {Number} index The index of the target node
24745 * @param {HTMLElement} node The target node
24746 * @param {Roo.EventObject} e The raw event object
24751 * Fires when a template node is double clicked.
24752 * @param {Roo.View} this
24753 * @param {Number} index The index of the target node
24754 * @param {HTMLElement} node The target node
24755 * @param {Roo.EventObject} e The raw event object
24759 * @event contextmenu
24760 * Fires when a template node is right clicked.
24761 * @param {Roo.View} this
24762 * @param {Number} index The index of the target node
24763 * @param {HTMLElement} node The target node
24764 * @param {Roo.EventObject} e The raw event object
24766 "contextmenu" : true,
24768 * @event selectionchange
24769 * Fires when the selected nodes change.
24770 * @param {Roo.View} this
24771 * @param {Array} selections Array of the selected nodes
24773 "selectionchange" : true,
24776 * @event beforeselect
24777 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24778 * @param {Roo.View} this
24779 * @param {HTMLElement} node The node to be selected
24780 * @param {Array} selections Array of currently selected nodes
24782 "beforeselect" : true,
24784 * @event preparedata
24785 * Fires on every row to render, to allow you to change the data.
24786 * @param {Roo.View} this
24787 * @param {Object} data to be rendered (change this)
24789 "preparedata" : true
24797 "click": this.onClick,
24798 "dblclick": this.onDblClick,
24799 "contextmenu": this.onContextMenu,
24803 this.selections = [];
24805 this.cmp = new Roo.CompositeElementLite([]);
24807 this.store = Roo.factory(this.store, Roo.data);
24808 this.setStore(this.store, true);
24811 if ( this.footer && this.footer.xtype) {
24813 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24815 this.footer.dataSource = this.store
24816 this.footer.container = fctr;
24817 this.footer = Roo.factory(this.footer, Roo);
24818 fctr.insertFirst(this.el);
24820 // this is a bit insane - as the paging toolbar seems to detach the el..
24821 // dom.parentNode.parentNode.parentNode
24822 // they get detached?
24826 Roo.View.superclass.constructor.call(this);
24831 Roo.extend(Roo.View, Roo.util.Observable, {
24834 * @cfg {Roo.data.Store} store Data store to load data from.
24839 * @cfg {String|Roo.Element} el The container element.
24844 * @cfg {String|Roo.Template} tpl The template used by this View
24848 * @cfg {String} dataName the named area of the template to use as the data area
24849 * Works with domtemplates roo-name="name"
24853 * @cfg {String} selectedClass The css class to add to selected nodes
24855 selectedClass : "x-view-selected",
24857 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24862 * @cfg {String} text to display on mask (default Loading)
24866 * @cfg {Boolean} multiSelect Allow multiple selection
24868 multiSelect : false,
24870 * @cfg {Boolean} singleSelect Allow single selection
24872 singleSelect: false,
24875 * @cfg {Boolean} toggleSelect - selecting
24877 toggleSelect : false,
24880 * Returns the element this view is bound to.
24881 * @return {Roo.Element}
24883 getEl : function(){
24884 return this.wrapEl;
24890 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24892 refresh : function(){
24895 // if we are using something like 'domtemplate', then
24896 // the what gets used is:
24897 // t.applySubtemplate(NAME, data, wrapping data..)
24898 // the outer template then get' applied with
24899 // the store 'extra data'
24900 // and the body get's added to the
24901 // roo-name="data" node?
24902 // <span class='roo-tpl-{name}'></span> ?????
24906 this.clearSelections();
24907 this.el.update("");
24909 var records = this.store.getRange();
24910 if(records.length < 1) {
24912 // is this valid?? = should it render a template??
24914 this.el.update(this.emptyText);
24918 if (this.dataName) {
24919 this.el.update(t.apply(this.store.meta)); //????
24920 el = this.el.child('.roo-tpl-' + this.dataName);
24923 for(var i = 0, len = records.length; i < len; i++){
24924 var data = this.prepareData(records[i].data, i, records[i]);
24925 this.fireEvent("preparedata", this, data, i, records[i]);
24926 html[html.length] = Roo.util.Format.trim(
24928 t.applySubtemplate(this.dataName, data, this.store.meta) :
24935 el.update(html.join(""));
24936 this.nodes = el.dom.childNodes;
24937 this.updateIndexes(0);
24941 * Function to override to reformat the data that is sent to
24942 * the template for each node.
24943 * DEPRICATED - use the preparedata event handler.
24944 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24945 * a JSON object for an UpdateManager bound view).
24947 prepareData : function(data, index, record)
24949 this.fireEvent("preparedata", this, data, index, record);
24953 onUpdate : function(ds, record){
24954 this.clearSelections();
24955 var index = this.store.indexOf(record);
24956 var n = this.nodes[index];
24957 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24958 n.parentNode.removeChild(n);
24959 this.updateIndexes(index, index);
24965 onAdd : function(ds, records, index)
24967 this.clearSelections();
24968 if(this.nodes.length == 0){
24972 var n = this.nodes[index];
24973 for(var i = 0, len = records.length; i < len; i++){
24974 var d = this.prepareData(records[i].data, i, records[i]);
24976 this.tpl.insertBefore(n, d);
24979 this.tpl.append(this.el, d);
24982 this.updateIndexes(index);
24985 onRemove : function(ds, record, index){
24986 this.clearSelections();
24987 var el = this.dataName ?
24988 this.el.child('.roo-tpl-' + this.dataName) :
24990 el.dom.removeChild(this.nodes[index]);
24991 this.updateIndexes(index);
24995 * Refresh an individual node.
24996 * @param {Number} index
24998 refreshNode : function(index){
24999 this.onUpdate(this.store, this.store.getAt(index));
25002 updateIndexes : function(startIndex, endIndex){
25003 var ns = this.nodes;
25004 startIndex = startIndex || 0;
25005 endIndex = endIndex || ns.length - 1;
25006 for(var i = startIndex; i <= endIndex; i++){
25007 ns[i].nodeIndex = i;
25012 * Changes the data store this view uses and refresh the view.
25013 * @param {Store} store
25015 setStore : function(store, initial){
25016 if(!initial && this.store){
25017 this.store.un("datachanged", this.refresh);
25018 this.store.un("add", this.onAdd);
25019 this.store.un("remove", this.onRemove);
25020 this.store.un("update", this.onUpdate);
25021 this.store.un("clear", this.refresh);
25022 this.store.un("beforeload", this.onBeforeLoad);
25023 this.store.un("load", this.onLoad);
25024 this.store.un("loadexception", this.onLoad);
25028 store.on("datachanged", this.refresh, this);
25029 store.on("add", this.onAdd, this);
25030 store.on("remove", this.onRemove, this);
25031 store.on("update", this.onUpdate, this);
25032 store.on("clear", this.refresh, this);
25033 store.on("beforeload", this.onBeforeLoad, this);
25034 store.on("load", this.onLoad, this);
25035 store.on("loadexception", this.onLoad, this);
25043 * onbeforeLoad - masks the loading area.
25046 onBeforeLoad : function()
25048 this.el.update("");
25049 this.el.mask(this.mask ? this.mask : "Loading" );
25051 onLoad : function ()
25058 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25059 * @param {HTMLElement} node
25060 * @return {HTMLElement} The template node
25062 findItemFromChild : function(node){
25063 var el = this.dataName ?
25064 this.el.child('.roo-tpl-' + this.dataName,true) :
25067 if(!node || node.parentNode == el){
25070 var p = node.parentNode;
25071 while(p && p != el){
25072 if(p.parentNode == el){
25081 onClick : function(e){
25082 var item = this.findItemFromChild(e.getTarget());
25084 var index = this.indexOf(item);
25085 if(this.onItemClick(item, index, e) !== false){
25086 this.fireEvent("click", this, index, item, e);
25089 this.clearSelections();
25094 onContextMenu : function(e){
25095 var item = this.findItemFromChild(e.getTarget());
25097 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25102 onDblClick : function(e){
25103 var item = this.findItemFromChild(e.getTarget());
25105 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25109 onItemClick : function(item, index, e)
25111 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25114 if (this.toggleSelect) {
25115 var m = this.isSelected(item) ? 'unselect' : 'select';
25118 _t[m](item, true, false);
25121 if(this.multiSelect || this.singleSelect){
25122 if(this.multiSelect && e.shiftKey && this.lastSelection){
25123 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25125 this.select(item, this.multiSelect && e.ctrlKey);
25126 this.lastSelection = item;
25128 e.preventDefault();
25134 * Get the number of selected nodes.
25137 getSelectionCount : function(){
25138 return this.selections.length;
25142 * Get the currently selected nodes.
25143 * @return {Array} An array of HTMLElements
25145 getSelectedNodes : function(){
25146 return this.selections;
25150 * Get the indexes of the selected nodes.
25153 getSelectedIndexes : function(){
25154 var indexes = [], s = this.selections;
25155 for(var i = 0, len = s.length; i < len; i++){
25156 indexes.push(s[i].nodeIndex);
25162 * Clear all selections
25163 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25165 clearSelections : function(suppressEvent){
25166 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25167 this.cmp.elements = this.selections;
25168 this.cmp.removeClass(this.selectedClass);
25169 this.selections = [];
25170 if(!suppressEvent){
25171 this.fireEvent("selectionchange", this, this.selections);
25177 * Returns true if the passed node is selected
25178 * @param {HTMLElement/Number} node The node or node index
25179 * @return {Boolean}
25181 isSelected : function(node){
25182 var s = this.selections;
25186 node = this.getNode(node);
25187 return s.indexOf(node) !== -1;
25192 * @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
25193 * @param {Boolean} keepExisting (optional) true to keep existing selections
25194 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25196 select : function(nodeInfo, keepExisting, suppressEvent){
25197 if(nodeInfo instanceof Array){
25199 this.clearSelections(true);
25201 for(var i = 0, len = nodeInfo.length; i < len; i++){
25202 this.select(nodeInfo[i], true, true);
25206 var node = this.getNode(nodeInfo);
25207 if(!node || this.isSelected(node)){
25208 return; // already selected.
25211 this.clearSelections(true);
25213 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25214 Roo.fly(node).addClass(this.selectedClass);
25215 this.selections.push(node);
25216 if(!suppressEvent){
25217 this.fireEvent("selectionchange", this, this.selections);
25225 * @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
25226 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25227 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25229 unselect : function(nodeInfo, keepExisting, suppressEvent)
25231 if(nodeInfo instanceof Array){
25232 Roo.each(this.selections, function(s) {
25233 this.unselect(s, nodeInfo);
25237 var node = this.getNode(nodeInfo);
25238 if(!node || !this.isSelected(node)){
25239 Roo.log("not selected");
25240 return; // not selected.
25244 Roo.each(this.selections, function(s) {
25246 Roo.fly(node).removeClass(this.selectedClass);
25253 this.selections= ns;
25254 this.fireEvent("selectionchange", this, this.selections);
25258 * Gets a template node.
25259 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25260 * @return {HTMLElement} The node or null if it wasn't found
25262 getNode : function(nodeInfo){
25263 if(typeof nodeInfo == "string"){
25264 return document.getElementById(nodeInfo);
25265 }else if(typeof nodeInfo == "number"){
25266 return this.nodes[nodeInfo];
25272 * Gets a range template nodes.
25273 * @param {Number} startIndex
25274 * @param {Number} endIndex
25275 * @return {Array} An array of nodes
25277 getNodes : function(start, end){
25278 var ns = this.nodes;
25279 start = start || 0;
25280 end = typeof end == "undefined" ? ns.length - 1 : end;
25283 for(var i = start; i <= end; i++){
25287 for(var i = start; i >= end; i--){
25295 * Finds the index of the passed node
25296 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25297 * @return {Number} The index of the node or -1
25299 indexOf : function(node){
25300 node = this.getNode(node);
25301 if(typeof node.nodeIndex == "number"){
25302 return node.nodeIndex;
25304 var ns = this.nodes;
25305 for(var i = 0, len = ns.length; i < len; i++){
25315 * Ext JS Library 1.1.1
25316 * Copyright(c) 2006-2007, Ext JS, LLC.
25318 * Originally Released Under LGPL - original licence link has changed is not relivant.
25321 * <script type="text/javascript">
25325 * @class Roo.JsonView
25326 * @extends Roo.View
25327 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25329 var view = new Roo.JsonView({
25330 container: "my-element",
25331 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25336 // listen for node click?
25337 view.on("click", function(vw, index, node, e){
25338 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25341 // direct load of JSON data
25342 view.load("foobar.php");
25344 // Example from my blog list
25345 var tpl = new Roo.Template(
25346 '<div class="entry">' +
25347 '<a class="entry-title" href="{link}">{title}</a>' +
25348 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25349 "</div><hr />"
25352 var moreView = new Roo.JsonView({
25353 container : "entry-list",
25357 moreView.on("beforerender", this.sortEntries, this);
25359 url: "/blog/get-posts.php",
25360 params: "allposts=true",
25361 text: "Loading Blog Entries..."
25365 * Note: old code is supported with arguments : (container, template, config)
25369 * Create a new JsonView
25371 * @param {Object} config The config object
25374 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25377 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25379 var um = this.el.getUpdateManager();
25380 um.setRenderer(this);
25381 um.on("update", this.onLoad, this);
25382 um.on("failure", this.onLoadException, this);
25385 * @event beforerender
25386 * Fires before rendering of the downloaded JSON data.
25387 * @param {Roo.JsonView} this
25388 * @param {Object} data The JSON data loaded
25392 * Fires when data is loaded.
25393 * @param {Roo.JsonView} this
25394 * @param {Object} data The JSON data loaded
25395 * @param {Object} response The raw Connect response object
25398 * @event loadexception
25399 * Fires when loading fails.
25400 * @param {Roo.JsonView} this
25401 * @param {Object} response The raw Connect response object
25404 'beforerender' : true,
25406 'loadexception' : true
25409 Roo.extend(Roo.JsonView, Roo.View, {
25411 * @type {String} The root property in the loaded JSON object that contains the data
25416 * Refreshes the view.
25418 refresh : function(){
25419 this.clearSelections();
25420 this.el.update("");
25422 var o = this.jsonData;
25423 if(o && o.length > 0){
25424 for(var i = 0, len = o.length; i < len; i++){
25425 var data = this.prepareData(o[i], i, o);
25426 html[html.length] = this.tpl.apply(data);
25429 html.push(this.emptyText);
25431 this.el.update(html.join(""));
25432 this.nodes = this.el.dom.childNodes;
25433 this.updateIndexes(0);
25437 * 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.
25438 * @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:
25441 url: "your-url.php",
25442 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25443 callback: yourFunction,
25444 scope: yourObject, //(optional scope)
25447 text: "Loading...",
25452 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25453 * 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.
25454 * @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}
25455 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25456 * @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.
25459 var um = this.el.getUpdateManager();
25460 um.update.apply(um, arguments);
25463 render : function(el, response){
25464 this.clearSelections();
25465 this.el.update("");
25468 o = Roo.util.JSON.decode(response.responseText);
25471 o = o[this.jsonRoot];
25476 * The current JSON data or null
25479 this.beforeRender();
25484 * Get the number of records in the current JSON dataset
25487 getCount : function(){
25488 return this.jsonData ? this.jsonData.length : 0;
25492 * Returns the JSON object for the specified node(s)
25493 * @param {HTMLElement/Array} node The node or an array of nodes
25494 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25495 * you get the JSON object for the node
25497 getNodeData : function(node){
25498 if(node instanceof Array){
25500 for(var i = 0, len = node.length; i < len; i++){
25501 data.push(this.getNodeData(node[i]));
25505 return this.jsonData[this.indexOf(node)] || null;
25508 beforeRender : function(){
25509 this.snapshot = this.jsonData;
25511 this.sort.apply(this, this.sortInfo);
25513 this.fireEvent("beforerender", this, this.jsonData);
25516 onLoad : function(el, o){
25517 this.fireEvent("load", this, this.jsonData, o);
25520 onLoadException : function(el, o){
25521 this.fireEvent("loadexception", this, o);
25525 * Filter the data by a specific property.
25526 * @param {String} property A property on your JSON objects
25527 * @param {String/RegExp} value Either string that the property values
25528 * should start with, or a RegExp to test against the property
25530 filter : function(property, value){
25533 var ss = this.snapshot;
25534 if(typeof value == "string"){
25535 var vlen = value.length;
25537 this.clearFilter();
25540 value = value.toLowerCase();
25541 for(var i = 0, len = ss.length; i < len; i++){
25543 if(o[property].substr(0, vlen).toLowerCase() == value){
25547 } else if(value.exec){ // regex?
25548 for(var i = 0, len = ss.length; i < len; i++){
25550 if(value.test(o[property])){
25557 this.jsonData = data;
25563 * Filter by a function. The passed function will be called with each
25564 * object in the current dataset. If the function returns true the value is kept,
25565 * otherwise it is filtered.
25566 * @param {Function} fn
25567 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25569 filterBy : function(fn, scope){
25572 var ss = this.snapshot;
25573 for(var i = 0, len = ss.length; i < len; i++){
25575 if(fn.call(scope || this, o)){
25579 this.jsonData = data;
25585 * Clears the current filter.
25587 clearFilter : function(){
25588 if(this.snapshot && this.jsonData != this.snapshot){
25589 this.jsonData = this.snapshot;
25596 * Sorts the data for this view and refreshes it.
25597 * @param {String} property A property on your JSON objects to sort on
25598 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25599 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25601 sort : function(property, dir, sortType){
25602 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25605 var dsc = dir && dir.toLowerCase() == "desc";
25606 var f = function(o1, o2){
25607 var v1 = sortType ? sortType(o1[p]) : o1[p];
25608 var v2 = sortType ? sortType(o2[p]) : o2[p];
25611 return dsc ? +1 : -1;
25612 } else if(v1 > v2){
25613 return dsc ? -1 : +1;
25618 this.jsonData.sort(f);
25620 if(this.jsonData != this.snapshot){
25621 this.snapshot.sort(f);
25627 * Ext JS Library 1.1.1
25628 * Copyright(c) 2006-2007, Ext JS, LLC.
25630 * Originally Released Under LGPL - original licence link has changed is not relivant.
25633 * <script type="text/javascript">
25638 * @class Roo.ColorPalette
25639 * @extends Roo.Component
25640 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25641 * Here's an example of typical usage:
25643 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25644 cp.render('my-div');
25646 cp.on('select', function(palette, selColor){
25647 // do something with selColor
25651 * Create a new ColorPalette
25652 * @param {Object} config The config object
25654 Roo.ColorPalette = function(config){
25655 Roo.ColorPalette.superclass.constructor.call(this, config);
25659 * Fires when a color is selected
25660 * @param {ColorPalette} this
25661 * @param {String} color The 6-digit color hex code (without the # symbol)
25667 this.on("select", this.handler, this.scope, true);
25670 Roo.extend(Roo.ColorPalette, Roo.Component, {
25672 * @cfg {String} itemCls
25673 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25675 itemCls : "x-color-palette",
25677 * @cfg {String} value
25678 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25679 * the hex codes are case-sensitive.
25682 clickEvent:'click',
25684 ctype: "Roo.ColorPalette",
25687 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25689 allowReselect : false,
25692 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25693 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25694 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25695 * of colors with the width setting until the box is symmetrical.</p>
25696 * <p>You can override individual colors if needed:</p>
25698 var cp = new Roo.ColorPalette();
25699 cp.colors[0] = "FF0000"; // change the first box to red
25702 Or you can provide a custom array of your own for complete control:
25704 var cp = new Roo.ColorPalette();
25705 cp.colors = ["000000", "993300", "333300"];
25710 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25711 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25712 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25713 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25714 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25718 onRender : function(container, position){
25719 var t = new Roo.MasterTemplate(
25720 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25722 var c = this.colors;
25723 for(var i = 0, len = c.length; i < len; i++){
25726 var el = document.createElement("div");
25727 el.className = this.itemCls;
25729 container.dom.insertBefore(el, position);
25730 this.el = Roo.get(el);
25731 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25732 if(this.clickEvent != 'click'){
25733 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25738 afterRender : function(){
25739 Roo.ColorPalette.superclass.afterRender.call(this);
25741 var s = this.value;
25748 handleClick : function(e, t){
25749 e.preventDefault();
25750 if(!this.disabled){
25751 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25752 this.select(c.toUpperCase());
25757 * Selects the specified color in the palette (fires the select event)
25758 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25760 select : function(color){
25761 color = color.replace("#", "");
25762 if(color != this.value || this.allowReselect){
25765 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25767 el.child("a.color-"+color).addClass("x-color-palette-sel");
25768 this.value = color;
25769 this.fireEvent("select", this, color);
25774 * Ext JS Library 1.1.1
25775 * Copyright(c) 2006-2007, Ext JS, LLC.
25777 * Originally Released Under LGPL - original licence link has changed is not relivant.
25780 * <script type="text/javascript">
25784 * @class Roo.DatePicker
25785 * @extends Roo.Component
25786 * Simple date picker class.
25788 * Create a new DatePicker
25789 * @param {Object} config The config object
25791 Roo.DatePicker = function(config){
25792 Roo.DatePicker.superclass.constructor.call(this, config);
25794 this.value = config && config.value ?
25795 config.value.clearTime() : new Date().clearTime();
25800 * Fires when a date is selected
25801 * @param {DatePicker} this
25802 * @param {Date} date The selected date
25806 * @event monthchange
25807 * Fires when the displayed month changes
25808 * @param {DatePicker} this
25809 * @param {Date} date The selected month
25811 'monthchange': true
25815 this.on("select", this.handler, this.scope || this);
25817 // build the disabledDatesRE
25818 if(!this.disabledDatesRE && this.disabledDates){
25819 var dd = this.disabledDates;
25821 for(var i = 0; i < dd.length; i++){
25823 if(i != dd.length-1) re += "|";
25825 this.disabledDatesRE = new RegExp(re + ")");
25829 Roo.extend(Roo.DatePicker, Roo.Component, {
25831 * @cfg {String} todayText
25832 * The text to display on the button that selects the current date (defaults to "Today")
25834 todayText : "Today",
25836 * @cfg {String} okText
25837 * The text to display on the ok button
25839 okText : " OK ", //   to give the user extra clicking room
25841 * @cfg {String} cancelText
25842 * The text to display on the cancel button
25844 cancelText : "Cancel",
25846 * @cfg {String} todayTip
25847 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25849 todayTip : "{0} (Spacebar)",
25851 * @cfg {Date} minDate
25852 * Minimum allowable date (JavaScript date object, defaults to null)
25856 * @cfg {Date} maxDate
25857 * Maximum allowable date (JavaScript date object, defaults to null)
25861 * @cfg {String} minText
25862 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25864 minText : "This date is before the minimum date",
25866 * @cfg {String} maxText
25867 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25869 maxText : "This date is after the maximum date",
25871 * @cfg {String} format
25872 * The default date format string which can be overriden for localization support. The format must be
25873 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25877 * @cfg {Array} disabledDays
25878 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25880 disabledDays : null,
25882 * @cfg {String} disabledDaysText
25883 * The tooltip to display when the date falls on a disabled day (defaults to "")
25885 disabledDaysText : "",
25887 * @cfg {RegExp} disabledDatesRE
25888 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25890 disabledDatesRE : null,
25892 * @cfg {String} disabledDatesText
25893 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25895 disabledDatesText : "",
25897 * @cfg {Boolean} constrainToViewport
25898 * True to constrain the date picker to the viewport (defaults to true)
25900 constrainToViewport : true,
25902 * @cfg {Array} monthNames
25903 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25905 monthNames : Date.monthNames,
25907 * @cfg {Array} dayNames
25908 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25910 dayNames : Date.dayNames,
25912 * @cfg {String} nextText
25913 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25915 nextText: 'Next Month (Control+Right)',
25917 * @cfg {String} prevText
25918 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25920 prevText: 'Previous Month (Control+Left)',
25922 * @cfg {String} monthYearText
25923 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25925 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25927 * @cfg {Number} startDay
25928 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25932 * @cfg {Bool} showClear
25933 * Show a clear button (usefull for date form elements that can be blank.)
25939 * Sets the value of the date field
25940 * @param {Date} value The date to set
25942 setValue : function(value){
25943 var old = this.value;
25945 if (typeof(value) == 'string') {
25947 value = Date.parseDate(value, this.format);
25950 value = new Date();
25953 this.value = value.clearTime(true);
25955 this.update(this.value);
25960 * Gets the current selected value of the date field
25961 * @return {Date} The selected date
25963 getValue : function(){
25968 focus : function(){
25970 this.update(this.activeDate);
25975 onRender : function(container, position){
25978 '<table cellspacing="0">',
25979 '<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>',
25980 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
25981 var dn = this.dayNames;
25982 for(var i = 0; i < 7; i++){
25983 var d = this.startDay+i;
25987 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
25989 m[m.length] = "</tr></thead><tbody><tr>";
25990 for(var i = 0; i < 42; i++) {
25991 if(i % 7 == 0 && i != 0){
25992 m[m.length] = "</tr><tr>";
25994 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
25996 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
25997 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
25999 var el = document.createElement("div");
26000 el.className = "x-date-picker";
26001 el.innerHTML = m.join("");
26003 container.dom.insertBefore(el, position);
26005 this.el = Roo.get(el);
26006 this.eventEl = Roo.get(el.firstChild);
26008 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26009 handler: this.showPrevMonth,
26011 preventDefault:true,
26015 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26016 handler: this.showNextMonth,
26018 preventDefault:true,
26022 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26024 this.monthPicker = this.el.down('div.x-date-mp');
26025 this.monthPicker.enableDisplayMode('block');
26027 var kn = new Roo.KeyNav(this.eventEl, {
26028 "left" : function(e){
26030 this.showPrevMonth() :
26031 this.update(this.activeDate.add("d", -1));
26034 "right" : function(e){
26036 this.showNextMonth() :
26037 this.update(this.activeDate.add("d", 1));
26040 "up" : function(e){
26042 this.showNextYear() :
26043 this.update(this.activeDate.add("d", -7));
26046 "down" : function(e){
26048 this.showPrevYear() :
26049 this.update(this.activeDate.add("d", 7));
26052 "pageUp" : function(e){
26053 this.showNextMonth();
26056 "pageDown" : function(e){
26057 this.showPrevMonth();
26060 "enter" : function(e){
26061 e.stopPropagation();
26068 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26070 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26072 this.el.unselectable();
26074 this.cells = this.el.select("table.x-date-inner tbody td");
26075 this.textNodes = this.el.query("table.x-date-inner tbody span");
26077 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26079 tooltip: this.monthYearText
26082 this.mbtn.on('click', this.showMonthPicker, this);
26083 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26086 var today = (new Date()).dateFormat(this.format);
26088 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26089 if (this.showClear) {
26090 baseTb.add( new Roo.Toolbar.Fill());
26093 text: String.format(this.todayText, today),
26094 tooltip: String.format(this.todayTip, today),
26095 handler: this.selectToday,
26099 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26102 if (this.showClear) {
26104 baseTb.add( new Roo.Toolbar.Fill());
26107 cls: 'x-btn-icon x-btn-clear',
26108 handler: function() {
26110 this.fireEvent("select", this, '');
26120 this.update(this.value);
26123 createMonthPicker : function(){
26124 if(!this.monthPicker.dom.firstChild){
26125 var buf = ['<table border="0" cellspacing="0">'];
26126 for(var i = 0; i < 6; i++){
26128 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26129 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26131 '<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>' :
26132 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26136 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26138 '</button><button type="button" class="x-date-mp-cancel">',
26140 '</button></td></tr>',
26143 this.monthPicker.update(buf.join(''));
26144 this.monthPicker.on('click', this.onMonthClick, this);
26145 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26147 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26148 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26150 this.mpMonths.each(function(m, a, i){
26153 m.dom.xmonth = 5 + Math.round(i * .5);
26155 m.dom.xmonth = Math.round((i-1) * .5);
26161 showMonthPicker : function(){
26162 this.createMonthPicker();
26163 var size = this.el.getSize();
26164 this.monthPicker.setSize(size);
26165 this.monthPicker.child('table').setSize(size);
26167 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26168 this.updateMPMonth(this.mpSelMonth);
26169 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26170 this.updateMPYear(this.mpSelYear);
26172 this.monthPicker.slideIn('t', {duration:.2});
26175 updateMPYear : function(y){
26177 var ys = this.mpYears.elements;
26178 for(var i = 1; i <= 10; i++){
26179 var td = ys[i-1], y2;
26181 y2 = y + Math.round(i * .5);
26182 td.firstChild.innerHTML = y2;
26185 y2 = y - (5-Math.round(i * .5));
26186 td.firstChild.innerHTML = y2;
26189 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26193 updateMPMonth : function(sm){
26194 this.mpMonths.each(function(m, a, i){
26195 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26199 selectMPMonth: function(m){
26203 onMonthClick : function(e, t){
26205 var el = new Roo.Element(t), pn;
26206 if(el.is('button.x-date-mp-cancel')){
26207 this.hideMonthPicker();
26209 else if(el.is('button.x-date-mp-ok')){
26210 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26211 this.hideMonthPicker();
26213 else if(pn = el.up('td.x-date-mp-month', 2)){
26214 this.mpMonths.removeClass('x-date-mp-sel');
26215 pn.addClass('x-date-mp-sel');
26216 this.mpSelMonth = pn.dom.xmonth;
26218 else if(pn = el.up('td.x-date-mp-year', 2)){
26219 this.mpYears.removeClass('x-date-mp-sel');
26220 pn.addClass('x-date-mp-sel');
26221 this.mpSelYear = pn.dom.xyear;
26223 else if(el.is('a.x-date-mp-prev')){
26224 this.updateMPYear(this.mpyear-10);
26226 else if(el.is('a.x-date-mp-next')){
26227 this.updateMPYear(this.mpyear+10);
26231 onMonthDblClick : function(e, t){
26233 var el = new Roo.Element(t), pn;
26234 if(pn = el.up('td.x-date-mp-month', 2)){
26235 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26236 this.hideMonthPicker();
26238 else if(pn = el.up('td.x-date-mp-year', 2)){
26239 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26240 this.hideMonthPicker();
26244 hideMonthPicker : function(disableAnim){
26245 if(this.monthPicker){
26246 if(disableAnim === true){
26247 this.monthPicker.hide();
26249 this.monthPicker.slideOut('t', {duration:.2});
26255 showPrevMonth : function(e){
26256 this.update(this.activeDate.add("mo", -1));
26260 showNextMonth : function(e){
26261 this.update(this.activeDate.add("mo", 1));
26265 showPrevYear : function(){
26266 this.update(this.activeDate.add("y", -1));
26270 showNextYear : function(){
26271 this.update(this.activeDate.add("y", 1));
26275 handleMouseWheel : function(e){
26276 var delta = e.getWheelDelta();
26278 this.showPrevMonth();
26280 } else if(delta < 0){
26281 this.showNextMonth();
26287 handleDateClick : function(e, t){
26289 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26290 this.setValue(new Date(t.dateValue));
26291 this.fireEvent("select", this, this.value);
26296 selectToday : function(){
26297 this.setValue(new Date().clearTime());
26298 this.fireEvent("select", this, this.value);
26302 update : function(date)
26304 var vd = this.activeDate;
26305 this.activeDate = date;
26307 var t = date.getTime();
26308 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26309 this.cells.removeClass("x-date-selected");
26310 this.cells.each(function(c){
26311 if(c.dom.firstChild.dateValue == t){
26312 c.addClass("x-date-selected");
26313 setTimeout(function(){
26314 try{c.dom.firstChild.focus();}catch(e){}
26323 var days = date.getDaysInMonth();
26324 var firstOfMonth = date.getFirstDateOfMonth();
26325 var startingPos = firstOfMonth.getDay()-this.startDay;
26327 if(startingPos <= this.startDay){
26331 var pm = date.add("mo", -1);
26332 var prevStart = pm.getDaysInMonth()-startingPos;
26334 var cells = this.cells.elements;
26335 var textEls = this.textNodes;
26336 days += startingPos;
26338 // convert everything to numbers so it's fast
26339 var day = 86400000;
26340 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26341 var today = new Date().clearTime().getTime();
26342 var sel = date.clearTime().getTime();
26343 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26344 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26345 var ddMatch = this.disabledDatesRE;
26346 var ddText = this.disabledDatesText;
26347 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26348 var ddaysText = this.disabledDaysText;
26349 var format = this.format;
26351 var setCellClass = function(cal, cell){
26353 var t = d.getTime();
26354 cell.firstChild.dateValue = t;
26356 cell.className += " x-date-today";
26357 cell.title = cal.todayText;
26360 cell.className += " x-date-selected";
26361 setTimeout(function(){
26362 try{cell.firstChild.focus();}catch(e){}
26367 cell.className = " x-date-disabled";
26368 cell.title = cal.minText;
26372 cell.className = " x-date-disabled";
26373 cell.title = cal.maxText;
26377 if(ddays.indexOf(d.getDay()) != -1){
26378 cell.title = ddaysText;
26379 cell.className = " x-date-disabled";
26382 if(ddMatch && format){
26383 var fvalue = d.dateFormat(format);
26384 if(ddMatch.test(fvalue)){
26385 cell.title = ddText.replace("%0", fvalue);
26386 cell.className = " x-date-disabled";
26392 for(; i < startingPos; i++) {
26393 textEls[i].innerHTML = (++prevStart);
26394 d.setDate(d.getDate()+1);
26395 cells[i].className = "x-date-prevday";
26396 setCellClass(this, cells[i]);
26398 for(; i < days; i++){
26399 intDay = i - startingPos + 1;
26400 textEls[i].innerHTML = (intDay);
26401 d.setDate(d.getDate()+1);
26402 cells[i].className = "x-date-active";
26403 setCellClass(this, cells[i]);
26406 for(; i < 42; i++) {
26407 textEls[i].innerHTML = (++extraDays);
26408 d.setDate(d.getDate()+1);
26409 cells[i].className = "x-date-nextday";
26410 setCellClass(this, cells[i]);
26413 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26414 this.fireEvent('monthchange', this, date);
26416 if(!this.internalRender){
26417 var main = this.el.dom.firstChild;
26418 var w = main.offsetWidth;
26419 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26420 Roo.fly(main).setWidth(w);
26421 this.internalRender = true;
26422 // opera does not respect the auto grow header center column
26423 // then, after it gets a width opera refuses to recalculate
26424 // without a second pass
26425 if(Roo.isOpera && !this.secondPass){
26426 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26427 this.secondPass = true;
26428 this.update.defer(10, this, [date]);
26436 * Ext JS Library 1.1.1
26437 * Copyright(c) 2006-2007, Ext JS, LLC.
26439 * Originally Released Under LGPL - original licence link has changed is not relivant.
26442 * <script type="text/javascript">
26445 * @class Roo.TabPanel
26446 * @extends Roo.util.Observable
26447 * A lightweight tab container.
26451 // basic tabs 1, built from existing content
26452 var tabs = new Roo.TabPanel("tabs1");
26453 tabs.addTab("script", "View Script");
26454 tabs.addTab("markup", "View Markup");
26455 tabs.activate("script");
26457 // more advanced tabs, built from javascript
26458 var jtabs = new Roo.TabPanel("jtabs");
26459 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26461 // set up the UpdateManager
26462 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26463 var updater = tab2.getUpdateManager();
26464 updater.setDefaultUrl("ajax1.htm");
26465 tab2.on('activate', updater.refresh, updater, true);
26467 // Use setUrl for Ajax loading
26468 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26469 tab3.setUrl("ajax2.htm", null, true);
26472 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26475 jtabs.activate("jtabs-1");
26478 * Create a new TabPanel.
26479 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26480 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26482 Roo.TabPanel = function(container, config){
26484 * The container element for this TabPanel.
26485 * @type Roo.Element
26487 this.el = Roo.get(container, true);
26489 if(typeof config == "boolean"){
26490 this.tabPosition = config ? "bottom" : "top";
26492 Roo.apply(this, config);
26495 if(this.tabPosition == "bottom"){
26496 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26497 this.el.addClass("x-tabs-bottom");
26499 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26500 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26501 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26503 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26505 if(this.tabPosition != "bottom"){
26506 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26507 * @type Roo.Element
26509 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26510 this.el.addClass("x-tabs-top");
26514 this.bodyEl.setStyle("position", "relative");
26516 this.active = null;
26517 this.activateDelegate = this.activate.createDelegate(this);
26522 * Fires when the active tab changes
26523 * @param {Roo.TabPanel} this
26524 * @param {Roo.TabPanelItem} activePanel The new active tab
26528 * @event beforetabchange
26529 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26530 * @param {Roo.TabPanel} this
26531 * @param {Object} e Set cancel to true on this object to cancel the tab change
26532 * @param {Roo.TabPanelItem} tab The tab being changed to
26534 "beforetabchange" : true
26537 Roo.EventManager.onWindowResize(this.onResize, this);
26538 this.cpad = this.el.getPadding("lr");
26539 this.hiddenCount = 0;
26542 // toolbar on the tabbar support...
26543 if (this.toolbar) {
26544 var tcfg = this.toolbar;
26545 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26546 this.toolbar = new Roo.Toolbar(tcfg);
26547 if (Roo.isSafari) {
26548 var tbl = tcfg.container.child('table', true);
26549 tbl.setAttribute('width', '100%');
26556 Roo.TabPanel.superclass.constructor.call(this);
26559 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26561 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26563 tabPosition : "top",
26565 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26567 currentTabWidth : 0,
26569 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26573 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26577 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26579 preferredTabWidth : 175,
26581 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26583 resizeTabs : false,
26585 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26587 monitorResize : true,
26589 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26594 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26595 * @param {String} id The id of the div to use <b>or create</b>
26596 * @param {String} text The text for the tab
26597 * @param {String} content (optional) Content to put in the TabPanelItem body
26598 * @param {Boolean} closable (optional) True to create a close icon on the tab
26599 * @return {Roo.TabPanelItem} The created TabPanelItem
26601 addTab : function(id, text, content, closable){
26602 var item = new Roo.TabPanelItem(this, id, text, closable);
26603 this.addTabItem(item);
26605 item.setContent(content);
26611 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26612 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26613 * @return {Roo.TabPanelItem}
26615 getTab : function(id){
26616 return this.items[id];
26620 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26621 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26623 hideTab : function(id){
26624 var t = this.items[id];
26627 this.hiddenCount++;
26628 this.autoSizeTabs();
26633 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26634 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26636 unhideTab : function(id){
26637 var t = this.items[id];
26639 t.setHidden(false);
26640 this.hiddenCount--;
26641 this.autoSizeTabs();
26646 * Adds an existing {@link Roo.TabPanelItem}.
26647 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26649 addTabItem : function(item){
26650 this.items[item.id] = item;
26651 this.items.push(item);
26652 if(this.resizeTabs){
26653 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26654 this.autoSizeTabs();
26661 * Removes a {@link Roo.TabPanelItem}.
26662 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26664 removeTab : function(id){
26665 var items = this.items;
26666 var tab = items[id];
26667 if(!tab) { return; }
26668 var index = items.indexOf(tab);
26669 if(this.active == tab && items.length > 1){
26670 var newTab = this.getNextAvailable(index);
26675 this.stripEl.dom.removeChild(tab.pnode.dom);
26676 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26677 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26679 items.splice(index, 1);
26680 delete this.items[tab.id];
26681 tab.fireEvent("close", tab);
26682 tab.purgeListeners();
26683 this.autoSizeTabs();
26686 getNextAvailable : function(start){
26687 var items = this.items;
26689 // look for a next tab that will slide over to
26690 // replace the one being removed
26691 while(index < items.length){
26692 var item = items[++index];
26693 if(item && !item.isHidden()){
26697 // if one isn't found select the previous tab (on the left)
26700 var item = items[--index];
26701 if(item && !item.isHidden()){
26709 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26710 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26712 disableTab : function(id){
26713 var tab = this.items[id];
26714 if(tab && this.active != tab){
26720 * Enables a {@link Roo.TabPanelItem} that is disabled.
26721 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26723 enableTab : function(id){
26724 var tab = this.items[id];
26729 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26730 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26731 * @return {Roo.TabPanelItem} The TabPanelItem.
26733 activate : function(id){
26734 var tab = this.items[id];
26738 if(tab == this.active || tab.disabled){
26742 this.fireEvent("beforetabchange", this, e, tab);
26743 if(e.cancel !== true && !tab.disabled){
26745 this.active.hide();
26747 this.active = this.items[id];
26748 this.active.show();
26749 this.fireEvent("tabchange", this, this.active);
26755 * Gets the active {@link Roo.TabPanelItem}.
26756 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26758 getActiveTab : function(){
26759 return this.active;
26763 * Updates the tab body element to fit the height of the container element
26764 * for overflow scrolling
26765 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26767 syncHeight : function(targetHeight){
26768 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26769 var bm = this.bodyEl.getMargins();
26770 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26771 this.bodyEl.setHeight(newHeight);
26775 onResize : function(){
26776 if(this.monitorResize){
26777 this.autoSizeTabs();
26782 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26784 beginUpdate : function(){
26785 this.updating = true;
26789 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26791 endUpdate : function(){
26792 this.updating = false;
26793 this.autoSizeTabs();
26797 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26799 autoSizeTabs : function(){
26800 var count = this.items.length;
26801 var vcount = count - this.hiddenCount;
26802 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26803 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26804 var availWidth = Math.floor(w / vcount);
26805 var b = this.stripBody;
26806 if(b.getWidth() > w){
26807 var tabs = this.items;
26808 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26809 if(availWidth < this.minTabWidth){
26810 /*if(!this.sleft){ // incomplete scrolling code
26811 this.createScrollButtons();
26814 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26817 if(this.currentTabWidth < this.preferredTabWidth){
26818 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26824 * Returns the number of tabs in this TabPanel.
26827 getCount : function(){
26828 return this.items.length;
26832 * Resizes all the tabs to the passed width
26833 * @param {Number} The new width
26835 setTabWidth : function(width){
26836 this.currentTabWidth = width;
26837 for(var i = 0, len = this.items.length; i < len; i++) {
26838 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26843 * Destroys this TabPanel
26844 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26846 destroy : function(removeEl){
26847 Roo.EventManager.removeResizeListener(this.onResize, this);
26848 for(var i = 0, len = this.items.length; i < len; i++){
26849 this.items[i].purgeListeners();
26851 if(removeEl === true){
26852 this.el.update("");
26859 * @class Roo.TabPanelItem
26860 * @extends Roo.util.Observable
26861 * Represents an individual item (tab plus body) in a TabPanel.
26862 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26863 * @param {String} id The id of this TabPanelItem
26864 * @param {String} text The text for the tab of this TabPanelItem
26865 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26867 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26869 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26870 * @type Roo.TabPanel
26872 this.tabPanel = tabPanel;
26874 * The id for this TabPanelItem
26879 this.disabled = false;
26883 this.loaded = false;
26884 this.closable = closable;
26887 * The body element for this TabPanelItem.
26888 * @type Roo.Element
26890 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26891 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26892 this.bodyEl.setStyle("display", "block");
26893 this.bodyEl.setStyle("zoom", "1");
26896 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26898 this.el = Roo.get(els.el, true);
26899 this.inner = Roo.get(els.inner, true);
26900 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26901 this.pnode = Roo.get(els.el.parentNode, true);
26902 this.el.on("mousedown", this.onTabMouseDown, this);
26903 this.el.on("click", this.onTabClick, this);
26906 var c = Roo.get(els.close, true);
26907 c.dom.title = this.closeText;
26908 c.addClassOnOver("close-over");
26909 c.on("click", this.closeClick, this);
26915 * Fires when this tab becomes the active tab.
26916 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26917 * @param {Roo.TabPanelItem} this
26921 * @event beforeclose
26922 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26923 * @param {Roo.TabPanelItem} this
26924 * @param {Object} e Set cancel to true on this object to cancel the close.
26926 "beforeclose": true,
26929 * Fires when this tab is closed.
26930 * @param {Roo.TabPanelItem} this
26934 * @event deactivate
26935 * Fires when this tab is no longer the active tab.
26936 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26937 * @param {Roo.TabPanelItem} this
26939 "deactivate" : true
26941 this.hidden = false;
26943 Roo.TabPanelItem.superclass.constructor.call(this);
26946 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26947 purgeListeners : function(){
26948 Roo.util.Observable.prototype.purgeListeners.call(this);
26949 this.el.removeAllListeners();
26952 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26955 this.pnode.addClass("on");
26958 this.tabPanel.stripWrap.repaint();
26960 this.fireEvent("activate", this.tabPanel, this);
26964 * Returns true if this tab is the active tab.
26965 * @return {Boolean}
26967 isActive : function(){
26968 return this.tabPanel.getActiveTab() == this;
26972 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
26975 this.pnode.removeClass("on");
26977 this.fireEvent("deactivate", this.tabPanel, this);
26980 hideAction : function(){
26981 this.bodyEl.hide();
26982 this.bodyEl.setStyle("position", "absolute");
26983 this.bodyEl.setLeft("-20000px");
26984 this.bodyEl.setTop("-20000px");
26987 showAction : function(){
26988 this.bodyEl.setStyle("position", "relative");
26989 this.bodyEl.setTop("");
26990 this.bodyEl.setLeft("");
26991 this.bodyEl.show();
26995 * Set the tooltip for the tab.
26996 * @param {String} tooltip The tab's tooltip
26998 setTooltip : function(text){
26999 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27000 this.textEl.dom.qtip = text;
27001 this.textEl.dom.removeAttribute('title');
27003 this.textEl.dom.title = text;
27007 onTabClick : function(e){
27008 e.preventDefault();
27009 this.tabPanel.activate(this.id);
27012 onTabMouseDown : function(e){
27013 e.preventDefault();
27014 this.tabPanel.activate(this.id);
27017 getWidth : function(){
27018 return this.inner.getWidth();
27021 setWidth : function(width){
27022 var iwidth = width - this.pnode.getPadding("lr");
27023 this.inner.setWidth(iwidth);
27024 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27025 this.pnode.setWidth(width);
27029 * Show or hide the tab
27030 * @param {Boolean} hidden True to hide or false to show.
27032 setHidden : function(hidden){
27033 this.hidden = hidden;
27034 this.pnode.setStyle("display", hidden ? "none" : "");
27038 * Returns true if this tab is "hidden"
27039 * @return {Boolean}
27041 isHidden : function(){
27042 return this.hidden;
27046 * Returns the text for this tab
27049 getText : function(){
27053 autoSize : function(){
27054 //this.el.beginMeasure();
27055 this.textEl.setWidth(1);
27056 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
27057 //this.el.endMeasure();
27061 * Sets the text for the tab (Note: this also sets the tooltip text)
27062 * @param {String} text The tab's text and tooltip
27064 setText : function(text){
27066 this.textEl.update(text);
27067 this.setTooltip(text);
27068 if(!this.tabPanel.resizeTabs){
27073 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27075 activate : function(){
27076 this.tabPanel.activate(this.id);
27080 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27082 disable : function(){
27083 if(this.tabPanel.active != this){
27084 this.disabled = true;
27085 this.pnode.addClass("disabled");
27090 * Enables this TabPanelItem if it was previously disabled.
27092 enable : function(){
27093 this.disabled = false;
27094 this.pnode.removeClass("disabled");
27098 * Sets the content for this TabPanelItem.
27099 * @param {String} content The content
27100 * @param {Boolean} loadScripts true to look for and load scripts
27102 setContent : function(content, loadScripts){
27103 this.bodyEl.update(content, loadScripts);
27107 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27108 * @return {Roo.UpdateManager} The UpdateManager
27110 getUpdateManager : function(){
27111 return this.bodyEl.getUpdateManager();
27115 * Set a URL to be used to load the content for this TabPanelItem.
27116 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27117 * @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)
27118 * @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)
27119 * @return {Roo.UpdateManager} The UpdateManager
27121 setUrl : function(url, params, loadOnce){
27122 if(this.refreshDelegate){
27123 this.un('activate', this.refreshDelegate);
27125 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27126 this.on("activate", this.refreshDelegate);
27127 return this.bodyEl.getUpdateManager();
27131 _handleRefresh : function(url, params, loadOnce){
27132 if(!loadOnce || !this.loaded){
27133 var updater = this.bodyEl.getUpdateManager();
27134 updater.update(url, params, this._setLoaded.createDelegate(this));
27139 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27140 * Will fail silently if the setUrl method has not been called.
27141 * This does not activate the panel, just updates its content.
27143 refresh : function(){
27144 if(this.refreshDelegate){
27145 this.loaded = false;
27146 this.refreshDelegate();
27151 _setLoaded : function(){
27152 this.loaded = true;
27156 closeClick : function(e){
27159 this.fireEvent("beforeclose", this, o);
27160 if(o.cancel !== true){
27161 this.tabPanel.removeTab(this.id);
27165 * The text displayed in the tooltip for the close icon.
27168 closeText : "Close this tab"
27172 Roo.TabPanel.prototype.createStrip = function(container){
27173 var strip = document.createElement("div");
27174 strip.className = "x-tabs-wrap";
27175 container.appendChild(strip);
27179 Roo.TabPanel.prototype.createStripList = function(strip){
27180 // div wrapper for retard IE
27181 // returns the "tr" element.
27182 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27183 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27184 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27185 return strip.firstChild.firstChild.firstChild.firstChild;
27188 Roo.TabPanel.prototype.createBody = function(container){
27189 var body = document.createElement("div");
27190 Roo.id(body, "tab-body");
27191 Roo.fly(body).addClass("x-tabs-body");
27192 container.appendChild(body);
27196 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27197 var body = Roo.getDom(id);
27199 body = document.createElement("div");
27202 Roo.fly(body).addClass("x-tabs-item-body");
27203 bodyEl.insertBefore(body, bodyEl.firstChild);
27207 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27208 var td = document.createElement("td");
27209 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27210 //stripEl.appendChild(td);
27212 td.className = "x-tabs-closable";
27213 if(!this.closeTpl){
27214 this.closeTpl = new Roo.Template(
27215 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27216 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27217 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27220 var el = this.closeTpl.overwrite(td, {"text": text});
27221 var close = el.getElementsByTagName("div")[0];
27222 var inner = el.getElementsByTagName("em")[0];
27223 return {"el": el, "close": close, "inner": inner};
27226 this.tabTpl = new Roo.Template(
27227 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27228 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27231 var el = this.tabTpl.overwrite(td, {"text": text});
27232 var inner = el.getElementsByTagName("em")[0];
27233 return {"el": el, "inner": inner};
27237 * Ext JS Library 1.1.1
27238 * Copyright(c) 2006-2007, Ext JS, LLC.
27240 * Originally Released Under LGPL - original licence link has changed is not relivant.
27243 * <script type="text/javascript">
27247 * @class Roo.Button
27248 * @extends Roo.util.Observable
27249 * Simple Button class
27250 * @cfg {String} text The button text
27251 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27252 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27253 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27254 * @cfg {Object} scope The scope of the handler
27255 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27256 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27257 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27258 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27259 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27260 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27261 applies if enableToggle = true)
27262 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27263 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27264 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27266 * Create a new button
27267 * @param {Object} config The config object
27269 Roo.Button = function(renderTo, config)
27273 renderTo = config.renderTo || false;
27276 Roo.apply(this, config);
27280 * Fires when this button is clicked
27281 * @param {Button} this
27282 * @param {EventObject} e The click event
27287 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27288 * @param {Button} this
27289 * @param {Boolean} pressed
27294 * Fires when the mouse hovers over the button
27295 * @param {Button} this
27296 * @param {Event} e The event object
27298 'mouseover' : true,
27301 * Fires when the mouse exits the button
27302 * @param {Button} this
27303 * @param {Event} e The event object
27308 * Fires when the button is rendered
27309 * @param {Button} this
27314 this.menu = Roo.menu.MenuMgr.get(this.menu);
27316 // register listeners first!! - so render can be captured..
27317 Roo.util.Observable.call(this);
27319 this.render(renderTo);
27325 Roo.extend(Roo.Button, Roo.util.Observable, {
27331 * Read-only. True if this button is hidden
27336 * Read-only. True if this button is disabled
27341 * Read-only. True if this button is pressed (only if enableToggle = true)
27347 * @cfg {Number} tabIndex
27348 * The DOM tabIndex for this button (defaults to undefined)
27350 tabIndex : undefined,
27353 * @cfg {Boolean} enableToggle
27354 * True to enable pressed/not pressed toggling (defaults to false)
27356 enableToggle: false,
27358 * @cfg {Mixed} menu
27359 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27363 * @cfg {String} menuAlign
27364 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27366 menuAlign : "tl-bl?",
27369 * @cfg {String} iconCls
27370 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27372 iconCls : undefined,
27374 * @cfg {String} type
27375 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27380 menuClassTarget: 'tr',
27383 * @cfg {String} clickEvent
27384 * The type of event to map to the button's event handler (defaults to 'click')
27386 clickEvent : 'click',
27389 * @cfg {Boolean} handleMouseEvents
27390 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27392 handleMouseEvents : true,
27395 * @cfg {String} tooltipType
27396 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27398 tooltipType : 'qtip',
27401 * @cfg {String} cls
27402 * A CSS class to apply to the button's main element.
27406 * @cfg {Roo.Template} template (Optional)
27407 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27408 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27409 * require code modifications if required elements (e.g. a button) aren't present.
27413 render : function(renderTo){
27415 if(this.hideParent){
27416 this.parentEl = Roo.get(renderTo);
27418 if(!this.dhconfig){
27419 if(!this.template){
27420 if(!Roo.Button.buttonTemplate){
27421 // hideous table template
27422 Roo.Button.buttonTemplate = new Roo.Template(
27423 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27424 '<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>',
27425 "</tr></tbody></table>");
27427 this.template = Roo.Button.buttonTemplate;
27429 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27430 var btnEl = btn.child("button:first");
27431 btnEl.on('focus', this.onFocus, this);
27432 btnEl.on('blur', this.onBlur, this);
27434 btn.addClass(this.cls);
27437 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27440 btnEl.addClass(this.iconCls);
27442 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27445 if(this.tabIndex !== undefined){
27446 btnEl.dom.tabIndex = this.tabIndex;
27449 if(typeof this.tooltip == 'object'){
27450 Roo.QuickTips.tips(Roo.apply({
27454 btnEl.dom[this.tooltipType] = this.tooltip;
27458 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27462 this.el.dom.id = this.el.id = this.id;
27465 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27466 this.menu.on("show", this.onMenuShow, this);
27467 this.menu.on("hide", this.onMenuHide, this);
27469 btn.addClass("x-btn");
27470 if(Roo.isIE && !Roo.isIE7){
27471 this.autoWidth.defer(1, this);
27475 if(this.handleMouseEvents){
27476 btn.on("mouseover", this.onMouseOver, this);
27477 btn.on("mouseout", this.onMouseOut, this);
27478 btn.on("mousedown", this.onMouseDown, this);
27480 btn.on(this.clickEvent, this.onClick, this);
27481 //btn.on("mouseup", this.onMouseUp, this);
27488 Roo.ButtonToggleMgr.register(this);
27490 this.el.addClass("x-btn-pressed");
27493 var repeater = new Roo.util.ClickRepeater(btn,
27494 typeof this.repeat == "object" ? this.repeat : {}
27496 repeater.on("click", this.onClick, this);
27499 this.fireEvent('render', this);
27503 * Returns the button's underlying element
27504 * @return {Roo.Element} The element
27506 getEl : function(){
27511 * Destroys this Button and removes any listeners.
27513 destroy : function(){
27514 Roo.ButtonToggleMgr.unregister(this);
27515 this.el.removeAllListeners();
27516 this.purgeListeners();
27521 autoWidth : function(){
27523 this.el.setWidth("auto");
27524 if(Roo.isIE7 && Roo.isStrict){
27525 var ib = this.el.child('button');
27526 if(ib && ib.getWidth() > 20){
27528 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27533 this.el.beginMeasure();
27535 if(this.el.getWidth() < this.minWidth){
27536 this.el.setWidth(this.minWidth);
27539 this.el.endMeasure();
27546 * Assigns this button's click handler
27547 * @param {Function} handler The function to call when the button is clicked
27548 * @param {Object} scope (optional) Scope for the function passed in
27550 setHandler : function(handler, scope){
27551 this.handler = handler;
27552 this.scope = scope;
27556 * Sets this button's text
27557 * @param {String} text The button text
27559 setText : function(text){
27562 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27568 * Gets the text for this button
27569 * @return {String} The button text
27571 getText : function(){
27579 this.hidden = false;
27581 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27589 this.hidden = true;
27591 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27596 * Convenience function for boolean show/hide
27597 * @param {Boolean} visible True to show, false to hide
27599 setVisible: function(visible){
27608 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27609 * @param {Boolean} state (optional) Force a particular state
27611 toggle : function(state){
27612 state = state === undefined ? !this.pressed : state;
27613 if(state != this.pressed){
27615 this.el.addClass("x-btn-pressed");
27616 this.pressed = true;
27617 this.fireEvent("toggle", this, true);
27619 this.el.removeClass("x-btn-pressed");
27620 this.pressed = false;
27621 this.fireEvent("toggle", this, false);
27623 if(this.toggleHandler){
27624 this.toggleHandler.call(this.scope || this, this, state);
27632 focus : function(){
27633 this.el.child('button:first').focus();
27637 * Disable this button
27639 disable : function(){
27641 this.el.addClass("x-btn-disabled");
27643 this.disabled = true;
27647 * Enable this button
27649 enable : function(){
27651 this.el.removeClass("x-btn-disabled");
27653 this.disabled = false;
27657 * Convenience function for boolean enable/disable
27658 * @param {Boolean} enabled True to enable, false to disable
27660 setDisabled : function(v){
27661 this[v !== true ? "enable" : "disable"]();
27665 onClick : function(e){
27667 e.preventDefault();
27672 if(!this.disabled){
27673 if(this.enableToggle){
27676 if(this.menu && !this.menu.isVisible()){
27677 this.menu.show(this.el, this.menuAlign);
27679 this.fireEvent("click", this, e);
27681 this.el.removeClass("x-btn-over");
27682 this.handler.call(this.scope || this, this, e);
27687 onMouseOver : function(e){
27688 if(!this.disabled){
27689 this.el.addClass("x-btn-over");
27690 this.fireEvent('mouseover', this, e);
27694 onMouseOut : function(e){
27695 if(!e.within(this.el, true)){
27696 this.el.removeClass("x-btn-over");
27697 this.fireEvent('mouseout', this, e);
27701 onFocus : function(e){
27702 if(!this.disabled){
27703 this.el.addClass("x-btn-focus");
27707 onBlur : function(e){
27708 this.el.removeClass("x-btn-focus");
27711 onMouseDown : function(e){
27712 if(!this.disabled && e.button == 0){
27713 this.el.addClass("x-btn-click");
27714 Roo.get(document).on('mouseup', this.onMouseUp, this);
27718 onMouseUp : function(e){
27720 this.el.removeClass("x-btn-click");
27721 Roo.get(document).un('mouseup', this.onMouseUp, this);
27725 onMenuShow : function(e){
27726 this.el.addClass("x-btn-menu-active");
27729 onMenuHide : function(e){
27730 this.el.removeClass("x-btn-menu-active");
27734 // Private utility class used by Button
27735 Roo.ButtonToggleMgr = function(){
27738 function toggleGroup(btn, state){
27740 var g = groups[btn.toggleGroup];
27741 for(var i = 0, l = g.length; i < l; i++){
27743 g[i].toggle(false);
27750 register : function(btn){
27751 if(!btn.toggleGroup){
27754 var g = groups[btn.toggleGroup];
27756 g = groups[btn.toggleGroup] = [];
27759 btn.on("toggle", toggleGroup);
27762 unregister : function(btn){
27763 if(!btn.toggleGroup){
27766 var g = groups[btn.toggleGroup];
27769 btn.un("toggle", toggleGroup);
27775 * Ext JS Library 1.1.1
27776 * Copyright(c) 2006-2007, Ext JS, LLC.
27778 * Originally Released Under LGPL - original licence link has changed is not relivant.
27781 * <script type="text/javascript">
27785 * @class Roo.SplitButton
27786 * @extends Roo.Button
27787 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27788 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27789 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27790 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27791 * @cfg {String} arrowTooltip The title attribute of the arrow
27793 * Create a new menu button
27794 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27795 * @param {Object} config The config object
27797 Roo.SplitButton = function(renderTo, config){
27798 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27800 * @event arrowclick
27801 * Fires when this button's arrow is clicked
27802 * @param {SplitButton} this
27803 * @param {EventObject} e The click event
27805 this.addEvents({"arrowclick":true});
27808 Roo.extend(Roo.SplitButton, Roo.Button, {
27809 render : function(renderTo){
27810 // this is one sweet looking template!
27811 var tpl = new Roo.Template(
27812 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27813 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27814 '<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>',
27815 "</tbody></table></td><td>",
27816 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27817 '<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>',
27818 "</tbody></table></td></tr></table>"
27820 var btn = tpl.append(renderTo, [this.text, this.type], true);
27821 var btnEl = btn.child("button");
27823 btn.addClass(this.cls);
27826 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27829 btnEl.addClass(this.iconCls);
27831 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27835 if(this.handleMouseEvents){
27836 btn.on("mouseover", this.onMouseOver, this);
27837 btn.on("mouseout", this.onMouseOut, this);
27838 btn.on("mousedown", this.onMouseDown, this);
27839 btn.on("mouseup", this.onMouseUp, this);
27841 btn.on(this.clickEvent, this.onClick, this);
27843 if(typeof this.tooltip == 'object'){
27844 Roo.QuickTips.tips(Roo.apply({
27848 btnEl.dom[this.tooltipType] = this.tooltip;
27851 if(this.arrowTooltip){
27852 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27861 this.el.addClass("x-btn-pressed");
27863 if(Roo.isIE && !Roo.isIE7){
27864 this.autoWidth.defer(1, this);
27869 this.menu.on("show", this.onMenuShow, this);
27870 this.menu.on("hide", this.onMenuHide, this);
27872 this.fireEvent('render', this);
27876 autoWidth : function(){
27878 var tbl = this.el.child("table:first");
27879 var tbl2 = this.el.child("table:last");
27880 this.el.setWidth("auto");
27881 tbl.setWidth("auto");
27882 if(Roo.isIE7 && Roo.isStrict){
27883 var ib = this.el.child('button:first');
27884 if(ib && ib.getWidth() > 20){
27886 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27891 this.el.beginMeasure();
27893 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27894 tbl.setWidth(this.minWidth-tbl2.getWidth());
27897 this.el.endMeasure();
27900 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27904 * Sets this button's click handler
27905 * @param {Function} handler The function to call when the button is clicked
27906 * @param {Object} scope (optional) Scope for the function passed above
27908 setHandler : function(handler, scope){
27909 this.handler = handler;
27910 this.scope = scope;
27914 * Sets this button's arrow click handler
27915 * @param {Function} handler The function to call when the arrow is clicked
27916 * @param {Object} scope (optional) Scope for the function passed above
27918 setArrowHandler : function(handler, scope){
27919 this.arrowHandler = handler;
27920 this.scope = scope;
27926 focus : function(){
27928 this.el.child("button:first").focus();
27933 onClick : function(e){
27934 e.preventDefault();
27935 if(!this.disabled){
27936 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27937 if(this.menu && !this.menu.isVisible()){
27938 this.menu.show(this.el, this.menuAlign);
27940 this.fireEvent("arrowclick", this, e);
27941 if(this.arrowHandler){
27942 this.arrowHandler.call(this.scope || this, this, e);
27945 this.fireEvent("click", this, e);
27947 this.handler.call(this.scope || this, this, e);
27953 onMouseDown : function(e){
27954 if(!this.disabled){
27955 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27959 onMouseUp : function(e){
27960 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27965 // backwards compat
27966 Roo.MenuButton = Roo.SplitButton;/*
27968 * Ext JS Library 1.1.1
27969 * Copyright(c) 2006-2007, Ext JS, LLC.
27971 * Originally Released Under LGPL - original licence link has changed is not relivant.
27974 * <script type="text/javascript">
27978 * @class Roo.Toolbar
27979 * Basic Toolbar class.
27981 * Creates a new Toolbar
27982 * @param {Object} container The config object
27984 Roo.Toolbar = function(container, buttons, config)
27986 /// old consturctor format still supported..
27987 if(container instanceof Array){ // omit the container for later rendering
27988 buttons = container;
27992 if (typeof(container) == 'object' && container.xtype) {
27993 config = container;
27994 container = config.container;
27995 buttons = config.buttons || []; // not really - use items!!
27998 if (config && config.items) {
27999 xitems = config.items;
28000 delete config.items;
28002 Roo.apply(this, config);
28003 this.buttons = buttons;
28006 this.render(container);
28008 this.xitems = xitems;
28009 Roo.each(xitems, function(b) {
28015 Roo.Toolbar.prototype = {
28017 * @cfg {Array} items
28018 * array of button configs or elements to add (will be converted to a MixedCollection)
28022 * @cfg {String/HTMLElement/Element} container
28023 * The id or element that will contain the toolbar
28026 render : function(ct){
28027 this.el = Roo.get(ct);
28029 this.el.addClass(this.cls);
28031 // using a table allows for vertical alignment
28032 // 100% width is needed by Safari...
28033 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28034 this.tr = this.el.child("tr", true);
28036 this.items = new Roo.util.MixedCollection(false, function(o){
28037 return o.id || ("item" + (++autoId));
28040 this.add.apply(this, this.buttons);
28041 delete this.buttons;
28046 * Adds element(s) to the toolbar -- this function takes a variable number of
28047 * arguments of mixed type and adds them to the toolbar.
28048 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28050 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28051 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28052 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28053 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28054 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28055 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28056 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28057 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28058 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28060 * @param {Mixed} arg2
28061 * @param {Mixed} etc.
28064 var a = arguments, l = a.length;
28065 for(var i = 0; i < l; i++){
28070 _add : function(el) {
28073 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28076 if (el.applyTo){ // some kind of form field
28077 return this.addField(el);
28079 if (el.render){ // some kind of Toolbar.Item
28080 return this.addItem(el);
28082 if (typeof el == "string"){ // string
28083 if(el == "separator" || el == "-"){
28084 return this.addSeparator();
28087 return this.addSpacer();
28090 return this.addFill();
28092 return this.addText(el);
28095 if(el.tagName){ // element
28096 return this.addElement(el);
28098 if(typeof el == "object"){ // must be button config?
28099 return this.addButton(el);
28101 // and now what?!?!
28107 * Add an Xtype element
28108 * @param {Object} xtype Xtype Object
28109 * @return {Object} created Object
28111 addxtype : function(e){
28112 return this.add(e);
28116 * Returns the Element for this toolbar.
28117 * @return {Roo.Element}
28119 getEl : function(){
28125 * @return {Roo.Toolbar.Item} The separator item
28127 addSeparator : function(){
28128 return this.addItem(new Roo.Toolbar.Separator());
28132 * Adds a spacer element
28133 * @return {Roo.Toolbar.Spacer} The spacer item
28135 addSpacer : function(){
28136 return this.addItem(new Roo.Toolbar.Spacer());
28140 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28141 * @return {Roo.Toolbar.Fill} The fill item
28143 addFill : function(){
28144 return this.addItem(new Roo.Toolbar.Fill());
28148 * Adds any standard HTML element to the toolbar
28149 * @param {String/HTMLElement/Element} el The element or id of the element to add
28150 * @return {Roo.Toolbar.Item} The element's item
28152 addElement : function(el){
28153 return this.addItem(new Roo.Toolbar.Item(el));
28156 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28157 * @type Roo.util.MixedCollection
28162 * Adds any Toolbar.Item or subclass
28163 * @param {Roo.Toolbar.Item} item
28164 * @return {Roo.Toolbar.Item} The item
28166 addItem : function(item){
28167 var td = this.nextBlock();
28169 this.items.add(item);
28174 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28175 * @param {Object/Array} config A button config or array of configs
28176 * @return {Roo.Toolbar.Button/Array}
28178 addButton : function(config){
28179 if(config instanceof Array){
28181 for(var i = 0, len = config.length; i < len; i++) {
28182 buttons.push(this.addButton(config[i]));
28187 if(!(config instanceof Roo.Toolbar.Button)){
28189 new Roo.Toolbar.SplitButton(config) :
28190 new Roo.Toolbar.Button(config);
28192 var td = this.nextBlock();
28199 * Adds text to the toolbar
28200 * @param {String} text The text to add
28201 * @return {Roo.Toolbar.Item} The element's item
28203 addText : function(text){
28204 return this.addItem(new Roo.Toolbar.TextItem(text));
28208 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28209 * @param {Number} index The index where the item is to be inserted
28210 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28211 * @return {Roo.Toolbar.Button/Item}
28213 insertButton : function(index, item){
28214 if(item instanceof Array){
28216 for(var i = 0, len = item.length; i < len; i++) {
28217 buttons.push(this.insertButton(index + i, item[i]));
28221 if (!(item instanceof Roo.Toolbar.Button)){
28222 item = new Roo.Toolbar.Button(item);
28224 var td = document.createElement("td");
28225 this.tr.insertBefore(td, this.tr.childNodes[index]);
28227 this.items.insert(index, item);
28232 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28233 * @param {Object} config
28234 * @return {Roo.Toolbar.Item} The element's item
28236 addDom : function(config, returnEl){
28237 var td = this.nextBlock();
28238 Roo.DomHelper.overwrite(td, config);
28239 var ti = new Roo.Toolbar.Item(td.firstChild);
28241 this.items.add(ti);
28246 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28247 * @type Roo.util.MixedCollection
28252 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28253 * Note: the field should not have been rendered yet. For a field that has already been
28254 * rendered, use {@link #addElement}.
28255 * @param {Roo.form.Field} field
28256 * @return {Roo.ToolbarItem}
28260 addField : function(field) {
28261 if (!this.fields) {
28263 this.fields = new Roo.util.MixedCollection(false, function(o){
28264 return o.id || ("item" + (++autoId));
28269 var td = this.nextBlock();
28271 var ti = new Roo.Toolbar.Item(td.firstChild);
28273 this.items.add(ti);
28274 this.fields.add(field);
28285 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28286 this.el.child('div').hide();
28294 this.el.child('div').show();
28298 nextBlock : function(){
28299 var td = document.createElement("td");
28300 this.tr.appendChild(td);
28305 destroy : function(){
28306 if(this.items){ // rendered?
28307 Roo.destroy.apply(Roo, this.items.items);
28309 if(this.fields){ // rendered?
28310 Roo.destroy.apply(Roo, this.fields.items);
28312 Roo.Element.uncache(this.el, this.tr);
28317 * @class Roo.Toolbar.Item
28318 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28320 * Creates a new Item
28321 * @param {HTMLElement} el
28323 Roo.Toolbar.Item = function(el){
28324 this.el = Roo.getDom(el);
28325 this.id = Roo.id(this.el);
28326 this.hidden = false;
28329 Roo.Toolbar.Item.prototype = {
28332 * Get this item's HTML Element
28333 * @return {HTMLElement}
28335 getEl : function(){
28340 render : function(td){
28342 td.appendChild(this.el);
28346 * Removes and destroys this item.
28348 destroy : function(){
28349 this.td.parentNode.removeChild(this.td);
28356 this.hidden = false;
28357 this.td.style.display = "";
28364 this.hidden = true;
28365 this.td.style.display = "none";
28369 * Convenience function for boolean show/hide.
28370 * @param {Boolean} visible true to show/false to hide
28372 setVisible: function(visible){
28381 * Try to focus this item.
28383 focus : function(){
28384 Roo.fly(this.el).focus();
28388 * Disables this item.
28390 disable : function(){
28391 Roo.fly(this.td).addClass("x-item-disabled");
28392 this.disabled = true;
28393 this.el.disabled = true;
28397 * Enables this item.
28399 enable : function(){
28400 Roo.fly(this.td).removeClass("x-item-disabled");
28401 this.disabled = false;
28402 this.el.disabled = false;
28408 * @class Roo.Toolbar.Separator
28409 * @extends Roo.Toolbar.Item
28410 * A simple toolbar separator class
28412 * Creates a new Separator
28414 Roo.Toolbar.Separator = function(){
28415 var s = document.createElement("span");
28416 s.className = "ytb-sep";
28417 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28419 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28420 enable:Roo.emptyFn,
28421 disable:Roo.emptyFn,
28426 * @class Roo.Toolbar.Spacer
28427 * @extends Roo.Toolbar.Item
28428 * A simple element that adds extra horizontal space to a toolbar.
28430 * Creates a new Spacer
28432 Roo.Toolbar.Spacer = function(){
28433 var s = document.createElement("div");
28434 s.className = "ytb-spacer";
28435 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28437 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28438 enable:Roo.emptyFn,
28439 disable:Roo.emptyFn,
28444 * @class Roo.Toolbar.Fill
28445 * @extends Roo.Toolbar.Spacer
28446 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28448 * Creates a new Spacer
28450 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28452 render : function(td){
28453 td.style.width = '100%';
28454 Roo.Toolbar.Fill.superclass.render.call(this, td);
28459 * @class Roo.Toolbar.TextItem
28460 * @extends Roo.Toolbar.Item
28461 * A simple class that renders text directly into a toolbar.
28463 * Creates a new TextItem
28464 * @param {String} text
28466 Roo.Toolbar.TextItem = function(text){
28467 if (typeof(text) == 'object') {
28470 var s = document.createElement("span");
28471 s.className = "ytb-text";
28472 s.innerHTML = text;
28473 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28475 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28476 enable:Roo.emptyFn,
28477 disable:Roo.emptyFn,
28482 * @class Roo.Toolbar.Button
28483 * @extends Roo.Button
28484 * A button that renders into a toolbar.
28486 * Creates a new Button
28487 * @param {Object} config A standard {@link Roo.Button} config object
28489 Roo.Toolbar.Button = function(config){
28490 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28492 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28493 render : function(td){
28495 Roo.Toolbar.Button.superclass.render.call(this, td);
28499 * Removes and destroys this button
28501 destroy : function(){
28502 Roo.Toolbar.Button.superclass.destroy.call(this);
28503 this.td.parentNode.removeChild(this.td);
28507 * Shows this button
28510 this.hidden = false;
28511 this.td.style.display = "";
28515 * Hides this button
28518 this.hidden = true;
28519 this.td.style.display = "none";
28523 * Disables this item
28525 disable : function(){
28526 Roo.fly(this.td).addClass("x-item-disabled");
28527 this.disabled = true;
28531 * Enables this item
28533 enable : function(){
28534 Roo.fly(this.td).removeClass("x-item-disabled");
28535 this.disabled = false;
28538 // backwards compat
28539 Roo.ToolbarButton = Roo.Toolbar.Button;
28542 * @class Roo.Toolbar.SplitButton
28543 * @extends Roo.SplitButton
28544 * A menu button that renders into a toolbar.
28546 * Creates a new SplitButton
28547 * @param {Object} config A standard {@link Roo.SplitButton} config object
28549 Roo.Toolbar.SplitButton = function(config){
28550 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28552 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28553 render : function(td){
28555 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28559 * Removes and destroys this button
28561 destroy : function(){
28562 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28563 this.td.parentNode.removeChild(this.td);
28567 * Shows this button
28570 this.hidden = false;
28571 this.td.style.display = "";
28575 * Hides this button
28578 this.hidden = true;
28579 this.td.style.display = "none";
28583 // backwards compat
28584 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28586 * Ext JS Library 1.1.1
28587 * Copyright(c) 2006-2007, Ext JS, LLC.
28589 * Originally Released Under LGPL - original licence link has changed is not relivant.
28592 * <script type="text/javascript">
28596 * @class Roo.PagingToolbar
28597 * @extends Roo.Toolbar
28598 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28600 * Create a new PagingToolbar
28601 * @param {Object} config The config object
28603 Roo.PagingToolbar = function(el, ds, config)
28605 // old args format still supported... - xtype is prefered..
28606 if (typeof(el) == 'object' && el.xtype) {
28607 // created from xtype...
28609 ds = el.dataSource;
28610 el = config.container;
28613 if (config.items) {
28614 items = config.items;
28618 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28621 this.renderButtons(this.el);
28624 // supprot items array.
28626 Roo.each(items, function(e) {
28627 this.add(Roo.factory(e));
28632 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28634 * @cfg {Roo.data.Store} dataSource
28635 * The underlying data store providing the paged data
28638 * @cfg {String/HTMLElement/Element} container
28639 * container The id or element that will contain the toolbar
28642 * @cfg {Boolean} displayInfo
28643 * True to display the displayMsg (defaults to false)
28646 * @cfg {Number} pageSize
28647 * The number of records to display per page (defaults to 20)
28651 * @cfg {String} displayMsg
28652 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28654 displayMsg : 'Displaying {0} - {1} of {2}',
28656 * @cfg {String} emptyMsg
28657 * The message to display when no records are found (defaults to "No data to display")
28659 emptyMsg : 'No data to display',
28661 * Customizable piece of the default paging text (defaults to "Page")
28664 beforePageText : "Page",
28666 * Customizable piece of the default paging text (defaults to "of %0")
28669 afterPageText : "of {0}",
28671 * Customizable piece of the default paging text (defaults to "First Page")
28674 firstText : "First Page",
28676 * Customizable piece of the default paging text (defaults to "Previous Page")
28679 prevText : "Previous Page",
28681 * Customizable piece of the default paging text (defaults to "Next Page")
28684 nextText : "Next Page",
28686 * Customizable piece of the default paging text (defaults to "Last Page")
28689 lastText : "Last Page",
28691 * Customizable piece of the default paging text (defaults to "Refresh")
28694 refreshText : "Refresh",
28697 renderButtons : function(el){
28698 Roo.PagingToolbar.superclass.render.call(this, el);
28699 this.first = this.addButton({
28700 tooltip: this.firstText,
28701 cls: "x-btn-icon x-grid-page-first",
28703 handler: this.onClick.createDelegate(this, ["first"])
28705 this.prev = this.addButton({
28706 tooltip: this.prevText,
28707 cls: "x-btn-icon x-grid-page-prev",
28709 handler: this.onClick.createDelegate(this, ["prev"])
28711 //this.addSeparator();
28712 this.add(this.beforePageText);
28713 this.field = Roo.get(this.addDom({
28718 cls: "x-grid-page-number"
28720 this.field.on("keydown", this.onPagingKeydown, this);
28721 this.field.on("focus", function(){this.dom.select();});
28722 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28723 this.field.setHeight(18);
28724 //this.addSeparator();
28725 this.next = this.addButton({
28726 tooltip: this.nextText,
28727 cls: "x-btn-icon x-grid-page-next",
28729 handler: this.onClick.createDelegate(this, ["next"])
28731 this.last = this.addButton({
28732 tooltip: this.lastText,
28733 cls: "x-btn-icon x-grid-page-last",
28735 handler: this.onClick.createDelegate(this, ["last"])
28737 //this.addSeparator();
28738 this.loading = this.addButton({
28739 tooltip: this.refreshText,
28740 cls: "x-btn-icon x-grid-loading",
28741 handler: this.onClick.createDelegate(this, ["refresh"])
28744 if(this.displayInfo){
28745 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28750 updateInfo : function(){
28751 if(this.displayEl){
28752 var count = this.ds.getCount();
28753 var msg = count == 0 ?
28757 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28759 this.displayEl.update(msg);
28764 onLoad : function(ds, r, o){
28765 this.cursor = o.params ? o.params.start : 0;
28766 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28768 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28769 this.field.dom.value = ap;
28770 this.first.setDisabled(ap == 1);
28771 this.prev.setDisabled(ap == 1);
28772 this.next.setDisabled(ap == ps);
28773 this.last.setDisabled(ap == ps);
28774 this.loading.enable();
28779 getPageData : function(){
28780 var total = this.ds.getTotalCount();
28783 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28784 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28789 onLoadError : function(){
28790 this.loading.enable();
28794 onPagingKeydown : function(e){
28795 var k = e.getKey();
28796 var d = this.getPageData();
28798 var v = this.field.dom.value, pageNum;
28799 if(!v || isNaN(pageNum = parseInt(v, 10))){
28800 this.field.dom.value = d.activePage;
28803 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28804 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28807 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))
28809 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28810 this.field.dom.value = pageNum;
28811 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28814 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28816 var v = this.field.dom.value, pageNum;
28817 var increment = (e.shiftKey) ? 10 : 1;
28818 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28820 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28821 this.field.dom.value = d.activePage;
28824 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28826 this.field.dom.value = parseInt(v, 10) + increment;
28827 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28828 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28835 beforeLoad : function(){
28837 this.loading.disable();
28842 onClick : function(which){
28846 ds.load({params:{start: 0, limit: this.pageSize}});
28849 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28852 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28855 var total = ds.getTotalCount();
28856 var extra = total % this.pageSize;
28857 var lastStart = extra ? (total - extra) : total-this.pageSize;
28858 ds.load({params:{start: lastStart, limit: this.pageSize}});
28861 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28867 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28868 * @param {Roo.data.Store} store The data store to unbind
28870 unbind : function(ds){
28871 ds.un("beforeload", this.beforeLoad, this);
28872 ds.un("load", this.onLoad, this);
28873 ds.un("loadexception", this.onLoadError, this);
28874 ds.un("remove", this.updateInfo, this);
28875 ds.un("add", this.updateInfo, this);
28876 this.ds = undefined;
28880 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28881 * @param {Roo.data.Store} store The data store to bind
28883 bind : function(ds){
28884 ds.on("beforeload", this.beforeLoad, this);
28885 ds.on("load", this.onLoad, this);
28886 ds.on("loadexception", this.onLoadError, this);
28887 ds.on("remove", this.updateInfo, this);
28888 ds.on("add", this.updateInfo, this);
28893 * Ext JS Library 1.1.1
28894 * Copyright(c) 2006-2007, Ext JS, LLC.
28896 * Originally Released Under LGPL - original licence link has changed is not relivant.
28899 * <script type="text/javascript">
28903 * @class Roo.Resizable
28904 * @extends Roo.util.Observable
28905 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28906 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28907 * 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
28908 * the element will be wrapped for you automatically.</p>
28909 * <p>Here is the list of valid resize handles:</p>
28912 ------ -------------------
28921 'hd' horizontal drag
28924 * <p>Here's an example showing the creation of a typical Resizable:</p>
28926 var resizer = new Roo.Resizable("element-id", {
28934 resizer.on("resize", myHandler);
28936 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28937 * resizer.east.setDisplayed(false);</p>
28938 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28939 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28940 * resize operation's new size (defaults to [0, 0])
28941 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28942 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28943 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28944 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28945 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28946 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28947 * @cfg {Number} width The width of the element in pixels (defaults to null)
28948 * @cfg {Number} height The height of the element in pixels (defaults to null)
28949 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28950 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28951 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28952 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28953 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28954 * in favor of the handles config option (defaults to false)
28955 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28956 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28957 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28958 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28959 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28960 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28961 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28962 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28963 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28964 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28965 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28967 * Create a new resizable component
28968 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28969 * @param {Object} config configuration options
28971 Roo.Resizable = function(el, config)
28973 this.el = Roo.get(el);
28975 if(config && config.wrap){
28976 config.resizeChild = this.el;
28977 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
28978 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
28979 this.el.setStyle("overflow", "hidden");
28980 this.el.setPositioning(config.resizeChild.getPositioning());
28981 config.resizeChild.clearPositioning();
28982 if(!config.width || !config.height){
28983 var csize = config.resizeChild.getSize();
28984 this.el.setSize(csize.width, csize.height);
28986 if(config.pinned && !config.adjustments){
28987 config.adjustments = "auto";
28991 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
28992 this.proxy.unselectable();
28993 this.proxy.enableDisplayMode('block');
28995 Roo.apply(this, config);
28998 this.disableTrackOver = true;
28999 this.el.addClass("x-resizable-pinned");
29001 // if the element isn't positioned, make it relative
29002 var position = this.el.getStyle("position");
29003 if(position != "absolute" && position != "fixed"){
29004 this.el.setStyle("position", "relative");
29006 if(!this.handles){ // no handles passed, must be legacy style
29007 this.handles = 's,e,se';
29008 if(this.multiDirectional){
29009 this.handles += ',n,w';
29012 if(this.handles == "all"){
29013 this.handles = "n s e w ne nw se sw";
29015 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29016 var ps = Roo.Resizable.positions;
29017 for(var i = 0, len = hs.length; i < len; i++){
29018 if(hs[i] && ps[hs[i]]){
29019 var pos = ps[hs[i]];
29020 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29024 this.corner = this.southeast;
29026 // updateBox = the box can move..
29027 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29028 this.updateBox = true;
29031 this.activeHandle = null;
29033 if(this.resizeChild){
29034 if(typeof this.resizeChild == "boolean"){
29035 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29037 this.resizeChild = Roo.get(this.resizeChild, true);
29041 if(this.adjustments == "auto"){
29042 var rc = this.resizeChild;
29043 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29044 if(rc && (hw || hn)){
29045 rc.position("relative");
29046 rc.setLeft(hw ? hw.el.getWidth() : 0);
29047 rc.setTop(hn ? hn.el.getHeight() : 0);
29049 this.adjustments = [
29050 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29051 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29055 if(this.draggable){
29056 this.dd = this.dynamic ?
29057 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29058 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29064 * @event beforeresize
29065 * Fired before resize is allowed. Set enabled to false to cancel resize.
29066 * @param {Roo.Resizable} this
29067 * @param {Roo.EventObject} e The mousedown event
29069 "beforeresize" : true,
29072 * Fired a resizing.
29073 * @param {Roo.Resizable} this
29074 * @param {Number} x The new x position
29075 * @param {Number} y The new y position
29076 * @param {Number} w The new w width
29077 * @param {Number} h The new h hight
29078 * @param {Roo.EventObject} e The mouseup event
29083 * Fired after a resize.
29084 * @param {Roo.Resizable} this
29085 * @param {Number} width The new width
29086 * @param {Number} height The new height
29087 * @param {Roo.EventObject} e The mouseup event
29092 if(this.width !== null && this.height !== null){
29093 this.resizeTo(this.width, this.height);
29095 this.updateChildSize();
29098 this.el.dom.style.zoom = 1;
29100 Roo.Resizable.superclass.constructor.call(this);
29103 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29104 resizeChild : false,
29105 adjustments : [0, 0],
29115 multiDirectional : false,
29116 disableTrackOver : false,
29117 easing : 'easeOutStrong',
29118 widthIncrement : 0,
29119 heightIncrement : 0,
29123 preserveRatio : false,
29124 transparent: false,
29130 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29132 constrainTo: undefined,
29134 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29136 resizeRegion: undefined,
29140 * Perform a manual resize
29141 * @param {Number} width
29142 * @param {Number} height
29144 resizeTo : function(width, height){
29145 this.el.setSize(width, height);
29146 this.updateChildSize();
29147 this.fireEvent("resize", this, width, height, null);
29151 startSizing : function(e, handle){
29152 this.fireEvent("beforeresize", this, e);
29153 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29156 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29157 this.overlay.unselectable();
29158 this.overlay.enableDisplayMode("block");
29159 this.overlay.on("mousemove", this.onMouseMove, this);
29160 this.overlay.on("mouseup", this.onMouseUp, this);
29162 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29164 this.resizing = true;
29165 this.startBox = this.el.getBox();
29166 this.startPoint = e.getXY();
29167 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29168 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29170 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29171 this.overlay.show();
29173 if(this.constrainTo) {
29174 var ct = Roo.get(this.constrainTo);
29175 this.resizeRegion = ct.getRegion().adjust(
29176 ct.getFrameWidth('t'),
29177 ct.getFrameWidth('l'),
29178 -ct.getFrameWidth('b'),
29179 -ct.getFrameWidth('r')
29183 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29185 this.proxy.setBox(this.startBox);
29187 this.proxy.setStyle('visibility', 'visible');
29193 onMouseDown : function(handle, e){
29196 this.activeHandle = handle;
29197 this.startSizing(e, handle);
29202 onMouseUp : function(e){
29203 var size = this.resizeElement();
29204 this.resizing = false;
29206 this.overlay.hide();
29208 this.fireEvent("resize", this, size.width, size.height, e);
29212 updateChildSize : function(){
29214 if(this.resizeChild){
29216 var child = this.resizeChild;
29217 var adj = this.adjustments;
29218 if(el.dom.offsetWidth){
29219 var b = el.getSize(true);
29220 child.setSize(b.width+adj[0], b.height+adj[1]);
29222 // Second call here for IE
29223 // The first call enables instant resizing and
29224 // the second call corrects scroll bars if they
29227 setTimeout(function(){
29228 if(el.dom.offsetWidth){
29229 var b = el.getSize(true);
29230 child.setSize(b.width+adj[0], b.height+adj[1]);
29238 snap : function(value, inc, min){
29239 if(!inc || !value) return value;
29240 var newValue = value;
29241 var m = value % inc;
29244 newValue = value + (inc-m);
29246 newValue = value - m;
29249 return Math.max(min, newValue);
29253 resizeElement : function(){
29254 var box = this.proxy.getBox();
29255 if(this.updateBox){
29256 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29258 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29260 this.updateChildSize();
29268 constrain : function(v, diff, m, mx){
29271 }else if(v - diff > mx){
29278 onMouseMove : function(e){
29281 try{// try catch so if something goes wrong the user doesn't get hung
29283 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29287 //var curXY = this.startPoint;
29288 var curSize = this.curSize || this.startBox;
29289 var x = this.startBox.x, y = this.startBox.y;
29290 var ox = x, oy = y;
29291 var w = curSize.width, h = curSize.height;
29292 var ow = w, oh = h;
29293 var mw = this.minWidth, mh = this.minHeight;
29294 var mxw = this.maxWidth, mxh = this.maxHeight;
29295 var wi = this.widthIncrement;
29296 var hi = this.heightIncrement;
29298 var eventXY = e.getXY();
29299 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29300 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29302 var pos = this.activeHandle.position;
29307 w = Math.min(Math.max(mw, w), mxw);
29312 h = Math.min(Math.max(mh, h), mxh);
29317 w = Math.min(Math.max(mw, w), mxw);
29318 h = Math.min(Math.max(mh, h), mxh);
29321 diffY = this.constrain(h, diffY, mh, mxh);
29328 var adiffX = Math.abs(diffX);
29329 var sub = (adiffX % wi); // how much
29330 if (sub > (wi/2)) { // far enough to snap
29331 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29333 // remove difference..
29334 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29338 x = Math.max(this.minX, x);
29341 diffX = this.constrain(w, diffX, mw, mxw);
29347 w = Math.min(Math.max(mw, w), mxw);
29348 diffY = this.constrain(h, diffY, mh, mxh);
29353 diffX = this.constrain(w, diffX, mw, mxw);
29354 diffY = this.constrain(h, diffY, mh, mxh);
29361 diffX = this.constrain(w, diffX, mw, mxw);
29363 h = Math.min(Math.max(mh, h), mxh);
29369 var sw = this.snap(w, wi, mw);
29370 var sh = this.snap(h, hi, mh);
29371 if(sw != w || sh != h){
29394 if(this.preserveRatio){
29399 h = Math.min(Math.max(mh, h), mxh);
29404 w = Math.min(Math.max(mw, w), mxw);
29409 w = Math.min(Math.max(mw, w), mxw);
29415 w = Math.min(Math.max(mw, w), mxw);
29421 h = Math.min(Math.max(mh, h), mxh);
29429 h = Math.min(Math.max(mh, h), mxh);
29439 h = Math.min(Math.max(mh, h), mxh);
29447 if (pos == 'hdrag') {
29450 this.proxy.setBounds(x, y, w, h);
29452 this.resizeElement();
29456 this.fireEvent("resizing", this, x, y, w, h, e);
29460 handleOver : function(){
29462 this.el.addClass("x-resizable-over");
29467 handleOut : function(){
29468 if(!this.resizing){
29469 this.el.removeClass("x-resizable-over");
29474 * Returns the element this component is bound to.
29475 * @return {Roo.Element}
29477 getEl : function(){
29482 * Returns the resizeChild element (or null).
29483 * @return {Roo.Element}
29485 getResizeChild : function(){
29486 return this.resizeChild;
29488 groupHandler : function()
29493 * Destroys this resizable. If the element was wrapped and
29494 * removeEl is not true then the element remains.
29495 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29497 destroy : function(removeEl){
29498 this.proxy.remove();
29500 this.overlay.removeAllListeners();
29501 this.overlay.remove();
29503 var ps = Roo.Resizable.positions;
29505 if(typeof ps[k] != "function" && this[ps[k]]){
29506 var h = this[ps[k]];
29507 h.el.removeAllListeners();
29512 this.el.update("");
29519 // hash to map config positions to true positions
29520 Roo.Resizable.positions = {
29521 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29526 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29528 // only initialize the template if resizable is used
29529 var tpl = Roo.DomHelper.createTemplate(
29530 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29533 Roo.Resizable.Handle.prototype.tpl = tpl;
29535 this.position = pos;
29537 // show north drag fro topdra
29538 var handlepos = pos == 'hdrag' ? 'north' : pos;
29540 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29541 if (pos == 'hdrag') {
29542 this.el.setStyle('cursor', 'pointer');
29544 this.el.unselectable();
29546 this.el.setOpacity(0);
29548 this.el.on("mousedown", this.onMouseDown, this);
29549 if(!disableTrackOver){
29550 this.el.on("mouseover", this.onMouseOver, this);
29551 this.el.on("mouseout", this.onMouseOut, this);
29556 Roo.Resizable.Handle.prototype = {
29557 afterResize : function(rz){
29561 onMouseDown : function(e){
29562 this.rz.onMouseDown(this, e);
29565 onMouseOver : function(e){
29566 this.rz.handleOver(this, e);
29569 onMouseOut : function(e){
29570 this.rz.handleOut(this, e);
29574 * Ext JS Library 1.1.1
29575 * Copyright(c) 2006-2007, Ext JS, LLC.
29577 * Originally Released Under LGPL - original licence link has changed is not relivant.
29580 * <script type="text/javascript">
29584 * @class Roo.Editor
29585 * @extends Roo.Component
29586 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29588 * Create a new Editor
29589 * @param {Roo.form.Field} field The Field object (or descendant)
29590 * @param {Object} config The config object
29592 Roo.Editor = function(field, config){
29593 Roo.Editor.superclass.constructor.call(this, config);
29594 this.field = field;
29597 * @event beforestartedit
29598 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29599 * false from the handler of this event.
29600 * @param {Editor} this
29601 * @param {Roo.Element} boundEl The underlying element bound to this editor
29602 * @param {Mixed} value The field value being set
29604 "beforestartedit" : true,
29607 * Fires when this editor is displayed
29608 * @param {Roo.Element} boundEl The underlying element bound to this editor
29609 * @param {Mixed} value The starting field value
29611 "startedit" : true,
29613 * @event beforecomplete
29614 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29615 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29616 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29617 * event will not fire since no edit actually occurred.
29618 * @param {Editor} this
29619 * @param {Mixed} value The current field value
29620 * @param {Mixed} startValue The original field value
29622 "beforecomplete" : true,
29625 * Fires after editing is complete and any changed value has been written to the underlying field.
29626 * @param {Editor} this
29627 * @param {Mixed} value The current field value
29628 * @param {Mixed} startValue The original field value
29632 * @event specialkey
29633 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29634 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29635 * @param {Roo.form.Field} this
29636 * @param {Roo.EventObject} e The event object
29638 "specialkey" : true
29642 Roo.extend(Roo.Editor, Roo.Component, {
29644 * @cfg {Boolean/String} autosize
29645 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29646 * or "height" to adopt the height only (defaults to false)
29649 * @cfg {Boolean} revertInvalid
29650 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29651 * validation fails (defaults to true)
29654 * @cfg {Boolean} ignoreNoChange
29655 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29656 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29657 * will never be ignored.
29660 * @cfg {Boolean} hideEl
29661 * False to keep the bound element visible while the editor is displayed (defaults to true)
29664 * @cfg {Mixed} value
29665 * The data value of the underlying field (defaults to "")
29669 * @cfg {String} alignment
29670 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29674 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29675 * for bottom-right shadow (defaults to "frame")
29679 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29683 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29685 completeOnEnter : false,
29687 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29689 cancelOnEsc : false,
29691 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29696 onRender : function(ct, position){
29697 this.el = new Roo.Layer({
29698 shadow: this.shadow,
29704 constrain: this.constrain
29706 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29707 if(this.field.msgTarget != 'title'){
29708 this.field.msgTarget = 'qtip';
29710 this.field.render(this.el);
29712 this.field.el.dom.setAttribute('autocomplete', 'off');
29714 this.field.on("specialkey", this.onSpecialKey, this);
29715 if(this.swallowKeys){
29716 this.field.el.swallowEvent(['keydown','keypress']);
29719 this.field.on("blur", this.onBlur, this);
29720 if(this.field.grow){
29721 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29725 onSpecialKey : function(field, e)
29727 //Roo.log('editor onSpecialKey');
29728 if(this.completeOnEnter && e.getKey() == e.ENTER){
29730 this.completeEdit();
29733 // do not fire special key otherwise it might hide close the editor...
29734 if(e.getKey() == e.ENTER){
29737 if(this.cancelOnEsc && e.getKey() == e.ESC){
29741 this.fireEvent('specialkey', field, e);
29746 * Starts the editing process and shows the editor.
29747 * @param {String/HTMLElement/Element} el The element to edit
29748 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29749 * to the innerHTML of el.
29751 startEdit : function(el, value){
29753 this.completeEdit();
29755 this.boundEl = Roo.get(el);
29756 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29757 if(!this.rendered){
29758 this.render(this.parentEl || document.body);
29760 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29763 this.startValue = v;
29764 this.field.setValue(v);
29766 var sz = this.boundEl.getSize();
29767 switch(this.autoSize){
29769 this.setSize(sz.width, "");
29772 this.setSize("", sz.height);
29775 this.setSize(sz.width, sz.height);
29778 this.el.alignTo(this.boundEl, this.alignment);
29779 this.editing = true;
29781 Roo.QuickTips.disable();
29787 * Sets the height and width of this editor.
29788 * @param {Number} width The new width
29789 * @param {Number} height The new height
29791 setSize : function(w, h){
29792 this.field.setSize(w, h);
29799 * Realigns the editor to the bound field based on the current alignment config value.
29801 realign : function(){
29802 this.el.alignTo(this.boundEl, this.alignment);
29806 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29807 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29809 completeEdit : function(remainVisible){
29813 var v = this.getValue();
29814 if(this.revertInvalid !== false && !this.field.isValid()){
29815 v = this.startValue;
29816 this.cancelEdit(true);
29818 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29819 this.editing = false;
29823 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29824 this.editing = false;
29825 if(this.updateEl && this.boundEl){
29826 this.boundEl.update(v);
29828 if(remainVisible !== true){
29831 this.fireEvent("complete", this, v, this.startValue);
29836 onShow : function(){
29838 if(this.hideEl !== false){
29839 this.boundEl.hide();
29842 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29843 this.fixIEFocus = true;
29844 this.deferredFocus.defer(50, this);
29846 this.field.focus();
29848 this.fireEvent("startedit", this.boundEl, this.startValue);
29851 deferredFocus : function(){
29853 this.field.focus();
29858 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29859 * reverted to the original starting value.
29860 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29861 * cancel (defaults to false)
29863 cancelEdit : function(remainVisible){
29865 this.setValue(this.startValue);
29866 if(remainVisible !== true){
29873 onBlur : function(){
29874 if(this.allowBlur !== true && this.editing){
29875 this.completeEdit();
29880 onHide : function(){
29882 this.completeEdit();
29886 if(this.field.collapse){
29887 this.field.collapse();
29890 if(this.hideEl !== false){
29891 this.boundEl.show();
29894 Roo.QuickTips.enable();
29899 * Sets the data value of the editor
29900 * @param {Mixed} value Any valid value supported by the underlying field
29902 setValue : function(v){
29903 this.field.setValue(v);
29907 * Gets the data value of the editor
29908 * @return {Mixed} The data value
29910 getValue : function(){
29911 return this.field.getValue();
29915 * Ext JS Library 1.1.1
29916 * Copyright(c) 2006-2007, Ext JS, LLC.
29918 * Originally Released Under LGPL - original licence link has changed is not relivant.
29921 * <script type="text/javascript">
29925 * @class Roo.BasicDialog
29926 * @extends Roo.util.Observable
29927 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29929 var dlg = new Roo.BasicDialog("my-dlg", {
29938 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29939 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29940 dlg.addButton('Cancel', dlg.hide, dlg);
29943 <b>A Dialog should always be a direct child of the body element.</b>
29944 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29945 * @cfg {String} title Default text to display in the title bar (defaults to null)
29946 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29947 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29948 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29949 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29950 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29951 * (defaults to null with no animation)
29952 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29953 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29954 * property for valid values (defaults to 'all')
29955 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29956 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29957 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29958 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29959 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29960 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29961 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29962 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29963 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29964 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29965 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29966 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29967 * draggable = true (defaults to false)
29968 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29969 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29970 * shadow (defaults to false)
29971 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29972 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29973 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
29974 * @cfg {Array} buttons Array of buttons
29975 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
29977 * Create a new BasicDialog.
29978 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
29979 * @param {Object} config Configuration options
29981 Roo.BasicDialog = function(el, config){
29982 this.el = Roo.get(el);
29983 var dh = Roo.DomHelper;
29984 if(!this.el && config && config.autoCreate){
29985 if(typeof config.autoCreate == "object"){
29986 if(!config.autoCreate.id){
29987 config.autoCreate.id = el;
29989 this.el = dh.append(document.body,
29990 config.autoCreate, true);
29992 this.el = dh.append(document.body,
29993 {tag: "div", id: el, style:'visibility:hidden;'}, true);
29997 el.setDisplayed(true);
29998 el.hide = this.hideAction;
30000 el.addClass("x-dlg");
30002 Roo.apply(this, config);
30004 this.proxy = el.createProxy("x-dlg-proxy");
30005 this.proxy.hide = this.hideAction;
30006 this.proxy.setOpacity(.5);
30010 el.setWidth(config.width);
30013 el.setHeight(config.height);
30015 this.size = el.getSize();
30016 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30017 this.xy = [config.x,config.y];
30019 this.xy = el.getCenterXY(true);
30021 /** The header element @type Roo.Element */
30022 this.header = el.child("> .x-dlg-hd");
30023 /** The body element @type Roo.Element */
30024 this.body = el.child("> .x-dlg-bd");
30025 /** The footer element @type Roo.Element */
30026 this.footer = el.child("> .x-dlg-ft");
30029 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30032 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30035 this.header.unselectable();
30037 this.header.update(this.title);
30039 // this element allows the dialog to be focused for keyboard event
30040 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30041 this.focusEl.swallowEvent("click", true);
30043 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30045 // wrap the body and footer for special rendering
30046 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30048 this.bwrap.dom.appendChild(this.footer.dom);
30051 this.bg = this.el.createChild({
30052 tag: "div", cls:"x-dlg-bg",
30053 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30055 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30058 if(this.autoScroll !== false && !this.autoTabs){
30059 this.body.setStyle("overflow", "auto");
30062 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30064 if(this.closable !== false){
30065 this.el.addClass("x-dlg-closable");
30066 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30067 this.close.on("click", this.closeClick, this);
30068 this.close.addClassOnOver("x-dlg-close-over");
30070 if(this.collapsible !== false){
30071 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30072 this.collapseBtn.on("click", this.collapseClick, this);
30073 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30074 this.header.on("dblclick", this.collapseClick, this);
30076 if(this.resizable !== false){
30077 this.el.addClass("x-dlg-resizable");
30078 this.resizer = new Roo.Resizable(el, {
30079 minWidth: this.minWidth || 80,
30080 minHeight:this.minHeight || 80,
30081 handles: this.resizeHandles || "all",
30084 this.resizer.on("beforeresize", this.beforeResize, this);
30085 this.resizer.on("resize", this.onResize, this);
30087 if(this.draggable !== false){
30088 el.addClass("x-dlg-draggable");
30089 if (!this.proxyDrag) {
30090 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30093 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30095 dd.setHandleElId(this.header.id);
30096 dd.endDrag = this.endMove.createDelegate(this);
30097 dd.startDrag = this.startMove.createDelegate(this);
30098 dd.onDrag = this.onDrag.createDelegate(this);
30103 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30104 this.mask.enableDisplayMode("block");
30106 this.el.addClass("x-dlg-modal");
30109 this.shadow = new Roo.Shadow({
30110 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30111 offset : this.shadowOffset
30114 this.shadowOffset = 0;
30116 if(Roo.useShims && this.shim !== false){
30117 this.shim = this.el.createShim();
30118 this.shim.hide = this.hideAction;
30126 if (this.buttons) {
30127 var bts= this.buttons;
30129 Roo.each(bts, function(b) {
30138 * Fires when a key is pressed
30139 * @param {Roo.BasicDialog} this
30140 * @param {Roo.EventObject} e
30145 * Fires when this dialog is moved by the user.
30146 * @param {Roo.BasicDialog} this
30147 * @param {Number} x The new page X
30148 * @param {Number} y The new page Y
30153 * Fires when this dialog is resized by the user.
30154 * @param {Roo.BasicDialog} this
30155 * @param {Number} width The new width
30156 * @param {Number} height The new height
30160 * @event beforehide
30161 * Fires before this dialog is hidden.
30162 * @param {Roo.BasicDialog} this
30164 "beforehide" : true,
30167 * Fires when this dialog is hidden.
30168 * @param {Roo.BasicDialog} this
30172 * @event beforeshow
30173 * Fires before this dialog is shown.
30174 * @param {Roo.BasicDialog} this
30176 "beforeshow" : true,
30179 * Fires when this dialog is shown.
30180 * @param {Roo.BasicDialog} this
30184 el.on("keydown", this.onKeyDown, this);
30185 el.on("mousedown", this.toFront, this);
30186 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30188 Roo.DialogManager.register(this);
30189 Roo.BasicDialog.superclass.constructor.call(this);
30192 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30193 shadowOffset: Roo.isIE ? 6 : 5,
30196 minButtonWidth: 75,
30197 defaultButton: null,
30198 buttonAlign: "right",
30203 * Sets the dialog title text
30204 * @param {String} text The title text to display
30205 * @return {Roo.BasicDialog} this
30207 setTitle : function(text){
30208 this.header.update(text);
30213 closeClick : function(){
30218 collapseClick : function(){
30219 this[this.collapsed ? "expand" : "collapse"]();
30223 * Collapses the dialog to its minimized state (only the title bar is visible).
30224 * Equivalent to the user clicking the collapse dialog button.
30226 collapse : function(){
30227 if(!this.collapsed){
30228 this.collapsed = true;
30229 this.el.addClass("x-dlg-collapsed");
30230 this.restoreHeight = this.el.getHeight();
30231 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30236 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30237 * clicking the expand dialog button.
30239 expand : function(){
30240 if(this.collapsed){
30241 this.collapsed = false;
30242 this.el.removeClass("x-dlg-collapsed");
30243 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30248 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30249 * @return {Roo.TabPanel} The tabs component
30251 initTabs : function(){
30252 var tabs = this.getTabs();
30253 while(tabs.getTab(0)){
30256 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30258 tabs.addTab(Roo.id(dom), dom.title);
30266 beforeResize : function(){
30267 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30271 onResize : function(){
30272 this.refreshSize();
30273 this.syncBodyHeight();
30274 this.adjustAssets();
30276 this.fireEvent("resize", this, this.size.width, this.size.height);
30280 onKeyDown : function(e){
30281 if(this.isVisible()){
30282 this.fireEvent("keydown", this, e);
30287 * Resizes the dialog.
30288 * @param {Number} width
30289 * @param {Number} height
30290 * @return {Roo.BasicDialog} this
30292 resizeTo : function(width, height){
30293 this.el.setSize(width, height);
30294 this.size = {width: width, height: height};
30295 this.syncBodyHeight();
30296 if(this.fixedcenter){
30299 if(this.isVisible()){
30300 this.constrainXY();
30301 this.adjustAssets();
30303 this.fireEvent("resize", this, width, height);
30309 * Resizes the dialog to fit the specified content size.
30310 * @param {Number} width
30311 * @param {Number} height
30312 * @return {Roo.BasicDialog} this
30314 setContentSize : function(w, h){
30315 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30316 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30317 //if(!this.el.isBorderBox()){
30318 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30319 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30322 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30323 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30325 this.resizeTo(w, h);
30330 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30331 * executed in response to a particular key being pressed while the dialog is active.
30332 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30333 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30334 * @param {Function} fn The function to call
30335 * @param {Object} scope (optional) The scope of the function
30336 * @return {Roo.BasicDialog} this
30338 addKeyListener : function(key, fn, scope){
30339 var keyCode, shift, ctrl, alt;
30340 if(typeof key == "object" && !(key instanceof Array)){
30341 keyCode = key["key"];
30342 shift = key["shift"];
30343 ctrl = key["ctrl"];
30348 var handler = function(dlg, e){
30349 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30350 var k = e.getKey();
30351 if(keyCode instanceof Array){
30352 for(var i = 0, len = keyCode.length; i < len; i++){
30353 if(keyCode[i] == k){
30354 fn.call(scope || window, dlg, k, e);
30360 fn.call(scope || window, dlg, k, e);
30365 this.on("keydown", handler);
30370 * Returns the TabPanel component (creates it if it doesn't exist).
30371 * Note: If you wish to simply check for the existence of tabs without creating them,
30372 * check for a null 'tabs' property.
30373 * @return {Roo.TabPanel} The tabs component
30375 getTabs : function(){
30377 this.el.addClass("x-dlg-auto-tabs");
30378 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30379 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30385 * Adds a button to the footer section of the dialog.
30386 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30387 * object or a valid Roo.DomHelper element config
30388 * @param {Function} handler The function called when the button is clicked
30389 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30390 * @return {Roo.Button} The new button
30392 addButton : function(config, handler, scope){
30393 var dh = Roo.DomHelper;
30395 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30397 if(!this.btnContainer){
30398 var tb = this.footer.createChild({
30400 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30401 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30403 this.btnContainer = tb.firstChild.firstChild.firstChild;
30408 minWidth: this.minButtonWidth,
30411 if(typeof config == "string"){
30412 bconfig.text = config;
30415 bconfig.dhconfig = config;
30417 Roo.apply(bconfig, config);
30421 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30422 bconfig.position = Math.max(0, bconfig.position);
30423 fc = this.btnContainer.childNodes[bconfig.position];
30426 var btn = new Roo.Button(
30428 this.btnContainer.insertBefore(document.createElement("td"),fc)
30429 : this.btnContainer.appendChild(document.createElement("td")),
30430 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30433 this.syncBodyHeight();
30436 * Array of all the buttons that have been added to this dialog via addButton
30441 this.buttons.push(btn);
30446 * Sets the default button to be focused when the dialog is displayed.
30447 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30448 * @return {Roo.BasicDialog} this
30450 setDefaultButton : function(btn){
30451 this.defaultButton = btn;
30456 getHeaderFooterHeight : function(safe){
30459 height += this.header.getHeight();
30462 var fm = this.footer.getMargins();
30463 height += (this.footer.getHeight()+fm.top+fm.bottom);
30465 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30466 height += this.centerBg.getPadding("tb");
30471 syncBodyHeight : function()
30473 var bd = this.body, // the text
30474 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30476 var height = this.size.height - this.getHeaderFooterHeight(false);
30477 bd.setHeight(height-bd.getMargins("tb"));
30478 var hh = this.header.getHeight();
30479 var h = this.size.height-hh;
30482 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30483 bw.setHeight(h-cb.getPadding("tb"));
30485 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30486 bd.setWidth(bw.getWidth(true));
30488 this.tabs.syncHeight();
30490 this.tabs.el.repaint();
30496 * Restores the previous state of the dialog if Roo.state is configured.
30497 * @return {Roo.BasicDialog} this
30499 restoreState : function(){
30500 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30501 if(box && box.width){
30502 this.xy = [box.x, box.y];
30503 this.resizeTo(box.width, box.height);
30509 beforeShow : function(){
30511 if(this.fixedcenter){
30512 this.xy = this.el.getCenterXY(true);
30515 Roo.get(document.body).addClass("x-body-masked");
30516 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30519 this.constrainXY();
30523 animShow : function(){
30524 var b = Roo.get(this.animateTarget).getBox();
30525 this.proxy.setSize(b.width, b.height);
30526 this.proxy.setLocation(b.x, b.y);
30528 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30529 true, .35, this.showEl.createDelegate(this));
30533 * Shows the dialog.
30534 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30535 * @return {Roo.BasicDialog} this
30537 show : function(animateTarget){
30538 if (this.fireEvent("beforeshow", this) === false){
30541 if(this.syncHeightBeforeShow){
30542 this.syncBodyHeight();
30543 }else if(this.firstShow){
30544 this.firstShow = false;
30545 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30547 this.animateTarget = animateTarget || this.animateTarget;
30548 if(!this.el.isVisible()){
30550 if(this.animateTarget && Roo.get(this.animateTarget)){
30560 showEl : function(){
30562 this.el.setXY(this.xy);
30564 this.adjustAssets(true);
30567 // IE peekaboo bug - fix found by Dave Fenwick
30571 this.fireEvent("show", this);
30575 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30576 * dialog itself will receive focus.
30578 focus : function(){
30579 if(this.defaultButton){
30580 this.defaultButton.focus();
30582 this.focusEl.focus();
30587 constrainXY : function(){
30588 if(this.constraintoviewport !== false){
30589 if(!this.viewSize){
30590 if(this.container){
30591 var s = this.container.getSize();
30592 this.viewSize = [s.width, s.height];
30594 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30597 var s = Roo.get(this.container||document).getScroll();
30599 var x = this.xy[0], y = this.xy[1];
30600 var w = this.size.width, h = this.size.height;
30601 var vw = this.viewSize[0], vh = this.viewSize[1];
30602 // only move it if it needs it
30604 // first validate right/bottom
30605 if(x + w > vw+s.left){
30609 if(y + h > vh+s.top){
30613 // then make sure top/left isn't negative
30625 if(this.isVisible()){
30626 this.el.setLocation(x, y);
30627 this.adjustAssets();
30634 onDrag : function(){
30635 if(!this.proxyDrag){
30636 this.xy = this.el.getXY();
30637 this.adjustAssets();
30642 adjustAssets : function(doShow){
30643 var x = this.xy[0], y = this.xy[1];
30644 var w = this.size.width, h = this.size.height;
30645 if(doShow === true){
30647 this.shadow.show(this.el);
30653 if(this.shadow && this.shadow.isVisible()){
30654 this.shadow.show(this.el);
30656 if(this.shim && this.shim.isVisible()){
30657 this.shim.setBounds(x, y, w, h);
30662 adjustViewport : function(w, h){
30664 w = Roo.lib.Dom.getViewWidth();
30665 h = Roo.lib.Dom.getViewHeight();
30668 this.viewSize = [w, h];
30669 if(this.modal && this.mask.isVisible()){
30670 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30671 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30673 if(this.isVisible()){
30674 this.constrainXY();
30679 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30680 * shadow, proxy, mask, etc.) Also removes all event listeners.
30681 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30683 destroy : function(removeEl){
30684 if(this.isVisible()){
30685 this.animateTarget = null;
30688 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30690 this.tabs.destroy(removeEl);
30703 for(var i = 0, len = this.buttons.length; i < len; i++){
30704 this.buttons[i].destroy();
30707 this.el.removeAllListeners();
30708 if(removeEl === true){
30709 this.el.update("");
30712 Roo.DialogManager.unregister(this);
30716 startMove : function(){
30717 if(this.proxyDrag){
30720 if(this.constraintoviewport !== false){
30721 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30726 endMove : function(){
30727 if(!this.proxyDrag){
30728 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30730 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30733 this.refreshSize();
30734 this.adjustAssets();
30736 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30740 * Brings this dialog to the front of any other visible dialogs
30741 * @return {Roo.BasicDialog} this
30743 toFront : function(){
30744 Roo.DialogManager.bringToFront(this);
30749 * Sends this dialog to the back (under) of any other visible dialogs
30750 * @return {Roo.BasicDialog} this
30752 toBack : function(){
30753 Roo.DialogManager.sendToBack(this);
30758 * Centers this dialog in the viewport
30759 * @return {Roo.BasicDialog} this
30761 center : function(){
30762 var xy = this.el.getCenterXY(true);
30763 this.moveTo(xy[0], xy[1]);
30768 * Moves the dialog's top-left corner to the specified point
30769 * @param {Number} x
30770 * @param {Number} y
30771 * @return {Roo.BasicDialog} this
30773 moveTo : function(x, y){
30775 if(this.isVisible()){
30776 this.el.setXY(this.xy);
30777 this.adjustAssets();
30783 * Aligns the dialog to the specified element
30784 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30785 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30786 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30787 * @return {Roo.BasicDialog} this
30789 alignTo : function(element, position, offsets){
30790 this.xy = this.el.getAlignToXY(element, position, offsets);
30791 if(this.isVisible()){
30792 this.el.setXY(this.xy);
30793 this.adjustAssets();
30799 * Anchors an element to another element and realigns it when the window is resized.
30800 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30801 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30802 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30803 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30804 * is a number, it is used as the buffer delay (defaults to 50ms).
30805 * @return {Roo.BasicDialog} this
30807 anchorTo : function(el, alignment, offsets, monitorScroll){
30808 var action = function(){
30809 this.alignTo(el, alignment, offsets);
30811 Roo.EventManager.onWindowResize(action, this);
30812 var tm = typeof monitorScroll;
30813 if(tm != 'undefined'){
30814 Roo.EventManager.on(window, 'scroll', action, this,
30815 {buffer: tm == 'number' ? monitorScroll : 50});
30822 * Returns true if the dialog is visible
30823 * @return {Boolean}
30825 isVisible : function(){
30826 return this.el.isVisible();
30830 animHide : function(callback){
30831 var b = Roo.get(this.animateTarget).getBox();
30833 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30835 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30836 this.hideEl.createDelegate(this, [callback]));
30840 * Hides the dialog.
30841 * @param {Function} callback (optional) Function to call when the dialog is hidden
30842 * @return {Roo.BasicDialog} this
30844 hide : function(callback){
30845 if (this.fireEvent("beforehide", this) === false){
30849 this.shadow.hide();
30854 // sometimes animateTarget seems to get set.. causing problems...
30855 // this just double checks..
30856 if(this.animateTarget && Roo.get(this.animateTarget)) {
30857 this.animHide(callback);
30860 this.hideEl(callback);
30866 hideEl : function(callback){
30870 Roo.get(document.body).removeClass("x-body-masked");
30872 this.fireEvent("hide", this);
30873 if(typeof callback == "function"){
30879 hideAction : function(){
30880 this.setLeft("-10000px");
30881 this.setTop("-10000px");
30882 this.setStyle("visibility", "hidden");
30886 refreshSize : function(){
30887 this.size = this.el.getSize();
30888 this.xy = this.el.getXY();
30889 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30893 // z-index is managed by the DialogManager and may be overwritten at any time
30894 setZIndex : function(index){
30896 this.mask.setStyle("z-index", index);
30899 this.shim.setStyle("z-index", ++index);
30902 this.shadow.setZIndex(++index);
30904 this.el.setStyle("z-index", ++index);
30906 this.proxy.setStyle("z-index", ++index);
30909 this.resizer.proxy.setStyle("z-index", ++index);
30912 this.lastZIndex = index;
30916 * Returns the element for this dialog
30917 * @return {Roo.Element} The underlying dialog Element
30919 getEl : function(){
30925 * @class Roo.DialogManager
30926 * Provides global access to BasicDialogs that have been created and
30927 * support for z-indexing (layering) multiple open dialogs.
30929 Roo.DialogManager = function(){
30931 var accessList = [];
30935 var sortDialogs = function(d1, d2){
30936 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30940 var orderDialogs = function(){
30941 accessList.sort(sortDialogs);
30942 var seed = Roo.DialogManager.zseed;
30943 for(var i = 0, len = accessList.length; i < len; i++){
30944 var dlg = accessList[i];
30946 dlg.setZIndex(seed + (i*10));
30953 * The starting z-index for BasicDialogs (defaults to 9000)
30954 * @type Number The z-index value
30959 register : function(dlg){
30960 list[dlg.id] = dlg;
30961 accessList.push(dlg);
30965 unregister : function(dlg){
30966 delete list[dlg.id];
30969 if(!accessList.indexOf){
30970 for( i = 0, len = accessList.length; i < len; i++){
30971 if(accessList[i] == dlg){
30972 accessList.splice(i, 1);
30977 i = accessList.indexOf(dlg);
30979 accessList.splice(i, 1);
30985 * Gets a registered dialog by id
30986 * @param {String/Object} id The id of the dialog or a dialog
30987 * @return {Roo.BasicDialog} this
30989 get : function(id){
30990 return typeof id == "object" ? id : list[id];
30994 * Brings the specified dialog to the front
30995 * @param {String/Object} dlg The id of the dialog or a dialog
30996 * @return {Roo.BasicDialog} this
30998 bringToFront : function(dlg){
30999 dlg = this.get(dlg);
31002 dlg._lastAccess = new Date().getTime();
31009 * Sends the specified dialog to the back
31010 * @param {String/Object} dlg The id of the dialog or a dialog
31011 * @return {Roo.BasicDialog} this
31013 sendToBack : function(dlg){
31014 dlg = this.get(dlg);
31015 dlg._lastAccess = -(new Date().getTime());
31021 * Hides all dialogs
31023 hideAll : function(){
31024 for(var id in list){
31025 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31034 * @class Roo.LayoutDialog
31035 * @extends Roo.BasicDialog
31036 * Dialog which provides adjustments for working with a layout in a Dialog.
31037 * Add your necessary layout config options to the dialog's config.<br>
31038 * Example usage (including a nested layout):
31041 dialog = new Roo.LayoutDialog("download-dlg", {
31050 // layout config merges with the dialog config
31052 tabPosition: "top",
31053 alwaysShowTabs: true
31056 dialog.addKeyListener(27, dialog.hide, dialog);
31057 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31058 dialog.addButton("Build It!", this.getDownload, this);
31060 // we can even add nested layouts
31061 var innerLayout = new Roo.BorderLayout("dl-inner", {
31071 innerLayout.beginUpdate();
31072 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31073 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31074 innerLayout.endUpdate(true);
31076 var layout = dialog.getLayout();
31077 layout.beginUpdate();
31078 layout.add("center", new Roo.ContentPanel("standard-panel",
31079 {title: "Download the Source", fitToFrame:true}));
31080 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31081 {title: "Build your own roo.js"}));
31082 layout.getRegion("center").showPanel(sp);
31083 layout.endUpdate();
31087 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31088 * @param {Object} config configuration options
31090 Roo.LayoutDialog = function(el, cfg){
31093 if (typeof(cfg) == 'undefined') {
31094 config = Roo.apply({}, el);
31095 // not sure why we use documentElement here.. - it should always be body.
31096 // IE7 borks horribly if we use documentElement.
31097 // webkit also does not like documentElement - it creates a body element...
31098 el = Roo.get( document.body || document.documentElement ).createChild();
31099 //config.autoCreate = true;
31103 config.autoTabs = false;
31104 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31105 this.body.setStyle({overflow:"hidden", position:"relative"});
31106 this.layout = new Roo.BorderLayout(this.body.dom, config);
31107 this.layout.monitorWindowResize = false;
31108 this.el.addClass("x-dlg-auto-layout");
31109 // fix case when center region overwrites center function
31110 this.center = Roo.BasicDialog.prototype.center;
31111 this.on("show", this.layout.layout, this.layout, true);
31112 if (config.items) {
31113 var xitems = config.items;
31114 delete config.items;
31115 Roo.each(xitems, this.addxtype, this);
31120 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31122 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31125 endUpdate : function(){
31126 this.layout.endUpdate();
31130 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31133 beginUpdate : function(){
31134 this.layout.beginUpdate();
31138 * Get the BorderLayout for this dialog
31139 * @return {Roo.BorderLayout}
31141 getLayout : function(){
31142 return this.layout;
31145 showEl : function(){
31146 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31148 this.layout.layout();
31153 // Use the syncHeightBeforeShow config option to control this automatically
31154 syncBodyHeight : function(){
31155 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31156 if(this.layout){this.layout.layout();}
31160 * Add an xtype element (actually adds to the layout.)
31161 * @return {Object} xdata xtype object data.
31164 addxtype : function(c) {
31165 return this.layout.addxtype(c);
31169 * Ext JS Library 1.1.1
31170 * Copyright(c) 2006-2007, Ext JS, LLC.
31172 * Originally Released Under LGPL - original licence link has changed is not relivant.
31175 * <script type="text/javascript">
31179 * @class Roo.MessageBox
31180 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31184 Roo.Msg.alert('Status', 'Changes saved successfully.');
31186 // Prompt for user data:
31187 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31189 // process text value...
31193 // Show a dialog using config options:
31195 title:'Save Changes?',
31196 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31197 buttons: Roo.Msg.YESNOCANCEL,
31204 Roo.MessageBox = function(){
31205 var dlg, opt, mask, waitTimer;
31206 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31207 var buttons, activeTextEl, bwidth;
31210 var handleButton = function(button){
31212 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31216 var handleHide = function(){
31217 if(opt && opt.cls){
31218 dlg.el.removeClass(opt.cls);
31221 Roo.TaskMgr.stop(waitTimer);
31227 var updateButtons = function(b){
31230 buttons["ok"].hide();
31231 buttons["cancel"].hide();
31232 buttons["yes"].hide();
31233 buttons["no"].hide();
31234 dlg.footer.dom.style.display = 'none';
31237 dlg.footer.dom.style.display = '';
31238 for(var k in buttons){
31239 if(typeof buttons[k] != "function"){
31242 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31243 width += buttons[k].el.getWidth()+15;
31253 var handleEsc = function(d, k, e){
31254 if(opt && opt.closable !== false){
31264 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31265 * @return {Roo.BasicDialog} The BasicDialog element
31267 getDialog : function(){
31269 dlg = new Roo.BasicDialog("x-msg-box", {
31274 constraintoviewport:false,
31276 collapsible : false,
31279 width:400, height:100,
31280 buttonAlign:"center",
31281 closeClick : function(){
31282 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31283 handleButton("no");
31285 handleButton("cancel");
31289 dlg.on("hide", handleHide);
31291 dlg.addKeyListener(27, handleEsc);
31293 var bt = this.buttonText;
31294 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31295 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31296 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31297 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31298 bodyEl = dlg.body.createChild({
31300 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>'
31302 msgEl = bodyEl.dom.firstChild;
31303 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31304 textboxEl.enableDisplayMode();
31305 textboxEl.addKeyListener([10,13], function(){
31306 if(dlg.isVisible() && opt && opt.buttons){
31307 if(opt.buttons.ok){
31308 handleButton("ok");
31309 }else if(opt.buttons.yes){
31310 handleButton("yes");
31314 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31315 textareaEl.enableDisplayMode();
31316 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31317 progressEl.enableDisplayMode();
31318 var pf = progressEl.dom.firstChild;
31320 pp = Roo.get(pf.firstChild);
31321 pp.setHeight(pf.offsetHeight);
31329 * Updates the message box body text
31330 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31331 * the XHTML-compliant non-breaking space character '&#160;')
31332 * @return {Roo.MessageBox} This message box
31334 updateText : function(text){
31335 if(!dlg.isVisible() && !opt.width){
31336 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31338 msgEl.innerHTML = text || ' ';
31340 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31341 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31343 Math.min(opt.width || cw , this.maxWidth),
31344 Math.max(opt.minWidth || this.minWidth, bwidth)
31347 activeTextEl.setWidth(w);
31349 if(dlg.isVisible()){
31350 dlg.fixedcenter = false;
31352 // to big, make it scroll. = But as usual stupid IE does not support
31355 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31356 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31357 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31359 bodyEl.dom.style.height = '';
31360 bodyEl.dom.style.overflowY = '';
31363 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31365 bodyEl.dom.style.overflowX = '';
31368 dlg.setContentSize(w, bodyEl.getHeight());
31369 if(dlg.isVisible()){
31370 dlg.fixedcenter = true;
31376 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31377 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31378 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31379 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31380 * @return {Roo.MessageBox} This message box
31382 updateProgress : function(value, text){
31384 this.updateText(text);
31386 if (pp) { // weird bug on my firefox - for some reason this is not defined
31387 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31393 * Returns true if the message box is currently displayed
31394 * @return {Boolean} True if the message box is visible, else false
31396 isVisible : function(){
31397 return dlg && dlg.isVisible();
31401 * Hides the message box if it is displayed
31404 if(this.isVisible()){
31410 * Displays a new message box, or reinitializes an existing message box, based on the config options
31411 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31412 * The following config object properties are supported:
31414 Property Type Description
31415 ---------- --------------- ------------------------------------------------------------------------------------
31416 animEl String/Element An id or Element from which the message box should animate as it opens and
31417 closes (defaults to undefined)
31418 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31419 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31420 closable Boolean False to hide the top-right close button (defaults to true). Note that
31421 progress and wait dialogs will ignore this property and always hide the
31422 close button as they can only be closed programmatically.
31423 cls String A custom CSS class to apply to the message box element
31424 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31425 displayed (defaults to 75)
31426 fn Function A callback function to execute after closing the dialog. The arguments to the
31427 function will be btn (the name of the button that was clicked, if applicable,
31428 e.g. "ok"), and text (the value of the active text field, if applicable).
31429 Progress and wait dialogs will ignore this option since they do not respond to
31430 user actions and can only be closed programmatically, so any required function
31431 should be called by the same code after it closes the dialog.
31432 icon String A CSS class that provides a background image to be used as an icon for
31433 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31434 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31435 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31436 modal Boolean False to allow user interaction with the page while the message box is
31437 displayed (defaults to true)
31438 msg String A string that will replace the existing message box body text (defaults
31439 to the XHTML-compliant non-breaking space character ' ')
31440 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31441 progress Boolean True to display a progress bar (defaults to false)
31442 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31443 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31444 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31445 title String The title text
31446 value String The string value to set into the active textbox element if displayed
31447 wait Boolean True to display a progress bar (defaults to false)
31448 width Number The width of the dialog in pixels
31455 msg: 'Please enter your address:',
31457 buttons: Roo.MessageBox.OKCANCEL,
31460 animEl: 'addAddressBtn'
31463 * @param {Object} config Configuration options
31464 * @return {Roo.MessageBox} This message box
31466 show : function(options)
31469 // this causes nightmares if you show one dialog after another
31470 // especially on callbacks..
31472 if(this.isVisible()){
31475 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31476 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31477 Roo.log("New Dialog Message:" + options.msg )
31478 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31479 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31482 var d = this.getDialog();
31484 d.setTitle(opt.title || " ");
31485 d.close.setDisplayed(opt.closable !== false);
31486 activeTextEl = textboxEl;
31487 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31492 textareaEl.setHeight(typeof opt.multiline == "number" ?
31493 opt.multiline : this.defaultTextHeight);
31494 activeTextEl = textareaEl;
31503 progressEl.setDisplayed(opt.progress === true);
31504 this.updateProgress(0);
31505 activeTextEl.dom.value = opt.value || "";
31507 dlg.setDefaultButton(activeTextEl);
31509 var bs = opt.buttons;
31512 db = buttons["ok"];
31513 }else if(bs && bs.yes){
31514 db = buttons["yes"];
31516 dlg.setDefaultButton(db);
31518 bwidth = updateButtons(opt.buttons);
31519 this.updateText(opt.msg);
31521 d.el.addClass(opt.cls);
31523 d.proxyDrag = opt.proxyDrag === true;
31524 d.modal = opt.modal !== false;
31525 d.mask = opt.modal !== false ? mask : false;
31526 if(!d.isVisible()){
31527 // force it to the end of the z-index stack so it gets a cursor in FF
31528 document.body.appendChild(dlg.el.dom);
31529 d.animateTarget = null;
31530 d.show(options.animEl);
31536 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31537 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31538 * and closing the message box when the process is complete.
31539 * @param {String} title The title bar text
31540 * @param {String} msg The message box body text
31541 * @return {Roo.MessageBox} This message box
31543 progress : function(title, msg){
31550 minWidth: this.minProgressWidth,
31557 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31558 * If a callback function is passed it will be called after the user clicks the button, and the
31559 * id of the button that was clicked will be passed as the only parameter to the callback
31560 * (could also be the top-right close button).
31561 * @param {String} title The title bar text
31562 * @param {String} msg The message box body text
31563 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31564 * @param {Object} scope (optional) The scope of the callback function
31565 * @return {Roo.MessageBox} This message box
31567 alert : function(title, msg, fn, scope){
31580 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31581 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31582 * You are responsible for closing the message box when the process is complete.
31583 * @param {String} msg The message box body text
31584 * @param {String} title (optional) The title bar text
31585 * @return {Roo.MessageBox} This message box
31587 wait : function(msg, title){
31598 waitTimer = Roo.TaskMgr.start({
31600 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31608 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31609 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31610 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31611 * @param {String} title The title bar text
31612 * @param {String} msg The message box body text
31613 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31614 * @param {Object} scope (optional) The scope of the callback function
31615 * @return {Roo.MessageBox} This message box
31617 confirm : function(title, msg, fn, scope){
31621 buttons: this.YESNO,
31630 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31631 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31632 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31633 * (could also be the top-right close button) and the text that was entered will be passed as the two
31634 * parameters to the callback.
31635 * @param {String} title The title bar text
31636 * @param {String} msg The message box body text
31637 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31638 * @param {Object} scope (optional) The scope of the callback function
31639 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31640 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31641 * @return {Roo.MessageBox} This message box
31643 prompt : function(title, msg, fn, scope, multiline){
31647 buttons: this.OKCANCEL,
31652 multiline: multiline,
31659 * Button config that displays a single OK button
31664 * Button config that displays Yes and No buttons
31667 YESNO : {yes:true, no:true},
31669 * Button config that displays OK and Cancel buttons
31672 OKCANCEL : {ok:true, cancel:true},
31674 * Button config that displays Yes, No and Cancel buttons
31677 YESNOCANCEL : {yes:true, no:true, cancel:true},
31680 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31683 defaultTextHeight : 75,
31685 * The maximum width in pixels of the message box (defaults to 600)
31690 * The minimum width in pixels of the message box (defaults to 100)
31695 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31696 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31699 minProgressWidth : 250,
31701 * An object containing the default button text strings that can be overriden for localized language support.
31702 * Supported properties are: ok, cancel, yes and no.
31703 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31716 * Shorthand for {@link Roo.MessageBox}
31718 Roo.Msg = Roo.MessageBox;/*
31720 * Ext JS Library 1.1.1
31721 * Copyright(c) 2006-2007, Ext JS, LLC.
31723 * Originally Released Under LGPL - original licence link has changed is not relivant.
31726 * <script type="text/javascript">
31729 * @class Roo.QuickTips
31730 * Provides attractive and customizable tooltips for any element.
31733 Roo.QuickTips = function(){
31734 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31735 var ce, bd, xy, dd;
31736 var visible = false, disabled = true, inited = false;
31737 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31739 var onOver = function(e){
31743 var t = e.getTarget();
31744 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31747 if(ce && t == ce.el){
31748 clearTimeout(hideProc);
31751 if(t && tagEls[t.id]){
31752 tagEls[t.id].el = t;
31753 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31756 var ttp, et = Roo.fly(t);
31757 var ns = cfg.namespace;
31758 if(tm.interceptTitles && t.title){
31761 t.removeAttribute("title");
31762 e.preventDefault();
31764 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31767 showProc = show.defer(tm.showDelay, tm, [{
31770 width: et.getAttributeNS(ns, cfg.width),
31771 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31772 title: et.getAttributeNS(ns, cfg.title),
31773 cls: et.getAttributeNS(ns, cfg.cls)
31778 var onOut = function(e){
31779 clearTimeout(showProc);
31780 var t = e.getTarget();
31781 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31782 hideProc = setTimeout(hide, tm.hideDelay);
31786 var onMove = function(e){
31792 if(tm.trackMouse && ce){
31797 var onDown = function(e){
31798 clearTimeout(showProc);
31799 clearTimeout(hideProc);
31801 if(tm.hideOnClick){
31804 tm.enable.defer(100, tm);
31809 var getPad = function(){
31810 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31813 var show = function(o){
31817 clearTimeout(dismissProc);
31819 if(removeCls){ // in case manually hidden
31820 el.removeClass(removeCls);
31824 el.addClass(ce.cls);
31825 removeCls = ce.cls;
31828 tipTitle.update(ce.title);
31831 tipTitle.update('');
31834 el.dom.style.width = tm.maxWidth+'px';
31835 //tipBody.dom.style.width = '';
31836 tipBodyText.update(o.text);
31837 var p = getPad(), w = ce.width;
31839 var td = tipBodyText.dom;
31840 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31841 if(aw > tm.maxWidth){
31843 }else if(aw < tm.minWidth){
31849 //tipBody.setWidth(w);
31850 el.setWidth(parseInt(w, 10) + p);
31851 if(ce.autoHide === false){
31852 close.setDisplayed(true);
31857 close.setDisplayed(false);
31863 el.avoidY = xy[1]-18;
31868 el.setStyle("visibility", "visible");
31869 el.fadeIn({callback: afterShow});
31875 var afterShow = function(){
31879 if(tm.autoDismiss && ce.autoHide !== false){
31880 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31885 var hide = function(noanim){
31886 clearTimeout(dismissProc);
31887 clearTimeout(hideProc);
31889 if(el.isVisible()){
31891 if(noanim !== true && tm.animate){
31892 el.fadeOut({callback: afterHide});
31899 var afterHide = function(){
31902 el.removeClass(removeCls);
31909 * @cfg {Number} minWidth
31910 * The minimum width of the quick tip (defaults to 40)
31914 * @cfg {Number} maxWidth
31915 * The maximum width of the quick tip (defaults to 300)
31919 * @cfg {Boolean} interceptTitles
31920 * True to automatically use the element's DOM title value if available (defaults to false)
31922 interceptTitles : false,
31924 * @cfg {Boolean} trackMouse
31925 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31927 trackMouse : false,
31929 * @cfg {Boolean} hideOnClick
31930 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31932 hideOnClick : true,
31934 * @cfg {Number} showDelay
31935 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31939 * @cfg {Number} hideDelay
31940 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31944 * @cfg {Boolean} autoHide
31945 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31946 * Used in conjunction with hideDelay.
31951 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31952 * (defaults to true). Used in conjunction with autoDismissDelay.
31954 autoDismiss : true,
31957 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31959 autoDismissDelay : 5000,
31961 * @cfg {Boolean} animate
31962 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31967 * @cfg {String} title
31968 * Title text to display (defaults to ''). This can be any valid HTML markup.
31972 * @cfg {String} text
31973 * Body text to display (defaults to ''). This can be any valid HTML markup.
31977 * @cfg {String} cls
31978 * A CSS class to apply to the base quick tip element (defaults to '').
31982 * @cfg {Number} width
31983 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
31984 * minWidth or maxWidth.
31989 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
31990 * or display QuickTips in a page.
31993 tm = Roo.QuickTips;
31994 cfg = tm.tagConfig;
31996 if(!Roo.isReady){ // allow calling of init() before onReady
31997 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32000 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32001 el.fxDefaults = {stopFx: true};
32002 // maximum custom styling
32003 //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>');
32004 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>');
32005 tipTitle = el.child('h3');
32006 tipTitle.enableDisplayMode("block");
32007 tipBody = el.child('div.x-tip-bd');
32008 tipBodyText = el.child('div.x-tip-bd-inner');
32009 //bdLeft = el.child('div.x-tip-bd-left');
32010 //bdRight = el.child('div.x-tip-bd-right');
32011 close = el.child('div.x-tip-close');
32012 close.enableDisplayMode("block");
32013 close.on("click", hide);
32014 var d = Roo.get(document);
32015 d.on("mousedown", onDown);
32016 d.on("mouseover", onOver);
32017 d.on("mouseout", onOut);
32018 d.on("mousemove", onMove);
32019 esc = d.addKeyListener(27, hide);
32022 dd = el.initDD("default", null, {
32023 onDrag : function(){
32027 dd.setHandleElId(tipTitle.id);
32036 * Configures a new quick tip instance and assigns it to a target element. The following config options
32039 Property Type Description
32040 ---------- --------------------- ------------------------------------------------------------------------
32041 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32043 * @param {Object} config The config object
32045 register : function(config){
32046 var cs = config instanceof Array ? config : arguments;
32047 for(var i = 0, len = cs.length; i < len; i++) {
32049 var target = c.target;
32051 if(target instanceof Array){
32052 for(var j = 0, jlen = target.length; j < jlen; j++){
32053 tagEls[target[j]] = c;
32056 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32063 * Removes this quick tip from its element and destroys it.
32064 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32066 unregister : function(el){
32067 delete tagEls[Roo.id(el)];
32071 * Enable this quick tip.
32073 enable : function(){
32074 if(inited && disabled){
32076 if(locks.length < 1){
32083 * Disable this quick tip.
32085 disable : function(){
32087 clearTimeout(showProc);
32088 clearTimeout(hideProc);
32089 clearTimeout(dismissProc);
32097 * Returns true if the quick tip is enabled, else false.
32099 isEnabled : function(){
32106 attribute : "qtip",
32116 // backwards compat
32117 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32119 * Ext JS Library 1.1.1
32120 * Copyright(c) 2006-2007, Ext JS, LLC.
32122 * Originally Released Under LGPL - original licence link has changed is not relivant.
32125 * <script type="text/javascript">
32130 * @class Roo.tree.TreePanel
32131 * @extends Roo.data.Tree
32133 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32134 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32135 * @cfg {Boolean} enableDD true to enable drag and drop
32136 * @cfg {Boolean} enableDrag true to enable just drag
32137 * @cfg {Boolean} enableDrop true to enable just drop
32138 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32139 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32140 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32141 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32142 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32143 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32144 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32145 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32146 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32147 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32148 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32149 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32150 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32151 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32152 * @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>
32153 * @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>
32156 * @param {String/HTMLElement/Element} el The container element
32157 * @param {Object} config
32159 Roo.tree.TreePanel = function(el, config){
32161 var loader = false;
32163 root = config.root;
32164 delete config.root;
32166 if (config.loader) {
32167 loader = config.loader;
32168 delete config.loader;
32171 Roo.apply(this, config);
32172 Roo.tree.TreePanel.superclass.constructor.call(this);
32173 this.el = Roo.get(el);
32174 this.el.addClass('x-tree');
32175 //console.log(root);
32177 this.setRootNode( Roo.factory(root, Roo.tree));
32180 this.loader = Roo.factory(loader, Roo.tree);
32183 * Read-only. The id of the container element becomes this TreePanel's id.
32185 this.id = this.el.id;
32188 * @event beforeload
32189 * Fires before a node is loaded, return false to cancel
32190 * @param {Node} node The node being loaded
32192 "beforeload" : true,
32195 * Fires when a node is loaded
32196 * @param {Node} node The node that was loaded
32200 * @event textchange
32201 * Fires when the text for a node is changed
32202 * @param {Node} node The node
32203 * @param {String} text The new text
32204 * @param {String} oldText The old text
32206 "textchange" : true,
32208 * @event beforeexpand
32209 * Fires before a node is expanded, return false to cancel.
32210 * @param {Node} node The node
32211 * @param {Boolean} deep
32212 * @param {Boolean} anim
32214 "beforeexpand" : true,
32216 * @event beforecollapse
32217 * Fires before a node is collapsed, return false to cancel.
32218 * @param {Node} node The node
32219 * @param {Boolean} deep
32220 * @param {Boolean} anim
32222 "beforecollapse" : true,
32225 * Fires when a node is expanded
32226 * @param {Node} node The node
32230 * @event disabledchange
32231 * Fires when the disabled status of a node changes
32232 * @param {Node} node The node
32233 * @param {Boolean} disabled
32235 "disabledchange" : true,
32238 * Fires when a node is collapsed
32239 * @param {Node} node The node
32243 * @event beforeclick
32244 * Fires before click processing on a node. Return false to cancel the default action.
32245 * @param {Node} node The node
32246 * @param {Roo.EventObject} e The event object
32248 "beforeclick":true,
32250 * @event checkchange
32251 * Fires when a node with a checkbox's checked property changes
32252 * @param {Node} this This node
32253 * @param {Boolean} checked
32255 "checkchange":true,
32258 * Fires when a node is clicked
32259 * @param {Node} node The node
32260 * @param {Roo.EventObject} e The event object
32265 * Fires when a node is double clicked
32266 * @param {Node} node The node
32267 * @param {Roo.EventObject} e The event object
32271 * @event contextmenu
32272 * Fires when a node is right clicked
32273 * @param {Node} node The node
32274 * @param {Roo.EventObject} e The event object
32276 "contextmenu":true,
32278 * @event beforechildrenrendered
32279 * Fires right before the child nodes for a node are rendered
32280 * @param {Node} node The node
32282 "beforechildrenrendered":true,
32285 * Fires when a node starts being dragged
32286 * @param {Roo.tree.TreePanel} this
32287 * @param {Roo.tree.TreeNode} node
32288 * @param {event} e The raw browser event
32290 "startdrag" : true,
32293 * Fires when a drag operation is complete
32294 * @param {Roo.tree.TreePanel} this
32295 * @param {Roo.tree.TreeNode} node
32296 * @param {event} e The raw browser event
32301 * Fires when a dragged node is dropped on a valid DD target
32302 * @param {Roo.tree.TreePanel} this
32303 * @param {Roo.tree.TreeNode} node
32304 * @param {DD} dd The dd it was dropped on
32305 * @param {event} e The raw browser event
32309 * @event beforenodedrop
32310 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32311 * passed to handlers has the following properties:<br />
32312 * <ul style="padding:5px;padding-left:16px;">
32313 * <li>tree - The TreePanel</li>
32314 * <li>target - The node being targeted for the drop</li>
32315 * <li>data - The drag data from the drag source</li>
32316 * <li>point - The point of the drop - append, above or below</li>
32317 * <li>source - The drag source</li>
32318 * <li>rawEvent - Raw mouse event</li>
32319 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32320 * to be inserted by setting them on this object.</li>
32321 * <li>cancel - Set this to true to cancel the drop.</li>
32323 * @param {Object} dropEvent
32325 "beforenodedrop" : true,
32328 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32329 * passed to handlers has the following properties:<br />
32330 * <ul style="padding:5px;padding-left:16px;">
32331 * <li>tree - The TreePanel</li>
32332 * <li>target - The node being targeted for the drop</li>
32333 * <li>data - The drag data from the drag source</li>
32334 * <li>point - The point of the drop - append, above or below</li>
32335 * <li>source - The drag source</li>
32336 * <li>rawEvent - Raw mouse event</li>
32337 * <li>dropNode - Dropped node(s).</li>
32339 * @param {Object} dropEvent
32343 * @event nodedragover
32344 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32345 * passed to handlers has the following properties:<br />
32346 * <ul style="padding:5px;padding-left:16px;">
32347 * <li>tree - The TreePanel</li>
32348 * <li>target - The node being targeted for the drop</li>
32349 * <li>data - The drag data from the drag source</li>
32350 * <li>point - The point of the drop - append, above or below</li>
32351 * <li>source - The drag source</li>
32352 * <li>rawEvent - Raw mouse event</li>
32353 * <li>dropNode - Drop node(s) provided by the source.</li>
32354 * <li>cancel - Set this to true to signal drop not allowed.</li>
32356 * @param {Object} dragOverEvent
32358 "nodedragover" : true
32361 if(this.singleExpand){
32362 this.on("beforeexpand", this.restrictExpand, this);
32365 this.editor.tree = this;
32366 this.editor = Roo.factory(this.editor, Roo.tree);
32369 if (this.selModel) {
32370 this.selModel = Roo.factory(this.selModel, Roo.tree);
32374 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32375 rootVisible : true,
32376 animate: Roo.enableFx,
32379 hlDrop : Roo.enableFx,
32383 rendererTip: false,
32385 restrictExpand : function(node){
32386 var p = node.parentNode;
32388 if(p.expandedChild && p.expandedChild.parentNode == p){
32389 p.expandedChild.collapse();
32391 p.expandedChild = node;
32395 // private override
32396 setRootNode : function(node){
32397 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32398 if(!this.rootVisible){
32399 node.ui = new Roo.tree.RootTreeNodeUI(node);
32405 * Returns the container element for this TreePanel
32407 getEl : function(){
32412 * Returns the default TreeLoader for this TreePanel
32414 getLoader : function(){
32415 return this.loader;
32421 expandAll : function(){
32422 this.root.expand(true);
32426 * Collapse all nodes
32428 collapseAll : function(){
32429 this.root.collapse(true);
32433 * Returns the selection model used by this TreePanel
32435 getSelectionModel : function(){
32436 if(!this.selModel){
32437 this.selModel = new Roo.tree.DefaultSelectionModel();
32439 return this.selModel;
32443 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32444 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32445 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32448 getChecked : function(a, startNode){
32449 startNode = startNode || this.root;
32451 var f = function(){
32452 if(this.attributes.checked){
32453 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32456 startNode.cascade(f);
32461 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32462 * @param {String} path
32463 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32464 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32465 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32467 expandPath : function(path, attr, callback){
32468 attr = attr || "id";
32469 var keys = path.split(this.pathSeparator);
32470 var curNode = this.root;
32471 if(curNode.attributes[attr] != keys[1]){ // invalid root
32473 callback(false, null);
32478 var f = function(){
32479 if(++index == keys.length){
32481 callback(true, curNode);
32485 var c = curNode.findChild(attr, keys[index]);
32488 callback(false, curNode);
32493 c.expand(false, false, f);
32495 curNode.expand(false, false, f);
32499 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32500 * @param {String} path
32501 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32502 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32503 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32505 selectPath : function(path, attr, callback){
32506 attr = attr || "id";
32507 var keys = path.split(this.pathSeparator);
32508 var v = keys.pop();
32509 if(keys.length > 0){
32510 var f = function(success, node){
32511 if(success && node){
32512 var n = node.findChild(attr, v);
32518 }else if(callback){
32519 callback(false, n);
32523 callback(false, n);
32527 this.expandPath(keys.join(this.pathSeparator), attr, f);
32529 this.root.select();
32531 callback(true, this.root);
32536 getTreeEl : function(){
32541 * Trigger rendering of this TreePanel
32543 render : function(){
32544 if (this.innerCt) {
32545 return this; // stop it rendering more than once!!
32548 this.innerCt = this.el.createChild({tag:"ul",
32549 cls:"x-tree-root-ct " +
32550 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32552 if(this.containerScroll){
32553 Roo.dd.ScrollManager.register(this.el);
32555 if((this.enableDD || this.enableDrop) && !this.dropZone){
32557 * The dropZone used by this tree if drop is enabled
32558 * @type Roo.tree.TreeDropZone
32560 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32561 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32564 if((this.enableDD || this.enableDrag) && !this.dragZone){
32566 * The dragZone used by this tree if drag is enabled
32567 * @type Roo.tree.TreeDragZone
32569 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32570 ddGroup: this.ddGroup || "TreeDD",
32571 scroll: this.ddScroll
32574 this.getSelectionModel().init(this);
32576 Roo.log("ROOT not set in tree");
32579 this.root.render();
32580 if(!this.rootVisible){
32581 this.root.renderChildren();
32587 * Ext JS Library 1.1.1
32588 * Copyright(c) 2006-2007, Ext JS, LLC.
32590 * Originally Released Under LGPL - original licence link has changed is not relivant.
32593 * <script type="text/javascript">
32598 * @class Roo.tree.DefaultSelectionModel
32599 * @extends Roo.util.Observable
32600 * The default single selection for a TreePanel.
32601 * @param {Object} cfg Configuration
32603 Roo.tree.DefaultSelectionModel = function(cfg){
32604 this.selNode = null;
32610 * @event selectionchange
32611 * Fires when the selected node changes
32612 * @param {DefaultSelectionModel} this
32613 * @param {TreeNode} node the new selection
32615 "selectionchange" : true,
32618 * @event beforeselect
32619 * Fires before the selected node changes, return false to cancel the change
32620 * @param {DefaultSelectionModel} this
32621 * @param {TreeNode} node the new selection
32622 * @param {TreeNode} node the old selection
32624 "beforeselect" : true
32627 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32630 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32631 init : function(tree){
32633 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32634 tree.on("click", this.onNodeClick, this);
32637 onNodeClick : function(node, e){
32638 if (e.ctrlKey && this.selNode == node) {
32639 this.unselect(node);
32647 * @param {TreeNode} node The node to select
32648 * @return {TreeNode} The selected node
32650 select : function(node){
32651 var last = this.selNode;
32652 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32654 last.ui.onSelectedChange(false);
32656 this.selNode = node;
32657 node.ui.onSelectedChange(true);
32658 this.fireEvent("selectionchange", this, node, last);
32665 * @param {TreeNode} node The node to unselect
32667 unselect : function(node){
32668 if(this.selNode == node){
32669 this.clearSelections();
32674 * Clear all selections
32676 clearSelections : function(){
32677 var n = this.selNode;
32679 n.ui.onSelectedChange(false);
32680 this.selNode = null;
32681 this.fireEvent("selectionchange", this, null);
32687 * Get the selected node
32688 * @return {TreeNode} The selected node
32690 getSelectedNode : function(){
32691 return this.selNode;
32695 * Returns true if the node is selected
32696 * @param {TreeNode} node The node to check
32697 * @return {Boolean}
32699 isSelected : function(node){
32700 return this.selNode == node;
32704 * Selects the node above the selected node in the tree, intelligently walking the nodes
32705 * @return TreeNode The new selection
32707 selectPrevious : function(){
32708 var s = this.selNode || this.lastSelNode;
32712 var ps = s.previousSibling;
32714 if(!ps.isExpanded() || ps.childNodes.length < 1){
32715 return this.select(ps);
32717 var lc = ps.lastChild;
32718 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32721 return this.select(lc);
32723 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32724 return this.select(s.parentNode);
32730 * Selects the node above the selected node in the tree, intelligently walking the nodes
32731 * @return TreeNode The new selection
32733 selectNext : function(){
32734 var s = this.selNode || this.lastSelNode;
32738 if(s.firstChild && s.isExpanded()){
32739 return this.select(s.firstChild);
32740 }else if(s.nextSibling){
32741 return this.select(s.nextSibling);
32742 }else if(s.parentNode){
32744 s.parentNode.bubble(function(){
32745 if(this.nextSibling){
32746 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32755 onKeyDown : function(e){
32756 var s = this.selNode || this.lastSelNode;
32757 // undesirable, but required
32762 var k = e.getKey();
32770 this.selectPrevious();
32773 e.preventDefault();
32774 if(s.hasChildNodes()){
32775 if(!s.isExpanded()){
32777 }else if(s.firstChild){
32778 this.select(s.firstChild, e);
32783 e.preventDefault();
32784 if(s.hasChildNodes() && s.isExpanded()){
32786 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32787 this.select(s.parentNode, e);
32795 * @class Roo.tree.MultiSelectionModel
32796 * @extends Roo.util.Observable
32797 * Multi selection for a TreePanel.
32798 * @param {Object} cfg Configuration
32800 Roo.tree.MultiSelectionModel = function(){
32801 this.selNodes = [];
32805 * @event selectionchange
32806 * Fires when the selected nodes change
32807 * @param {MultiSelectionModel} this
32808 * @param {Array} nodes Array of the selected nodes
32810 "selectionchange" : true
32812 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32816 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32817 init : function(tree){
32819 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32820 tree.on("click", this.onNodeClick, this);
32823 onNodeClick : function(node, e){
32824 this.select(node, e, e.ctrlKey);
32829 * @param {TreeNode} node The node to select
32830 * @param {EventObject} e (optional) An event associated with the selection
32831 * @param {Boolean} keepExisting True to retain existing selections
32832 * @return {TreeNode} The selected node
32834 select : function(node, e, keepExisting){
32835 if(keepExisting !== true){
32836 this.clearSelections(true);
32838 if(this.isSelected(node)){
32839 this.lastSelNode = node;
32842 this.selNodes.push(node);
32843 this.selMap[node.id] = node;
32844 this.lastSelNode = node;
32845 node.ui.onSelectedChange(true);
32846 this.fireEvent("selectionchange", this, this.selNodes);
32852 * @param {TreeNode} node The node to unselect
32854 unselect : function(node){
32855 if(this.selMap[node.id]){
32856 node.ui.onSelectedChange(false);
32857 var sn = this.selNodes;
32860 index = sn.indexOf(node);
32862 for(var i = 0, len = sn.length; i < len; i++){
32870 this.selNodes.splice(index, 1);
32872 delete this.selMap[node.id];
32873 this.fireEvent("selectionchange", this, this.selNodes);
32878 * Clear all selections
32880 clearSelections : function(suppressEvent){
32881 var sn = this.selNodes;
32883 for(var i = 0, len = sn.length; i < len; i++){
32884 sn[i].ui.onSelectedChange(false);
32886 this.selNodes = [];
32888 if(suppressEvent !== true){
32889 this.fireEvent("selectionchange", this, this.selNodes);
32895 * Returns true if the node is selected
32896 * @param {TreeNode} node The node to check
32897 * @return {Boolean}
32899 isSelected : function(node){
32900 return this.selMap[node.id] ? true : false;
32904 * Returns an array of the selected nodes
32907 getSelectedNodes : function(){
32908 return this.selNodes;
32911 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32913 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32915 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32918 * Ext JS Library 1.1.1
32919 * Copyright(c) 2006-2007, Ext JS, LLC.
32921 * Originally Released Under LGPL - original licence link has changed is not relivant.
32924 * <script type="text/javascript">
32928 * @class Roo.tree.TreeNode
32929 * @extends Roo.data.Node
32930 * @cfg {String} text The text for this node
32931 * @cfg {Boolean} expanded true to start the node expanded
32932 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32933 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32934 * @cfg {Boolean} disabled true to start the node disabled
32935 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32936 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32937 * @cfg {String} cls A css class to be added to the node
32938 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32939 * @cfg {String} href URL of the link used for the node (defaults to #)
32940 * @cfg {String} hrefTarget target frame for the link
32941 * @cfg {String} qtip An Ext QuickTip for the node
32942 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32943 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32944 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32945 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32946 * (defaults to undefined with no checkbox rendered)
32948 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32950 Roo.tree.TreeNode = function(attributes){
32951 attributes = attributes || {};
32952 if(typeof attributes == "string"){
32953 attributes = {text: attributes};
32955 this.childrenRendered = false;
32956 this.rendered = false;
32957 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32958 this.expanded = attributes.expanded === true;
32959 this.isTarget = attributes.isTarget !== false;
32960 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32961 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32964 * Read-only. The text for this node. To change it use setText().
32967 this.text = attributes.text;
32969 * True if this node is disabled.
32972 this.disabled = attributes.disabled === true;
32976 * @event textchange
32977 * Fires when the text for this node is changed
32978 * @param {Node} this This node
32979 * @param {String} text The new text
32980 * @param {String} oldText The old text
32982 "textchange" : true,
32984 * @event beforeexpand
32985 * Fires before this node is expanded, return false to cancel.
32986 * @param {Node} this This node
32987 * @param {Boolean} deep
32988 * @param {Boolean} anim
32990 "beforeexpand" : true,
32992 * @event beforecollapse
32993 * Fires before this node is collapsed, return false to cancel.
32994 * @param {Node} this This node
32995 * @param {Boolean} deep
32996 * @param {Boolean} anim
32998 "beforecollapse" : true,
33001 * Fires when this node is expanded
33002 * @param {Node} this This node
33006 * @event disabledchange
33007 * Fires when the disabled status of this node changes
33008 * @param {Node} this This node
33009 * @param {Boolean} disabled
33011 "disabledchange" : true,
33014 * Fires when this node is collapsed
33015 * @param {Node} this This node
33019 * @event beforeclick
33020 * Fires before click processing. Return false to cancel the default action.
33021 * @param {Node} this This node
33022 * @param {Roo.EventObject} e The event object
33024 "beforeclick":true,
33026 * @event checkchange
33027 * Fires when a node with a checkbox's checked property changes
33028 * @param {Node} this This node
33029 * @param {Boolean} checked
33031 "checkchange":true,
33034 * Fires when this node is clicked
33035 * @param {Node} this This node
33036 * @param {Roo.EventObject} e The event object
33041 * Fires when this node is double clicked
33042 * @param {Node} this This node
33043 * @param {Roo.EventObject} e The event object
33047 * @event contextmenu
33048 * Fires when this node is right clicked
33049 * @param {Node} this This node
33050 * @param {Roo.EventObject} e The event object
33052 "contextmenu":true,
33054 * @event beforechildrenrendered
33055 * Fires right before the child nodes for this node are rendered
33056 * @param {Node} this This node
33058 "beforechildrenrendered":true
33061 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33064 * Read-only. The UI for this node
33067 this.ui = new uiClass(this);
33069 // finally support items[]
33070 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33075 Roo.each(this.attributes.items, function(c) {
33076 this.appendChild(Roo.factory(c,Roo.Tree));
33078 delete this.attributes.items;
33083 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33084 preventHScroll: true,
33086 * Returns true if this node is expanded
33087 * @return {Boolean}
33089 isExpanded : function(){
33090 return this.expanded;
33094 * Returns the UI object for this node
33095 * @return {TreeNodeUI}
33097 getUI : function(){
33101 // private override
33102 setFirstChild : function(node){
33103 var of = this.firstChild;
33104 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33105 if(this.childrenRendered && of && node != of){
33106 of.renderIndent(true, true);
33109 this.renderIndent(true, true);
33113 // private override
33114 setLastChild : function(node){
33115 var ol = this.lastChild;
33116 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33117 if(this.childrenRendered && ol && node != ol){
33118 ol.renderIndent(true, true);
33121 this.renderIndent(true, true);
33125 // these methods are overridden to provide lazy rendering support
33126 // private override
33127 appendChild : function()
33129 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33130 if(node && this.childrenRendered){
33133 this.ui.updateExpandIcon();
33137 // private override
33138 removeChild : function(node){
33139 this.ownerTree.getSelectionModel().unselect(node);
33140 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33141 // if it's been rendered remove dom node
33142 if(this.childrenRendered){
33145 if(this.childNodes.length < 1){
33146 this.collapse(false, false);
33148 this.ui.updateExpandIcon();
33150 if(!this.firstChild) {
33151 this.childrenRendered = false;
33156 // private override
33157 insertBefore : function(node, refNode){
33158 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33159 if(newNode && refNode && this.childrenRendered){
33162 this.ui.updateExpandIcon();
33167 * Sets the text for this node
33168 * @param {String} text
33170 setText : function(text){
33171 var oldText = this.text;
33173 this.attributes.text = text;
33174 if(this.rendered){ // event without subscribing
33175 this.ui.onTextChange(this, text, oldText);
33177 this.fireEvent("textchange", this, text, oldText);
33181 * Triggers selection of this node
33183 select : function(){
33184 this.getOwnerTree().getSelectionModel().select(this);
33188 * Triggers deselection of this node
33190 unselect : function(){
33191 this.getOwnerTree().getSelectionModel().unselect(this);
33195 * Returns true if this node is selected
33196 * @return {Boolean}
33198 isSelected : function(){
33199 return this.getOwnerTree().getSelectionModel().isSelected(this);
33203 * Expand this node.
33204 * @param {Boolean} deep (optional) True to expand all children as well
33205 * @param {Boolean} anim (optional) false to cancel the default animation
33206 * @param {Function} callback (optional) A callback to be called when
33207 * expanding this node completes (does not wait for deep expand to complete).
33208 * Called with 1 parameter, this node.
33210 expand : function(deep, anim, callback){
33211 if(!this.expanded){
33212 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33215 if(!this.childrenRendered){
33216 this.renderChildren();
33218 this.expanded = true;
33219 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33220 this.ui.animExpand(function(){
33221 this.fireEvent("expand", this);
33222 if(typeof callback == "function"){
33226 this.expandChildNodes(true);
33228 }.createDelegate(this));
33232 this.fireEvent("expand", this);
33233 if(typeof callback == "function"){
33238 if(typeof callback == "function"){
33243 this.expandChildNodes(true);
33247 isHiddenRoot : function(){
33248 return this.isRoot && !this.getOwnerTree().rootVisible;
33252 * Collapse this node.
33253 * @param {Boolean} deep (optional) True to collapse all children as well
33254 * @param {Boolean} anim (optional) false to cancel the default animation
33256 collapse : function(deep, anim){
33257 if(this.expanded && !this.isHiddenRoot()){
33258 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33261 this.expanded = false;
33262 if((this.getOwnerTree().animate && anim !== false) || anim){
33263 this.ui.animCollapse(function(){
33264 this.fireEvent("collapse", this);
33266 this.collapseChildNodes(true);
33268 }.createDelegate(this));
33271 this.ui.collapse();
33272 this.fireEvent("collapse", this);
33276 var cs = this.childNodes;
33277 for(var i = 0, len = cs.length; i < len; i++) {
33278 cs[i].collapse(true, false);
33284 delayedExpand : function(delay){
33285 if(!this.expandProcId){
33286 this.expandProcId = this.expand.defer(delay, this);
33291 cancelExpand : function(){
33292 if(this.expandProcId){
33293 clearTimeout(this.expandProcId);
33295 this.expandProcId = false;
33299 * Toggles expanded/collapsed state of the node
33301 toggle : function(){
33310 * Ensures all parent nodes are expanded
33312 ensureVisible : function(callback){
33313 var tree = this.getOwnerTree();
33314 tree.expandPath(this.parentNode.getPath(), false, function(){
33315 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33316 Roo.callback(callback);
33317 }.createDelegate(this));
33321 * Expand all child nodes
33322 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33324 expandChildNodes : function(deep){
33325 var cs = this.childNodes;
33326 for(var i = 0, len = cs.length; i < len; i++) {
33327 cs[i].expand(deep);
33332 * Collapse all child nodes
33333 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33335 collapseChildNodes : function(deep){
33336 var cs = this.childNodes;
33337 for(var i = 0, len = cs.length; i < len; i++) {
33338 cs[i].collapse(deep);
33343 * Disables this node
33345 disable : function(){
33346 this.disabled = true;
33348 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33349 this.ui.onDisableChange(this, true);
33351 this.fireEvent("disabledchange", this, true);
33355 * Enables this node
33357 enable : function(){
33358 this.disabled = false;
33359 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33360 this.ui.onDisableChange(this, false);
33362 this.fireEvent("disabledchange", this, false);
33366 renderChildren : function(suppressEvent){
33367 if(suppressEvent !== false){
33368 this.fireEvent("beforechildrenrendered", this);
33370 var cs = this.childNodes;
33371 for(var i = 0, len = cs.length; i < len; i++){
33372 cs[i].render(true);
33374 this.childrenRendered = true;
33378 sort : function(fn, scope){
33379 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33380 if(this.childrenRendered){
33381 var cs = this.childNodes;
33382 for(var i = 0, len = cs.length; i < len; i++){
33383 cs[i].render(true);
33389 render : function(bulkRender){
33390 this.ui.render(bulkRender);
33391 if(!this.rendered){
33392 this.rendered = true;
33394 this.expanded = false;
33395 this.expand(false, false);
33401 renderIndent : function(deep, refresh){
33403 this.ui.childIndent = null;
33405 this.ui.renderIndent();
33406 if(deep === true && this.childrenRendered){
33407 var cs = this.childNodes;
33408 for(var i = 0, len = cs.length; i < len; i++){
33409 cs[i].renderIndent(true, refresh);
33415 * Ext JS Library 1.1.1
33416 * Copyright(c) 2006-2007, Ext JS, LLC.
33418 * Originally Released Under LGPL - original licence link has changed is not relivant.
33421 * <script type="text/javascript">
33425 * @class Roo.tree.AsyncTreeNode
33426 * @extends Roo.tree.TreeNode
33427 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33429 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33431 Roo.tree.AsyncTreeNode = function(config){
33432 this.loaded = false;
33433 this.loading = false;
33434 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33436 * @event beforeload
33437 * Fires before this node is loaded, return false to cancel
33438 * @param {Node} this This node
33440 this.addEvents({'beforeload':true, 'load': true});
33443 * Fires when this node is loaded
33444 * @param {Node} this This node
33447 * The loader used by this node (defaults to using the tree's defined loader)
33452 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33453 expand : function(deep, anim, callback){
33454 if(this.loading){ // if an async load is already running, waiting til it's done
33456 var f = function(){
33457 if(!this.loading){ // done loading
33458 clearInterval(timer);
33459 this.expand(deep, anim, callback);
33461 }.createDelegate(this);
33462 timer = setInterval(f, 200);
33466 if(this.fireEvent("beforeload", this) === false){
33469 this.loading = true;
33470 this.ui.beforeLoad(this);
33471 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33473 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33477 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33481 * Returns true if this node is currently loading
33482 * @return {Boolean}
33484 isLoading : function(){
33485 return this.loading;
33488 loadComplete : function(deep, anim, callback){
33489 this.loading = false;
33490 this.loaded = true;
33491 this.ui.afterLoad(this);
33492 this.fireEvent("load", this);
33493 this.expand(deep, anim, callback);
33497 * Returns true if this node has been loaded
33498 * @return {Boolean}
33500 isLoaded : function(){
33501 return this.loaded;
33504 hasChildNodes : function(){
33505 if(!this.isLeaf() && !this.loaded){
33508 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33513 * Trigger a reload for this node
33514 * @param {Function} callback
33516 reload : function(callback){
33517 this.collapse(false, false);
33518 while(this.firstChild){
33519 this.removeChild(this.firstChild);
33521 this.childrenRendered = false;
33522 this.loaded = false;
33523 if(this.isHiddenRoot()){
33524 this.expanded = false;
33526 this.expand(false, false, callback);
33530 * Ext JS Library 1.1.1
33531 * Copyright(c) 2006-2007, Ext JS, LLC.
33533 * Originally Released Under LGPL - original licence link has changed is not relivant.
33536 * <script type="text/javascript">
33540 * @class Roo.tree.TreeNodeUI
33542 * @param {Object} node The node to render
33543 * The TreeNode UI implementation is separate from the
33544 * tree implementation. Unless you are customizing the tree UI,
33545 * you should never have to use this directly.
33547 Roo.tree.TreeNodeUI = function(node){
33549 this.rendered = false;
33550 this.animating = false;
33551 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33554 Roo.tree.TreeNodeUI.prototype = {
33555 removeChild : function(node){
33557 this.ctNode.removeChild(node.ui.getEl());
33561 beforeLoad : function(){
33562 this.addClass("x-tree-node-loading");
33565 afterLoad : function(){
33566 this.removeClass("x-tree-node-loading");
33569 onTextChange : function(node, text, oldText){
33571 this.textNode.innerHTML = text;
33575 onDisableChange : function(node, state){
33576 this.disabled = state;
33578 this.addClass("x-tree-node-disabled");
33580 this.removeClass("x-tree-node-disabled");
33584 onSelectedChange : function(state){
33587 this.addClass("x-tree-selected");
33590 this.removeClass("x-tree-selected");
33594 onMove : function(tree, node, oldParent, newParent, index, refNode){
33595 this.childIndent = null;
33597 var targetNode = newParent.ui.getContainer();
33598 if(!targetNode){//target not rendered
33599 this.holder = document.createElement("div");
33600 this.holder.appendChild(this.wrap);
33603 var insertBefore = refNode ? refNode.ui.getEl() : null;
33605 targetNode.insertBefore(this.wrap, insertBefore);
33607 targetNode.appendChild(this.wrap);
33609 this.node.renderIndent(true);
33613 addClass : function(cls){
33615 Roo.fly(this.elNode).addClass(cls);
33619 removeClass : function(cls){
33621 Roo.fly(this.elNode).removeClass(cls);
33625 remove : function(){
33627 this.holder = document.createElement("div");
33628 this.holder.appendChild(this.wrap);
33632 fireEvent : function(){
33633 return this.node.fireEvent.apply(this.node, arguments);
33636 initEvents : function(){
33637 this.node.on("move", this.onMove, this);
33638 var E = Roo.EventManager;
33639 var a = this.anchor;
33641 var el = Roo.fly(a, '_treeui');
33643 if(Roo.isOpera){ // opera render bug ignores the CSS
33644 el.setStyle("text-decoration", "none");
33647 el.on("click", this.onClick, this);
33648 el.on("dblclick", this.onDblClick, this);
33651 Roo.EventManager.on(this.checkbox,
33652 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33655 el.on("contextmenu", this.onContextMenu, this);
33657 var icon = Roo.fly(this.iconNode);
33658 icon.on("click", this.onClick, this);
33659 icon.on("dblclick", this.onDblClick, this);
33660 icon.on("contextmenu", this.onContextMenu, this);
33661 E.on(this.ecNode, "click", this.ecClick, this, true);
33663 if(this.node.disabled){
33664 this.addClass("x-tree-node-disabled");
33666 if(this.node.hidden){
33667 this.addClass("x-tree-node-disabled");
33669 var ot = this.node.getOwnerTree();
33670 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33671 if(dd && (!this.node.isRoot || ot.rootVisible)){
33672 Roo.dd.Registry.register(this.elNode, {
33674 handles: this.getDDHandles(),
33680 getDDHandles : function(){
33681 return [this.iconNode, this.textNode];
33686 this.wrap.style.display = "none";
33692 this.wrap.style.display = "";
33696 onContextMenu : function(e){
33697 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33698 e.preventDefault();
33700 this.fireEvent("contextmenu", this.node, e);
33704 onClick : function(e){
33709 if(this.fireEvent("beforeclick", this.node, e) !== false){
33710 if(!this.disabled && this.node.attributes.href){
33711 this.fireEvent("click", this.node, e);
33714 e.preventDefault();
33719 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33720 this.node.toggle();
33723 this.fireEvent("click", this.node, e);
33729 onDblClick : function(e){
33730 e.preventDefault();
33735 this.toggleCheck();
33737 if(!this.animating && this.node.hasChildNodes()){
33738 this.node.toggle();
33740 this.fireEvent("dblclick", this.node, e);
33743 onCheckChange : function(){
33744 var checked = this.checkbox.checked;
33745 this.node.attributes.checked = checked;
33746 this.fireEvent('checkchange', this.node, checked);
33749 ecClick : function(e){
33750 if(!this.animating && this.node.hasChildNodes()){
33751 this.node.toggle();
33755 startDrop : function(){
33756 this.dropping = true;
33759 // delayed drop so the click event doesn't get fired on a drop
33760 endDrop : function(){
33761 setTimeout(function(){
33762 this.dropping = false;
33763 }.createDelegate(this), 50);
33766 expand : function(){
33767 this.updateExpandIcon();
33768 this.ctNode.style.display = "";
33771 focus : function(){
33772 if(!this.node.preventHScroll){
33773 try{this.anchor.focus();
33775 }else if(!Roo.isIE){
33777 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33778 var l = noscroll.scrollLeft;
33779 this.anchor.focus();
33780 noscroll.scrollLeft = l;
33785 toggleCheck : function(value){
33786 var cb = this.checkbox;
33788 cb.checked = (value === undefined ? !cb.checked : value);
33794 this.anchor.blur();
33798 animExpand : function(callback){
33799 var ct = Roo.get(this.ctNode);
33801 if(!this.node.hasChildNodes()){
33802 this.updateExpandIcon();
33803 this.ctNode.style.display = "";
33804 Roo.callback(callback);
33807 this.animating = true;
33808 this.updateExpandIcon();
33811 callback : function(){
33812 this.animating = false;
33813 Roo.callback(callback);
33816 duration: this.node.ownerTree.duration || .25
33820 highlight : function(){
33821 var tree = this.node.getOwnerTree();
33822 Roo.fly(this.wrap).highlight(
33823 tree.hlColor || "C3DAF9",
33824 {endColor: tree.hlBaseColor}
33828 collapse : function(){
33829 this.updateExpandIcon();
33830 this.ctNode.style.display = "none";
33833 animCollapse : function(callback){
33834 var ct = Roo.get(this.ctNode);
33835 ct.enableDisplayMode('block');
33838 this.animating = true;
33839 this.updateExpandIcon();
33842 callback : function(){
33843 this.animating = false;
33844 Roo.callback(callback);
33847 duration: this.node.ownerTree.duration || .25
33851 getContainer : function(){
33852 return this.ctNode;
33855 getEl : function(){
33859 appendDDGhost : function(ghostNode){
33860 ghostNode.appendChild(this.elNode.cloneNode(true));
33863 getDDRepairXY : function(){
33864 return Roo.lib.Dom.getXY(this.iconNode);
33867 onRender : function(){
33871 render : function(bulkRender){
33872 var n = this.node, a = n.attributes;
33873 var targetNode = n.parentNode ?
33874 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33876 if(!this.rendered){
33877 this.rendered = true;
33879 this.renderElements(n, a, targetNode, bulkRender);
33882 if(this.textNode.setAttributeNS){
33883 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33885 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33888 this.textNode.setAttribute("ext:qtip", a.qtip);
33890 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33893 }else if(a.qtipCfg){
33894 a.qtipCfg.target = Roo.id(this.textNode);
33895 Roo.QuickTips.register(a.qtipCfg);
33898 if(!this.node.expanded){
33899 this.updateExpandIcon();
33902 if(bulkRender === true) {
33903 targetNode.appendChild(this.wrap);
33908 renderElements : function(n, a, targetNode, bulkRender)
33910 // add some indent caching, this helps performance when rendering a large tree
33911 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33912 var t = n.getOwnerTree();
33913 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33914 if (typeof(n.attributes.html) != 'undefined') {
33915 txt = n.attributes.html;
33917 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33918 var cb = typeof a.checked == 'boolean';
33919 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33920 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33921 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33922 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33923 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33924 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33925 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33926 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33927 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33928 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33931 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33932 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33933 n.nextSibling.ui.getEl(), buf.join(""));
33935 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33938 this.elNode = this.wrap.childNodes[0];
33939 this.ctNode = this.wrap.childNodes[1];
33940 var cs = this.elNode.childNodes;
33941 this.indentNode = cs[0];
33942 this.ecNode = cs[1];
33943 this.iconNode = cs[2];
33946 this.checkbox = cs[3];
33949 this.anchor = cs[index];
33950 this.textNode = cs[index].firstChild;
33953 getAnchor : function(){
33954 return this.anchor;
33957 getTextEl : function(){
33958 return this.textNode;
33961 getIconEl : function(){
33962 return this.iconNode;
33965 isChecked : function(){
33966 return this.checkbox ? this.checkbox.checked : false;
33969 updateExpandIcon : function(){
33971 var n = this.node, c1, c2;
33972 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33973 var hasChild = n.hasChildNodes();
33977 c1 = "x-tree-node-collapsed";
33978 c2 = "x-tree-node-expanded";
33981 c1 = "x-tree-node-expanded";
33982 c2 = "x-tree-node-collapsed";
33985 this.removeClass("x-tree-node-leaf");
33986 this.wasLeaf = false;
33988 if(this.c1 != c1 || this.c2 != c2){
33989 Roo.fly(this.elNode).replaceClass(c1, c2);
33990 this.c1 = c1; this.c2 = c2;
33993 // this changes non-leafs into leafs if they have no children.
33994 // it's not very rational behaviour..
33996 if(!this.wasLeaf && this.node.leaf){
33997 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34000 this.wasLeaf = true;
34003 var ecc = "x-tree-ec-icon "+cls;
34004 if(this.ecc != ecc){
34005 this.ecNode.className = ecc;
34011 getChildIndent : function(){
34012 if(!this.childIndent){
34016 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34018 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34020 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34025 this.childIndent = buf.join("");
34027 return this.childIndent;
34030 renderIndent : function(){
34033 var p = this.node.parentNode;
34035 indent = p.ui.getChildIndent();
34037 if(this.indentMarkup != indent){ // don't rerender if not required
34038 this.indentNode.innerHTML = indent;
34039 this.indentMarkup = indent;
34041 this.updateExpandIcon();
34046 Roo.tree.RootTreeNodeUI = function(){
34047 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34049 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34050 render : function(){
34051 if(!this.rendered){
34052 var targetNode = this.node.ownerTree.innerCt.dom;
34053 this.node.expanded = true;
34054 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34055 this.wrap = this.ctNode = targetNode.firstChild;
34058 collapse : function(){
34060 expand : function(){
34064 * Ext JS Library 1.1.1
34065 * Copyright(c) 2006-2007, Ext JS, LLC.
34067 * Originally Released Under LGPL - original licence link has changed is not relivant.
34070 * <script type="text/javascript">
34073 * @class Roo.tree.TreeLoader
34074 * @extends Roo.util.Observable
34075 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34076 * nodes from a specified URL. The response must be a javascript Array definition
34077 * who's elements are node definition objects. eg:
34082 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34083 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34090 * The old style respose with just an array is still supported, but not recommended.
34093 * A server request is sent, and child nodes are loaded only when a node is expanded.
34094 * The loading node's id is passed to the server under the parameter name "node" to
34095 * enable the server to produce the correct child nodes.
34097 * To pass extra parameters, an event handler may be attached to the "beforeload"
34098 * event, and the parameters specified in the TreeLoader's baseParams property:
34100 myTreeLoader.on("beforeload", function(treeLoader, node) {
34101 this.baseParams.category = node.attributes.category;
34104 * This would pass an HTTP parameter called "category" to the server containing
34105 * the value of the Node's "category" attribute.
34107 * Creates a new Treeloader.
34108 * @param {Object} config A config object containing config properties.
34110 Roo.tree.TreeLoader = function(config){
34111 this.baseParams = {};
34112 this.requestMethod = "POST";
34113 Roo.apply(this, config);
34118 * @event beforeload
34119 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34120 * @param {Object} This TreeLoader object.
34121 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34122 * @param {Object} callback The callback function specified in the {@link #load} call.
34127 * Fires when the node has been successfuly loaded.
34128 * @param {Object} This TreeLoader object.
34129 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34130 * @param {Object} response The response object containing the data from the server.
34134 * @event loadexception
34135 * Fires if the network request failed.
34136 * @param {Object} This TreeLoader object.
34137 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34138 * @param {Object} response The response object containing the data from the server.
34140 loadexception : true,
34143 * Fires before a node is created, enabling you to return custom Node types
34144 * @param {Object} This TreeLoader object.
34145 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34150 Roo.tree.TreeLoader.superclass.constructor.call(this);
34153 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34155 * @cfg {String} dataUrl The URL from which to request a Json string which
34156 * specifies an array of node definition object representing the child nodes
34160 * @cfg {String} requestMethod either GET or POST
34161 * defaults to POST (due to BC)
34165 * @cfg {Object} baseParams (optional) An object containing properties which
34166 * specify HTTP parameters to be passed to each request for child nodes.
34169 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34170 * created by this loader. If the attributes sent by the server have an attribute in this object,
34171 * they take priority.
34174 * @cfg {Object} uiProviders (optional) An object containing properties which
34176 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34177 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34178 * <i>uiProvider</i> attribute of a returned child node is a string rather
34179 * than a reference to a TreeNodeUI implementation, this that string value
34180 * is used as a property name in the uiProviders object. You can define the provider named
34181 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34186 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34187 * child nodes before loading.
34189 clearOnLoad : true,
34192 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34193 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34194 * Grid query { data : [ .....] }
34199 * @cfg {String} queryParam (optional)
34200 * Name of the query as it will be passed on the querystring (defaults to 'node')
34201 * eg. the request will be ?node=[id]
34208 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34209 * This is called automatically when a node is expanded, but may be used to reload
34210 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34211 * @param {Roo.tree.TreeNode} node
34212 * @param {Function} callback
34214 load : function(node, callback){
34215 if(this.clearOnLoad){
34216 while(node.firstChild){
34217 node.removeChild(node.firstChild);
34220 if(node.attributes.children){ // preloaded json children
34221 var cs = node.attributes.children;
34222 for(var i = 0, len = cs.length; i < len; i++){
34223 node.appendChild(this.createNode(cs[i]));
34225 if(typeof callback == "function"){
34228 }else if(this.dataUrl){
34229 this.requestData(node, callback);
34233 getParams: function(node){
34234 var buf = [], bp = this.baseParams;
34235 for(var key in bp){
34236 if(typeof bp[key] != "function"){
34237 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34240 var n = this.queryParam === false ? 'node' : this.queryParam;
34241 buf.push(n + "=", encodeURIComponent(node.id));
34242 return buf.join("");
34245 requestData : function(node, callback){
34246 if(this.fireEvent("beforeload", this, node, callback) !== false){
34247 this.transId = Roo.Ajax.request({
34248 method:this.requestMethod,
34249 url: this.dataUrl||this.url,
34250 success: this.handleResponse,
34251 failure: this.handleFailure,
34253 argument: {callback: callback, node: node},
34254 params: this.getParams(node)
34257 // if the load is cancelled, make sure we notify
34258 // the node that we are done
34259 if(typeof callback == "function"){
34265 isLoading : function(){
34266 return this.transId ? true : false;
34269 abort : function(){
34270 if(this.isLoading()){
34271 Roo.Ajax.abort(this.transId);
34276 createNode : function(attr)
34278 // apply baseAttrs, nice idea Corey!
34279 if(this.baseAttrs){
34280 Roo.applyIf(attr, this.baseAttrs);
34282 if(this.applyLoader !== false){
34283 attr.loader = this;
34285 // uiProvider = depreciated..
34287 if(typeof(attr.uiProvider) == 'string'){
34288 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34289 /** eval:var:attr */ eval(attr.uiProvider);
34291 if(typeof(this.uiProviders['default']) != 'undefined') {
34292 attr.uiProvider = this.uiProviders['default'];
34295 this.fireEvent('create', this, attr);
34297 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34299 new Roo.tree.TreeNode(attr) :
34300 new Roo.tree.AsyncTreeNode(attr));
34303 processResponse : function(response, node, callback)
34305 var json = response.responseText;
34308 var o = Roo.decode(json);
34310 if (this.root === false && typeof(o.success) != undefined) {
34311 this.root = 'data'; // the default behaviour for list like data..
34314 if (this.root !== false && !o.success) {
34315 // it's a failure condition.
34316 var a = response.argument;
34317 this.fireEvent("loadexception", this, a.node, response);
34318 Roo.log("Load failed - should have a handler really");
34324 if (this.root !== false) {
34328 for(var i = 0, len = o.length; i < len; i++){
34329 var n = this.createNode(o[i]);
34331 node.appendChild(n);
34334 if(typeof callback == "function"){
34335 callback(this, node);
34338 this.handleFailure(response);
34342 handleResponse : function(response){
34343 this.transId = false;
34344 var a = response.argument;
34345 this.processResponse(response, a.node, a.callback);
34346 this.fireEvent("load", this, a.node, response);
34349 handleFailure : function(response)
34351 // should handle failure better..
34352 this.transId = false;
34353 var a = response.argument;
34354 this.fireEvent("loadexception", this, a.node, response);
34355 if(typeof a.callback == "function"){
34356 a.callback(this, a.node);
34361 * Ext JS Library 1.1.1
34362 * Copyright(c) 2006-2007, Ext JS, LLC.
34364 * Originally Released Under LGPL - original licence link has changed is not relivant.
34367 * <script type="text/javascript">
34371 * @class Roo.tree.TreeFilter
34372 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34373 * @param {TreePanel} tree
34374 * @param {Object} config (optional)
34376 Roo.tree.TreeFilter = function(tree, config){
34378 this.filtered = {};
34379 Roo.apply(this, config);
34382 Roo.tree.TreeFilter.prototype = {
34389 * Filter the data by a specific attribute.
34390 * @param {String/RegExp} value Either string that the attribute value
34391 * should start with or a RegExp to test against the attribute
34392 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34393 * @param {TreeNode} startNode (optional) The node to start the filter at.
34395 filter : function(value, attr, startNode){
34396 attr = attr || "text";
34398 if(typeof value == "string"){
34399 var vlen = value.length;
34400 // auto clear empty filter
34401 if(vlen == 0 && this.clearBlank){
34405 value = value.toLowerCase();
34407 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34409 }else if(value.exec){ // regex?
34411 return value.test(n.attributes[attr]);
34414 throw 'Illegal filter type, must be string or regex';
34416 this.filterBy(f, null, startNode);
34420 * Filter by a function. The passed function will be called with each
34421 * node in the tree (or from the startNode). If the function returns true, the node is kept
34422 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34423 * @param {Function} fn The filter function
34424 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34426 filterBy : function(fn, scope, startNode){
34427 startNode = startNode || this.tree.root;
34428 if(this.autoClear){
34431 var af = this.filtered, rv = this.reverse;
34432 var f = function(n){
34433 if(n == startNode){
34439 var m = fn.call(scope || n, n);
34447 startNode.cascade(f);
34450 if(typeof id != "function"){
34452 if(n && n.parentNode){
34453 n.parentNode.removeChild(n);
34461 * Clears the current filter. Note: with the "remove" option
34462 * set a filter cannot be cleared.
34464 clear : function(){
34466 var af = this.filtered;
34468 if(typeof id != "function"){
34475 this.filtered = {};
34480 * Ext JS Library 1.1.1
34481 * Copyright(c) 2006-2007, Ext JS, LLC.
34483 * Originally Released Under LGPL - original licence link has changed is not relivant.
34486 * <script type="text/javascript">
34491 * @class Roo.tree.TreeSorter
34492 * Provides sorting of nodes in a TreePanel
34494 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34495 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34496 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34497 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34498 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34499 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34501 * @param {TreePanel} tree
34502 * @param {Object} config
34504 Roo.tree.TreeSorter = function(tree, config){
34505 Roo.apply(this, config);
34506 tree.on("beforechildrenrendered", this.doSort, this);
34507 tree.on("append", this.updateSort, this);
34508 tree.on("insert", this.updateSort, this);
34510 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34511 var p = this.property || "text";
34512 var sortType = this.sortType;
34513 var fs = this.folderSort;
34514 var cs = this.caseSensitive === true;
34515 var leafAttr = this.leafAttr || 'leaf';
34517 this.sortFn = function(n1, n2){
34519 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34522 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34526 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34527 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34529 return dsc ? +1 : -1;
34531 return dsc ? -1 : +1;
34538 Roo.tree.TreeSorter.prototype = {
34539 doSort : function(node){
34540 node.sort(this.sortFn);
34543 compareNodes : function(n1, n2){
34544 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34547 updateSort : function(tree, node){
34548 if(node.childrenRendered){
34549 this.doSort.defer(1, this, [node]);
34554 * Ext JS Library 1.1.1
34555 * Copyright(c) 2006-2007, Ext JS, LLC.
34557 * Originally Released Under LGPL - original licence link has changed is not relivant.
34560 * <script type="text/javascript">
34563 if(Roo.dd.DropZone){
34565 Roo.tree.TreeDropZone = function(tree, config){
34566 this.allowParentInsert = false;
34567 this.allowContainerDrop = false;
34568 this.appendOnly = false;
34569 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34571 this.lastInsertClass = "x-tree-no-status";
34572 this.dragOverData = {};
34575 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34576 ddGroup : "TreeDD",
34579 expandDelay : 1000,
34581 expandNode : function(node){
34582 if(node.hasChildNodes() && !node.isExpanded()){
34583 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34587 queueExpand : function(node){
34588 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34591 cancelExpand : function(){
34592 if(this.expandProcId){
34593 clearTimeout(this.expandProcId);
34594 this.expandProcId = false;
34598 isValidDropPoint : function(n, pt, dd, e, data){
34599 if(!n || !data){ return false; }
34600 var targetNode = n.node;
34601 var dropNode = data.node;
34602 // default drop rules
34603 if(!(targetNode && targetNode.isTarget && pt)){
34606 if(pt == "append" && targetNode.allowChildren === false){
34609 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34612 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34615 // reuse the object
34616 var overEvent = this.dragOverData;
34617 overEvent.tree = this.tree;
34618 overEvent.target = targetNode;
34619 overEvent.data = data;
34620 overEvent.point = pt;
34621 overEvent.source = dd;
34622 overEvent.rawEvent = e;
34623 overEvent.dropNode = dropNode;
34624 overEvent.cancel = false;
34625 var result = this.tree.fireEvent("nodedragover", overEvent);
34626 return overEvent.cancel === false && result !== false;
34629 getDropPoint : function(e, n, dd)
34633 return tn.allowChildren !== false ? "append" : false; // always append for root
34635 var dragEl = n.ddel;
34636 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34637 var y = Roo.lib.Event.getPageY(e);
34638 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34640 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34641 var noAppend = tn.allowChildren === false;
34642 if(this.appendOnly || tn.parentNode.allowChildren === false){
34643 return noAppend ? false : "append";
34645 var noBelow = false;
34646 if(!this.allowParentInsert){
34647 noBelow = tn.hasChildNodes() && tn.isExpanded();
34649 var q = (b - t) / (noAppend ? 2 : 3);
34650 if(y >= t && y < (t + q)){
34652 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34659 onNodeEnter : function(n, dd, e, data)
34661 this.cancelExpand();
34664 onNodeOver : function(n, dd, e, data)
34667 var pt = this.getDropPoint(e, n, dd);
34670 // auto node expand check
34671 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34672 this.queueExpand(node);
34673 }else if(pt != "append"){
34674 this.cancelExpand();
34677 // set the insert point style on the target node
34678 var returnCls = this.dropNotAllowed;
34679 if(this.isValidDropPoint(n, pt, dd, e, data)){
34684 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34685 cls = "x-tree-drag-insert-above";
34686 }else if(pt == "below"){
34687 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34688 cls = "x-tree-drag-insert-below";
34690 returnCls = "x-tree-drop-ok-append";
34691 cls = "x-tree-drag-append";
34693 if(this.lastInsertClass != cls){
34694 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34695 this.lastInsertClass = cls;
34702 onNodeOut : function(n, dd, e, data){
34704 this.cancelExpand();
34705 this.removeDropIndicators(n);
34708 onNodeDrop : function(n, dd, e, data){
34709 var point = this.getDropPoint(e, n, dd);
34710 var targetNode = n.node;
34711 targetNode.ui.startDrop();
34712 if(!this.isValidDropPoint(n, point, dd, e, data)){
34713 targetNode.ui.endDrop();
34716 // first try to find the drop node
34717 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34720 target: targetNode,
34725 dropNode: dropNode,
34728 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34729 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34730 targetNode.ui.endDrop();
34733 // allow target changing
34734 targetNode = dropEvent.target;
34735 if(point == "append" && !targetNode.isExpanded()){
34736 targetNode.expand(false, null, function(){
34737 this.completeDrop(dropEvent);
34738 }.createDelegate(this));
34740 this.completeDrop(dropEvent);
34745 completeDrop : function(de){
34746 var ns = de.dropNode, p = de.point, t = de.target;
34747 if(!(ns instanceof Array)){
34751 for(var i = 0, len = ns.length; i < len; i++){
34754 t.parentNode.insertBefore(n, t);
34755 }else if(p == "below"){
34756 t.parentNode.insertBefore(n, t.nextSibling);
34762 if(this.tree.hlDrop){
34766 this.tree.fireEvent("nodedrop", de);
34769 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34770 if(this.tree.hlDrop){
34771 dropNode.ui.focus();
34772 dropNode.ui.highlight();
34774 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34777 getTree : function(){
34781 removeDropIndicators : function(n){
34784 Roo.fly(el).removeClass([
34785 "x-tree-drag-insert-above",
34786 "x-tree-drag-insert-below",
34787 "x-tree-drag-append"]);
34788 this.lastInsertClass = "_noclass";
34792 beforeDragDrop : function(target, e, id){
34793 this.cancelExpand();
34797 afterRepair : function(data){
34798 if(data && Roo.enableFx){
34799 data.node.ui.highlight();
34809 * Ext JS Library 1.1.1
34810 * Copyright(c) 2006-2007, Ext JS, LLC.
34812 * Originally Released Under LGPL - original licence link has changed is not relivant.
34815 * <script type="text/javascript">
34819 if(Roo.dd.DragZone){
34820 Roo.tree.TreeDragZone = function(tree, config){
34821 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34825 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34826 ddGroup : "TreeDD",
34828 onBeforeDrag : function(data, e){
34830 return n && n.draggable && !n.disabled;
34834 onInitDrag : function(e){
34835 var data = this.dragData;
34836 this.tree.getSelectionModel().select(data.node);
34837 this.proxy.update("");
34838 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34839 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34842 getRepairXY : function(e, data){
34843 return data.node.ui.getDDRepairXY();
34846 onEndDrag : function(data, e){
34847 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34852 onValidDrop : function(dd, e, id){
34853 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34857 beforeInvalidDrop : function(e, id){
34858 // this scrolls the original position back into view
34859 var sm = this.tree.getSelectionModel();
34860 sm.clearSelections();
34861 sm.select(this.dragData.node);
34866 * Ext JS Library 1.1.1
34867 * Copyright(c) 2006-2007, Ext JS, LLC.
34869 * Originally Released Under LGPL - original licence link has changed is not relivant.
34872 * <script type="text/javascript">
34875 * @class Roo.tree.TreeEditor
34876 * @extends Roo.Editor
34877 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34878 * as the editor field.
34880 * @param {Object} config (used to be the tree panel.)
34881 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34883 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34884 * @cfg {Roo.form.TextField|Object} field The field configuration
34888 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34891 if (oldconfig) { // old style..
34892 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34895 tree = config.tree;
34896 config.field = config.field || {};
34897 config.field.xtype = 'TextField';
34898 field = Roo.factory(config.field, Roo.form);
34900 config = config || {};
34905 * @event beforenodeedit
34906 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34907 * false from the handler of this event.
34908 * @param {Editor} this
34909 * @param {Roo.tree.Node} node
34911 "beforenodeedit" : true
34915 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34919 tree.on('beforeclick', this.beforeNodeClick, this);
34920 tree.getTreeEl().on('mousedown', this.hide, this);
34921 this.on('complete', this.updateNode, this);
34922 this.on('beforestartedit', this.fitToTree, this);
34923 this.on('startedit', this.bindScroll, this, {delay:10});
34924 this.on('specialkey', this.onSpecialKey, this);
34927 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34929 * @cfg {String} alignment
34930 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34936 * @cfg {Boolean} hideEl
34937 * True to hide the bound element while the editor is displayed (defaults to false)
34941 * @cfg {String} cls
34942 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34944 cls: "x-small-editor x-tree-editor",
34946 * @cfg {Boolean} shim
34947 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34953 * @cfg {Number} maxWidth
34954 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34955 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34956 * scroll and client offsets into account prior to each edit.
34963 fitToTree : function(ed, el){
34964 var td = this.tree.getTreeEl().dom, nd = el.dom;
34965 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34966 td.scrollLeft = nd.offsetLeft;
34970 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34971 this.setSize(w, '');
34973 return this.fireEvent('beforenodeedit', this, this.editNode);
34978 triggerEdit : function(node){
34979 this.completeEdit();
34980 this.editNode = node;
34981 this.startEdit(node.ui.textNode, node.text);
34985 bindScroll : function(){
34986 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
34990 beforeNodeClick : function(node, e){
34991 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
34992 this.lastClick = new Date();
34993 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
34995 this.triggerEdit(node);
35002 updateNode : function(ed, value){
35003 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35004 this.editNode.setText(value);
35008 onHide : function(){
35009 Roo.tree.TreeEditor.superclass.onHide.call(this);
35011 this.editNode.ui.focus();
35016 onSpecialKey : function(field, e){
35017 var k = e.getKey();
35021 }else if(k == e.ENTER && !e.hasModifier()){
35023 this.completeEdit();
35026 });//<Script type="text/javascript">
35029 * Ext JS Library 1.1.1
35030 * Copyright(c) 2006-2007, Ext JS, LLC.
35032 * Originally Released Under LGPL - original licence link has changed is not relivant.
35035 * <script type="text/javascript">
35039 * Not documented??? - probably should be...
35042 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35043 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35045 renderElements : function(n, a, targetNode, bulkRender){
35046 //consel.log("renderElements?");
35047 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35049 var t = n.getOwnerTree();
35050 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35052 var cols = t.columns;
35053 var bw = t.borderWidth;
35055 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35056 var cb = typeof a.checked == "boolean";
35057 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35058 var colcls = 'x-t-' + tid + '-c0';
35060 '<li class="x-tree-node">',
35063 '<div class="x-tree-node-el ', a.cls,'">',
35065 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35068 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35069 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35070 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35071 (a.icon ? ' x-tree-node-inline-icon' : ''),
35072 (a.iconCls ? ' '+a.iconCls : ''),
35073 '" unselectable="on" />',
35074 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35075 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35077 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35078 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35079 '<span unselectable="on" qtip="' + tx + '">',
35083 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35084 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35086 for(var i = 1, len = cols.length; i < len; i++){
35088 colcls = 'x-t-' + tid + '-c' +i;
35089 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35090 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35091 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35097 '<div class="x-clear"></div></div>',
35098 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35101 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35102 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35103 n.nextSibling.ui.getEl(), buf.join(""));
35105 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35107 var el = this.wrap.firstChild;
35109 this.elNode = el.firstChild;
35110 this.ranchor = el.childNodes[1];
35111 this.ctNode = this.wrap.childNodes[1];
35112 var cs = el.firstChild.childNodes;
35113 this.indentNode = cs[0];
35114 this.ecNode = cs[1];
35115 this.iconNode = cs[2];
35118 this.checkbox = cs[3];
35121 this.anchor = cs[index];
35123 this.textNode = cs[index].firstChild;
35125 //el.on("click", this.onClick, this);
35126 //el.on("dblclick", this.onDblClick, this);
35129 // console.log(this);
35131 initEvents : function(){
35132 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35135 var a = this.ranchor;
35137 var el = Roo.get(a);
35139 if(Roo.isOpera){ // opera render bug ignores the CSS
35140 el.setStyle("text-decoration", "none");
35143 el.on("click", this.onClick, this);
35144 el.on("dblclick", this.onDblClick, this);
35145 el.on("contextmenu", this.onContextMenu, this);
35149 /*onSelectedChange : function(state){
35152 this.addClass("x-tree-selected");
35155 this.removeClass("x-tree-selected");
35158 addClass : function(cls){
35160 Roo.fly(this.elRow).addClass(cls);
35166 removeClass : function(cls){
35168 Roo.fly(this.elRow).removeClass(cls);
35174 });//<Script type="text/javascript">
35178 * Ext JS Library 1.1.1
35179 * Copyright(c) 2006-2007, Ext JS, LLC.
35181 * Originally Released Under LGPL - original licence link has changed is not relivant.
35184 * <script type="text/javascript">
35189 * @class Roo.tree.ColumnTree
35190 * @extends Roo.data.TreePanel
35191 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35192 * @cfg {int} borderWidth compined right/left border allowance
35194 * @param {String/HTMLElement/Element} el The container element
35195 * @param {Object} config
35197 Roo.tree.ColumnTree = function(el, config)
35199 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35203 * Fire this event on a container when it resizes
35204 * @param {int} w Width
35205 * @param {int} h Height
35209 this.on('resize', this.onResize, this);
35212 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35216 borderWidth: Roo.isBorderBox ? 0 : 2,
35219 render : function(){
35220 // add the header.....
35222 Roo.tree.ColumnTree.superclass.render.apply(this);
35224 this.el.addClass('x-column-tree');
35226 this.headers = this.el.createChild(
35227 {cls:'x-tree-headers'},this.innerCt.dom);
35229 var cols = this.columns, c;
35230 var totalWidth = 0;
35232 var len = cols.length;
35233 for(var i = 0; i < len; i++){
35235 totalWidth += c.width;
35236 this.headEls.push(this.headers.createChild({
35237 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35239 cls:'x-tree-hd-text',
35242 style:'width:'+(c.width-this.borderWidth)+'px;'
35245 this.headers.createChild({cls:'x-clear'});
35246 // prevent floats from wrapping when clipped
35247 this.headers.setWidth(totalWidth);
35248 //this.innerCt.setWidth(totalWidth);
35249 this.innerCt.setStyle({ overflow: 'auto' });
35250 this.onResize(this.width, this.height);
35254 onResize : function(w,h)
35259 this.innerCt.setWidth(this.width);
35260 this.innerCt.setHeight(this.height-20);
35263 var cols = this.columns, c;
35264 var totalWidth = 0;
35266 var len = cols.length;
35267 for(var i = 0; i < len; i++){
35269 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35270 // it's the expander..
35271 expEl = this.headEls[i];
35274 totalWidth += c.width;
35278 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35280 this.headers.setWidth(w-20);
35289 * Ext JS Library 1.1.1
35290 * Copyright(c) 2006-2007, Ext JS, LLC.
35292 * Originally Released Under LGPL - original licence link has changed is not relivant.
35295 * <script type="text/javascript">
35299 * @class Roo.menu.Menu
35300 * @extends Roo.util.Observable
35301 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35302 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35304 * Creates a new Menu
35305 * @param {Object} config Configuration options
35307 Roo.menu.Menu = function(config){
35308 Roo.apply(this, config);
35309 this.id = this.id || Roo.id();
35312 * @event beforeshow
35313 * Fires before this menu is displayed
35314 * @param {Roo.menu.Menu} this
35318 * @event beforehide
35319 * Fires before this menu is hidden
35320 * @param {Roo.menu.Menu} this
35325 * Fires after this menu is displayed
35326 * @param {Roo.menu.Menu} this
35331 * Fires after this menu is hidden
35332 * @param {Roo.menu.Menu} this
35337 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35338 * @param {Roo.menu.Menu} this
35339 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35340 * @param {Roo.EventObject} e
35345 * Fires when the mouse is hovering over this menu
35346 * @param {Roo.menu.Menu} this
35347 * @param {Roo.EventObject} e
35348 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35353 * Fires when the mouse exits this menu
35354 * @param {Roo.menu.Menu} this
35355 * @param {Roo.EventObject} e
35356 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35361 * Fires when a menu item contained in this menu is clicked
35362 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35363 * @param {Roo.EventObject} e
35367 if (this.registerMenu) {
35368 Roo.menu.MenuMgr.register(this);
35371 var mis = this.items;
35372 this.items = new Roo.util.MixedCollection();
35374 this.add.apply(this, mis);
35378 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35380 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35384 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35385 * for bottom-right shadow (defaults to "sides")
35389 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35390 * this menu (defaults to "tl-tr?")
35392 subMenuAlign : "tl-tr?",
35394 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35395 * relative to its element of origin (defaults to "tl-bl?")
35397 defaultAlign : "tl-bl?",
35399 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35401 allowOtherMenus : false,
35403 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35405 registerMenu : true,
35410 render : function(){
35414 var el = this.el = new Roo.Layer({
35416 shadow:this.shadow,
35418 parentEl: this.parentEl || document.body,
35422 this.keyNav = new Roo.menu.MenuNav(this);
35425 el.addClass("x-menu-plain");
35428 el.addClass(this.cls);
35430 // generic focus element
35431 this.focusEl = el.createChild({
35432 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35434 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35435 ul.on("click", this.onClick, this);
35436 ul.on("mouseover", this.onMouseOver, this);
35437 ul.on("mouseout", this.onMouseOut, this);
35438 this.items.each(function(item){
35443 var li = document.createElement("li");
35444 li.className = "x-menu-list-item";
35445 ul.dom.appendChild(li);
35446 item.render(li, this);
35453 autoWidth : function(){
35454 var el = this.el, ul = this.ul;
35458 var w = this.width;
35461 }else if(Roo.isIE){
35462 el.setWidth(this.minWidth);
35463 var t = el.dom.offsetWidth; // force recalc
35464 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35469 delayAutoWidth : function(){
35472 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35474 this.awTask.delay(20);
35479 findTargetItem : function(e){
35480 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35481 if(t && t.menuItemId){
35482 return this.items.get(t.menuItemId);
35487 onClick : function(e){
35489 if(t = this.findTargetItem(e)){
35491 this.fireEvent("click", this, t, e);
35496 setActiveItem : function(item, autoExpand){
35497 if(item != this.activeItem){
35498 if(this.activeItem){
35499 this.activeItem.deactivate();
35501 this.activeItem = item;
35502 item.activate(autoExpand);
35503 }else if(autoExpand){
35509 tryActivate : function(start, step){
35510 var items = this.items;
35511 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35512 var item = items.get(i);
35513 if(!item.disabled && item.canActivate){
35514 this.setActiveItem(item, false);
35522 onMouseOver : function(e){
35524 if(t = this.findTargetItem(e)){
35525 if(t.canActivate && !t.disabled){
35526 this.setActiveItem(t, true);
35529 this.fireEvent("mouseover", this, e, t);
35533 onMouseOut : function(e){
35535 if(t = this.findTargetItem(e)){
35536 if(t == this.activeItem && t.shouldDeactivate(e)){
35537 this.activeItem.deactivate();
35538 delete this.activeItem;
35541 this.fireEvent("mouseout", this, e, t);
35545 * Read-only. Returns true if the menu is currently displayed, else false.
35548 isVisible : function(){
35549 return this.el && !this.hidden;
35553 * Displays this menu relative to another element
35554 * @param {String/HTMLElement/Roo.Element} element The element to align to
35555 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35556 * the element (defaults to this.defaultAlign)
35557 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35559 show : function(el, pos, parentMenu){
35560 this.parentMenu = parentMenu;
35564 this.fireEvent("beforeshow", this);
35565 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35569 * Displays this menu at a specific xy position
35570 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35571 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35573 showAt : function(xy, parentMenu, /* private: */_e){
35574 this.parentMenu = parentMenu;
35579 this.fireEvent("beforeshow", this);
35580 xy = this.el.adjustForConstraints(xy);
35584 this.hidden = false;
35586 this.fireEvent("show", this);
35589 focus : function(){
35591 this.doFocus.defer(50, this);
35595 doFocus : function(){
35597 this.focusEl.focus();
35602 * Hides this menu and optionally all parent menus
35603 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35605 hide : function(deep){
35606 if(this.el && this.isVisible()){
35607 this.fireEvent("beforehide", this);
35608 if(this.activeItem){
35609 this.activeItem.deactivate();
35610 this.activeItem = null;
35613 this.hidden = true;
35614 this.fireEvent("hide", this);
35616 if(deep === true && this.parentMenu){
35617 this.parentMenu.hide(true);
35622 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35623 * Any of the following are valid:
35625 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35626 * <li>An HTMLElement object which will be converted to a menu item</li>
35627 * <li>A menu item config object that will be created as a new menu item</li>
35628 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35629 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35634 var menu = new Roo.menu.Menu();
35636 // Create a menu item to add by reference
35637 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35639 // Add a bunch of items at once using different methods.
35640 // Only the last item added will be returned.
35641 var item = menu.add(
35642 menuItem, // add existing item by ref
35643 'Dynamic Item', // new TextItem
35644 '-', // new separator
35645 { text: 'Config Item' } // new item by config
35648 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35649 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35652 var a = arguments, l = a.length, item;
35653 for(var i = 0; i < l; i++){
35655 if ((typeof(el) == "object") && el.xtype && el.xns) {
35656 el = Roo.factory(el, Roo.menu);
35659 if(el.render){ // some kind of Item
35660 item = this.addItem(el);
35661 }else if(typeof el == "string"){ // string
35662 if(el == "separator" || el == "-"){
35663 item = this.addSeparator();
35665 item = this.addText(el);
35667 }else if(el.tagName || el.el){ // element
35668 item = this.addElement(el);
35669 }else if(typeof el == "object"){ // must be menu item config?
35670 item = this.addMenuItem(el);
35677 * Returns this menu's underlying {@link Roo.Element} object
35678 * @return {Roo.Element} The element
35680 getEl : function(){
35688 * Adds a separator bar to the menu
35689 * @return {Roo.menu.Item} The menu item that was added
35691 addSeparator : function(){
35692 return this.addItem(new Roo.menu.Separator());
35696 * Adds an {@link Roo.Element} object to the menu
35697 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35698 * @return {Roo.menu.Item} The menu item that was added
35700 addElement : function(el){
35701 return this.addItem(new Roo.menu.BaseItem(el));
35705 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35706 * @param {Roo.menu.Item} item The menu item to add
35707 * @return {Roo.menu.Item} The menu item that was added
35709 addItem : function(item){
35710 this.items.add(item);
35712 var li = document.createElement("li");
35713 li.className = "x-menu-list-item";
35714 this.ul.dom.appendChild(li);
35715 item.render(li, this);
35716 this.delayAutoWidth();
35722 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35723 * @param {Object} config A MenuItem config object
35724 * @return {Roo.menu.Item} The menu item that was added
35726 addMenuItem : function(config){
35727 if(!(config instanceof Roo.menu.Item)){
35728 if(typeof config.checked == "boolean"){ // must be check menu item config?
35729 config = new Roo.menu.CheckItem(config);
35731 config = new Roo.menu.Item(config);
35734 return this.addItem(config);
35738 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35739 * @param {String} text The text to display in the menu item
35740 * @return {Roo.menu.Item} The menu item that was added
35742 addText : function(text){
35743 return this.addItem(new Roo.menu.TextItem({ text : text }));
35747 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35748 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35749 * @param {Roo.menu.Item} item The menu item to add
35750 * @return {Roo.menu.Item} The menu item that was added
35752 insert : function(index, item){
35753 this.items.insert(index, item);
35755 var li = document.createElement("li");
35756 li.className = "x-menu-list-item";
35757 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35758 item.render(li, this);
35759 this.delayAutoWidth();
35765 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35766 * @param {Roo.menu.Item} item The menu item to remove
35768 remove : function(item){
35769 this.items.removeKey(item.id);
35774 * Removes and destroys all items in the menu
35776 removeAll : function(){
35778 while(f = this.items.first()){
35784 // MenuNav is a private utility class used internally by the Menu
35785 Roo.menu.MenuNav = function(menu){
35786 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35787 this.scope = this.menu = menu;
35790 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35791 doRelay : function(e, h){
35792 var k = e.getKey();
35793 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35794 this.menu.tryActivate(0, 1);
35797 return h.call(this.scope || this, e, this.menu);
35800 up : function(e, m){
35801 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35802 m.tryActivate(m.items.length-1, -1);
35806 down : function(e, m){
35807 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35808 m.tryActivate(0, 1);
35812 right : function(e, m){
35814 m.activeItem.expandMenu(true);
35818 left : function(e, m){
35820 if(m.parentMenu && m.parentMenu.activeItem){
35821 m.parentMenu.activeItem.activate();
35825 enter : function(e, m){
35827 e.stopPropagation();
35828 m.activeItem.onClick(e);
35829 m.fireEvent("click", this, m.activeItem);
35835 * Ext JS Library 1.1.1
35836 * Copyright(c) 2006-2007, Ext JS, LLC.
35838 * Originally Released Under LGPL - original licence link has changed is not relivant.
35841 * <script type="text/javascript">
35845 * @class Roo.menu.MenuMgr
35846 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35849 Roo.menu.MenuMgr = function(){
35850 var menus, active, groups = {}, attached = false, lastShow = new Date();
35852 // private - called when first menu is created
35855 active = new Roo.util.MixedCollection();
35856 Roo.get(document).addKeyListener(27, function(){
35857 if(active.length > 0){
35864 function hideAll(){
35865 if(active && active.length > 0){
35866 var c = active.clone();
35867 c.each(function(m){
35874 function onHide(m){
35876 if(active.length < 1){
35877 Roo.get(document).un("mousedown", onMouseDown);
35883 function onShow(m){
35884 var last = active.last();
35885 lastShow = new Date();
35888 Roo.get(document).on("mousedown", onMouseDown);
35892 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35893 m.parentMenu.activeChild = m;
35894 }else if(last && last.isVisible()){
35895 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35900 function onBeforeHide(m){
35902 m.activeChild.hide();
35904 if(m.autoHideTimer){
35905 clearTimeout(m.autoHideTimer);
35906 delete m.autoHideTimer;
35911 function onBeforeShow(m){
35912 var pm = m.parentMenu;
35913 if(!pm && !m.allowOtherMenus){
35915 }else if(pm && pm.activeChild && active != m){
35916 pm.activeChild.hide();
35921 function onMouseDown(e){
35922 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35928 function onBeforeCheck(mi, state){
35930 var g = groups[mi.group];
35931 for(var i = 0, l = g.length; i < l; i++){
35933 g[i].setChecked(false);
35942 * Hides all menus that are currently visible
35944 hideAll : function(){
35949 register : function(menu){
35953 menus[menu.id] = menu;
35954 menu.on("beforehide", onBeforeHide);
35955 menu.on("hide", onHide);
35956 menu.on("beforeshow", onBeforeShow);
35957 menu.on("show", onShow);
35958 var g = menu.group;
35959 if(g && menu.events["checkchange"]){
35963 groups[g].push(menu);
35964 menu.on("checkchange", onCheck);
35969 * Returns a {@link Roo.menu.Menu} object
35970 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35971 * be used to generate and return a new Menu instance.
35973 get : function(menu){
35974 if(typeof menu == "string"){ // menu id
35975 return menus[menu];
35976 }else if(menu.events){ // menu instance
35978 }else if(typeof menu.length == 'number'){ // array of menu items?
35979 return new Roo.menu.Menu({items:menu});
35980 }else{ // otherwise, must be a config
35981 return new Roo.menu.Menu(menu);
35986 unregister : function(menu){
35987 delete menus[menu.id];
35988 menu.un("beforehide", onBeforeHide);
35989 menu.un("hide", onHide);
35990 menu.un("beforeshow", onBeforeShow);
35991 menu.un("show", onShow);
35992 var g = menu.group;
35993 if(g && menu.events["checkchange"]){
35994 groups[g].remove(menu);
35995 menu.un("checkchange", onCheck);
36000 registerCheckable : function(menuItem){
36001 var g = menuItem.group;
36006 groups[g].push(menuItem);
36007 menuItem.on("beforecheckchange", onBeforeCheck);
36012 unregisterCheckable : function(menuItem){
36013 var g = menuItem.group;
36015 groups[g].remove(menuItem);
36016 menuItem.un("beforecheckchange", onBeforeCheck);
36022 * Ext JS Library 1.1.1
36023 * Copyright(c) 2006-2007, Ext JS, LLC.
36025 * Originally Released Under LGPL - original licence link has changed is not relivant.
36028 * <script type="text/javascript">
36033 * @class Roo.menu.BaseItem
36034 * @extends Roo.Component
36035 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36036 * management and base configuration options shared by all menu components.
36038 * Creates a new BaseItem
36039 * @param {Object} config Configuration options
36041 Roo.menu.BaseItem = function(config){
36042 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36047 * Fires when this item is clicked
36048 * @param {Roo.menu.BaseItem} this
36049 * @param {Roo.EventObject} e
36054 * Fires when this item is activated
36055 * @param {Roo.menu.BaseItem} this
36059 * @event deactivate
36060 * Fires when this item is deactivated
36061 * @param {Roo.menu.BaseItem} this
36067 this.on("click", this.handler, this.scope, true);
36071 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36073 * @cfg {Function} handler
36074 * A function that will handle the click event of this menu item (defaults to undefined)
36077 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36079 canActivate : false,
36082 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36087 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36089 activeClass : "x-menu-item-active",
36091 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36093 hideOnClick : true,
36095 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36100 ctype: "Roo.menu.BaseItem",
36103 actionMode : "container",
36106 render : function(container, parentMenu){
36107 this.parentMenu = parentMenu;
36108 Roo.menu.BaseItem.superclass.render.call(this, container);
36109 this.container.menuItemId = this.id;
36113 onRender : function(container, position){
36114 this.el = Roo.get(this.el);
36115 container.dom.appendChild(this.el.dom);
36119 onClick : function(e){
36120 if(!this.disabled && this.fireEvent("click", this, e) !== false
36121 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36122 this.handleClick(e);
36129 activate : function(){
36133 var li = this.container;
36134 li.addClass(this.activeClass);
36135 this.region = li.getRegion().adjust(2, 2, -2, -2);
36136 this.fireEvent("activate", this);
36141 deactivate : function(){
36142 this.container.removeClass(this.activeClass);
36143 this.fireEvent("deactivate", this);
36147 shouldDeactivate : function(e){
36148 return !this.region || !this.region.contains(e.getPoint());
36152 handleClick : function(e){
36153 if(this.hideOnClick){
36154 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36159 expandMenu : function(autoActivate){
36164 hideMenu : function(){
36169 * Ext JS Library 1.1.1
36170 * Copyright(c) 2006-2007, Ext JS, LLC.
36172 * Originally Released Under LGPL - original licence link has changed is not relivant.
36175 * <script type="text/javascript">
36179 * @class Roo.menu.Adapter
36180 * @extends Roo.menu.BaseItem
36181 * 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.
36182 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36184 * Creates a new Adapter
36185 * @param {Object} config Configuration options
36187 Roo.menu.Adapter = function(component, config){
36188 Roo.menu.Adapter.superclass.constructor.call(this, config);
36189 this.component = component;
36191 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36193 canActivate : true,
36196 onRender : function(container, position){
36197 this.component.render(container);
36198 this.el = this.component.getEl();
36202 activate : function(){
36206 this.component.focus();
36207 this.fireEvent("activate", this);
36212 deactivate : function(){
36213 this.fireEvent("deactivate", this);
36217 disable : function(){
36218 this.component.disable();
36219 Roo.menu.Adapter.superclass.disable.call(this);
36223 enable : function(){
36224 this.component.enable();
36225 Roo.menu.Adapter.superclass.enable.call(this);
36229 * Ext JS Library 1.1.1
36230 * Copyright(c) 2006-2007, Ext JS, LLC.
36232 * Originally Released Under LGPL - original licence link has changed is not relivant.
36235 * <script type="text/javascript">
36239 * @class Roo.menu.TextItem
36240 * @extends Roo.menu.BaseItem
36241 * Adds a static text string to a menu, usually used as either a heading or group separator.
36242 * Note: old style constructor with text is still supported.
36245 * Creates a new TextItem
36246 * @param {Object} cfg Configuration
36248 Roo.menu.TextItem = function(cfg){
36249 if (typeof(cfg) == 'string') {
36252 Roo.apply(this,cfg);
36255 Roo.menu.TextItem.superclass.constructor.call(this);
36258 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36260 * @cfg {Boolean} text Text to show on item.
36265 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36267 hideOnClick : false,
36269 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36271 itemCls : "x-menu-text",
36274 onRender : function(){
36275 var s = document.createElement("span");
36276 s.className = this.itemCls;
36277 s.innerHTML = this.text;
36279 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36283 * Ext JS Library 1.1.1
36284 * Copyright(c) 2006-2007, Ext JS, LLC.
36286 * Originally Released Under LGPL - original licence link has changed is not relivant.
36289 * <script type="text/javascript">
36293 * @class Roo.menu.Separator
36294 * @extends Roo.menu.BaseItem
36295 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36296 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36298 * @param {Object} config Configuration options
36300 Roo.menu.Separator = function(config){
36301 Roo.menu.Separator.superclass.constructor.call(this, config);
36304 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36306 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36308 itemCls : "x-menu-sep",
36310 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36312 hideOnClick : false,
36315 onRender : function(li){
36316 var s = document.createElement("span");
36317 s.className = this.itemCls;
36318 s.innerHTML = " ";
36320 li.addClass("x-menu-sep-li");
36321 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36325 * Ext JS Library 1.1.1
36326 * Copyright(c) 2006-2007, Ext JS, LLC.
36328 * Originally Released Under LGPL - original licence link has changed is not relivant.
36331 * <script type="text/javascript">
36334 * @class Roo.menu.Item
36335 * @extends Roo.menu.BaseItem
36336 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36337 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36338 * activation and click handling.
36340 * Creates a new Item
36341 * @param {Object} config Configuration options
36343 Roo.menu.Item = function(config){
36344 Roo.menu.Item.superclass.constructor.call(this, config);
36346 this.menu = Roo.menu.MenuMgr.get(this.menu);
36349 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36352 * @cfg {String} text
36353 * The text to show on the menu item.
36357 * @cfg {String} HTML to render in menu
36358 * The text to show on the menu item (HTML version).
36362 * @cfg {String} icon
36363 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36367 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36369 itemCls : "x-menu-item",
36371 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36373 canActivate : true,
36375 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36378 // doc'd in BaseItem
36382 ctype: "Roo.menu.Item",
36385 onRender : function(container, position){
36386 var el = document.createElement("a");
36387 el.hideFocus = true;
36388 el.unselectable = "on";
36389 el.href = this.href || "#";
36390 if(this.hrefTarget){
36391 el.target = this.hrefTarget;
36393 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36395 var html = this.html.length ? this.html : String.format('{0}',this.text);
36397 el.innerHTML = String.format(
36398 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36399 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36401 Roo.menu.Item.superclass.onRender.call(this, container, position);
36405 * Sets the text to display in this menu item
36406 * @param {String} text The text to display
36407 * @param {Boolean} isHTML true to indicate text is pure html.
36409 setText : function(text, isHTML){
36417 var html = this.html.length ? this.html : String.format('{0}',this.text);
36419 this.el.update(String.format(
36420 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36421 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36422 this.parentMenu.autoWidth();
36427 handleClick : function(e){
36428 if(!this.href){ // if no link defined, stop the event automatically
36431 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36435 activate : function(autoExpand){
36436 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36446 shouldDeactivate : function(e){
36447 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36448 if(this.menu && this.menu.isVisible()){
36449 return !this.menu.getEl().getRegion().contains(e.getPoint());
36457 deactivate : function(){
36458 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36463 expandMenu : function(autoActivate){
36464 if(!this.disabled && this.menu){
36465 clearTimeout(this.hideTimer);
36466 delete this.hideTimer;
36467 if(!this.menu.isVisible() && !this.showTimer){
36468 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36469 }else if (this.menu.isVisible() && autoActivate){
36470 this.menu.tryActivate(0, 1);
36476 deferExpand : function(autoActivate){
36477 delete this.showTimer;
36478 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36480 this.menu.tryActivate(0, 1);
36485 hideMenu : function(){
36486 clearTimeout(this.showTimer);
36487 delete this.showTimer;
36488 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36489 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36494 deferHide : function(){
36495 delete this.hideTimer;
36500 * Ext JS Library 1.1.1
36501 * Copyright(c) 2006-2007, Ext JS, LLC.
36503 * Originally Released Under LGPL - original licence link has changed is not relivant.
36506 * <script type="text/javascript">
36510 * @class Roo.menu.CheckItem
36511 * @extends Roo.menu.Item
36512 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36514 * Creates a new CheckItem
36515 * @param {Object} config Configuration options
36517 Roo.menu.CheckItem = function(config){
36518 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36521 * @event beforecheckchange
36522 * Fires before the checked value is set, providing an opportunity to cancel if needed
36523 * @param {Roo.menu.CheckItem} this
36524 * @param {Boolean} checked The new checked value that will be set
36526 "beforecheckchange" : true,
36528 * @event checkchange
36529 * Fires after the checked value has been set
36530 * @param {Roo.menu.CheckItem} this
36531 * @param {Boolean} checked The checked value that was set
36533 "checkchange" : true
36535 if(this.checkHandler){
36536 this.on('checkchange', this.checkHandler, this.scope);
36539 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36541 * @cfg {String} group
36542 * All check items with the same group name will automatically be grouped into a single-select
36543 * radio button group (defaults to '')
36546 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36548 itemCls : "x-menu-item x-menu-check-item",
36550 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36552 groupClass : "x-menu-group-item",
36555 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36556 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36557 * initialized with checked = true will be rendered as checked.
36562 ctype: "Roo.menu.CheckItem",
36565 onRender : function(c){
36566 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36568 this.el.addClass(this.groupClass);
36570 Roo.menu.MenuMgr.registerCheckable(this);
36572 this.checked = false;
36573 this.setChecked(true, true);
36578 destroy : function(){
36580 Roo.menu.MenuMgr.unregisterCheckable(this);
36582 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36586 * Set the checked state of this item
36587 * @param {Boolean} checked The new checked value
36588 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36590 setChecked : function(state, suppressEvent){
36591 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36592 if(this.container){
36593 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36595 this.checked = state;
36596 if(suppressEvent !== true){
36597 this.fireEvent("checkchange", this, state);
36603 handleClick : function(e){
36604 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36605 this.setChecked(!this.checked);
36607 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36611 * Ext JS Library 1.1.1
36612 * Copyright(c) 2006-2007, Ext JS, LLC.
36614 * Originally Released Under LGPL - original licence link has changed is not relivant.
36617 * <script type="text/javascript">
36621 * @class Roo.menu.DateItem
36622 * @extends Roo.menu.Adapter
36623 * A menu item that wraps the {@link Roo.DatPicker} component.
36625 * Creates a new DateItem
36626 * @param {Object} config Configuration options
36628 Roo.menu.DateItem = function(config){
36629 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36630 /** The Roo.DatePicker object @type Roo.DatePicker */
36631 this.picker = this.component;
36632 this.addEvents({select: true});
36634 this.picker.on("render", function(picker){
36635 picker.getEl().swallowEvent("click");
36636 picker.container.addClass("x-menu-date-item");
36639 this.picker.on("select", this.onSelect, this);
36642 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36644 onSelect : function(picker, date){
36645 this.fireEvent("select", this, date, picker);
36646 Roo.menu.DateItem.superclass.handleClick.call(this);
36650 * Ext JS Library 1.1.1
36651 * Copyright(c) 2006-2007, Ext JS, LLC.
36653 * Originally Released Under LGPL - original licence link has changed is not relivant.
36656 * <script type="text/javascript">
36660 * @class Roo.menu.ColorItem
36661 * @extends Roo.menu.Adapter
36662 * A menu item that wraps the {@link Roo.ColorPalette} component.
36664 * Creates a new ColorItem
36665 * @param {Object} config Configuration options
36667 Roo.menu.ColorItem = function(config){
36668 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36669 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36670 this.palette = this.component;
36671 this.relayEvents(this.palette, ["select"]);
36672 if(this.selectHandler){
36673 this.on('select', this.selectHandler, this.scope);
36676 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36678 * Ext JS Library 1.1.1
36679 * Copyright(c) 2006-2007, Ext JS, LLC.
36681 * Originally Released Under LGPL - original licence link has changed is not relivant.
36684 * <script type="text/javascript">
36689 * @class Roo.menu.DateMenu
36690 * @extends Roo.menu.Menu
36691 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36693 * Creates a new DateMenu
36694 * @param {Object} config Configuration options
36696 Roo.menu.DateMenu = function(config){
36697 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36699 var di = new Roo.menu.DateItem(config);
36702 * The {@link Roo.DatePicker} instance for this DateMenu
36705 this.picker = di.picker;
36708 * @param {DatePicker} picker
36709 * @param {Date} date
36711 this.relayEvents(di, ["select"]);
36712 this.on('beforeshow', function(){
36714 this.picker.hideMonthPicker(false);
36718 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36722 * Ext JS Library 1.1.1
36723 * Copyright(c) 2006-2007, Ext JS, LLC.
36725 * Originally Released Under LGPL - original licence link has changed is not relivant.
36728 * <script type="text/javascript">
36733 * @class Roo.menu.ColorMenu
36734 * @extends Roo.menu.Menu
36735 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36737 * Creates a new ColorMenu
36738 * @param {Object} config Configuration options
36740 Roo.menu.ColorMenu = function(config){
36741 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36743 var ci = new Roo.menu.ColorItem(config);
36746 * The {@link Roo.ColorPalette} instance for this ColorMenu
36747 * @type ColorPalette
36749 this.palette = ci.palette;
36752 * @param {ColorPalette} palette
36753 * @param {String} color
36755 this.relayEvents(ci, ["select"]);
36757 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36759 * Ext JS Library 1.1.1
36760 * Copyright(c) 2006-2007, Ext JS, LLC.
36762 * Originally Released Under LGPL - original licence link has changed is not relivant.
36765 * <script type="text/javascript">
36769 * @class Roo.form.Field
36770 * @extends Roo.BoxComponent
36771 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36773 * Creates a new Field
36774 * @param {Object} config Configuration options
36776 Roo.form.Field = function(config){
36777 Roo.form.Field.superclass.constructor.call(this, config);
36780 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36782 * @cfg {String} fieldLabel Label to use when rendering a form.
36785 * @cfg {String} qtip Mouse over tip
36789 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36791 invalidClass : "x-form-invalid",
36793 * @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")
36795 invalidText : "The value in this field is invalid",
36797 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36799 focusClass : "x-form-focus",
36801 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36802 automatic validation (defaults to "keyup").
36804 validationEvent : "keyup",
36806 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36808 validateOnBlur : true,
36810 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36812 validationDelay : 250,
36814 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36815 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36817 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36819 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36821 fieldClass : "x-form-field",
36823 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36826 ----------- ----------------------------------------------------------------------
36827 qtip Display a quick tip when the user hovers over the field
36828 title Display a default browser title attribute popup
36829 under Add a block div beneath the field containing the error text
36830 side Add an error icon to the right of the field with a popup on hover
36831 [element id] Add the error text directly to the innerHTML of the specified element
36834 msgTarget : 'qtip',
36836 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36841 * @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.
36846 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36851 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36853 inputType : undefined,
36856 * @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).
36858 tabIndex : undefined,
36861 isFormField : true,
36866 * @property {Roo.Element} fieldEl
36867 * Element Containing the rendered Field (with label etc.)
36870 * @cfg {Mixed} value A value to initialize this field with.
36875 * @cfg {String} name The field's HTML name attribute.
36878 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36882 initComponent : function(){
36883 Roo.form.Field.superclass.initComponent.call(this);
36887 * Fires when this field receives input focus.
36888 * @param {Roo.form.Field} this
36893 * Fires when this field loses input focus.
36894 * @param {Roo.form.Field} this
36898 * @event specialkey
36899 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36900 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36901 * @param {Roo.form.Field} this
36902 * @param {Roo.EventObject} e The event object
36907 * Fires just before the field blurs if the field value has changed.
36908 * @param {Roo.form.Field} this
36909 * @param {Mixed} newValue The new value
36910 * @param {Mixed} oldValue The original value
36915 * Fires after the field has been marked as invalid.
36916 * @param {Roo.form.Field} this
36917 * @param {String} msg The validation message
36922 * Fires after the field has been validated with no errors.
36923 * @param {Roo.form.Field} this
36928 * Fires after the key up
36929 * @param {Roo.form.Field} this
36930 * @param {Roo.EventObject} e The event Object
36937 * Returns the name attribute of the field if available
36938 * @return {String} name The field name
36940 getName: function(){
36941 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36945 onRender : function(ct, position){
36946 Roo.form.Field.superclass.onRender.call(this, ct, position);
36948 var cfg = this.getAutoCreate();
36950 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
36952 if (!cfg.name.length) {
36955 if(this.inputType){
36956 cfg.type = this.inputType;
36958 this.el = ct.createChild(cfg, position);
36960 var type = this.el.dom.type;
36962 if(type == 'password'){
36965 this.el.addClass('x-form-'+type);
36968 this.el.dom.readOnly = true;
36970 if(this.tabIndex !== undefined){
36971 this.el.dom.setAttribute('tabIndex', this.tabIndex);
36974 this.el.addClass([this.fieldClass, this.cls]);
36979 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
36980 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
36981 * @return {Roo.form.Field} this
36983 applyTo : function(target){
36984 this.allowDomMove = false;
36985 this.el = Roo.get(target);
36986 this.render(this.el.dom.parentNode);
36991 initValue : function(){
36992 if(this.value !== undefined){
36993 this.setValue(this.value);
36994 }else if(this.el.dom.value.length > 0){
36995 this.setValue(this.el.dom.value);
37000 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37002 isDirty : function() {
37003 if(this.disabled) {
37006 return String(this.getValue()) !== String(this.originalValue);
37010 afterRender : function(){
37011 Roo.form.Field.superclass.afterRender.call(this);
37016 fireKey : function(e){
37017 //Roo.log('field ' + e.getKey());
37018 if(e.isNavKeyPress()){
37019 this.fireEvent("specialkey", this, e);
37024 * Resets the current field value to the originally loaded value and clears any validation messages
37026 reset : function(){
37027 this.setValue(this.originalValue);
37028 this.clearInvalid();
37032 initEvents : function(){
37033 // safari killled keypress - so keydown is now used..
37034 this.el.on("keydown" , this.fireKey, this);
37035 this.el.on("focus", this.onFocus, this);
37036 this.el.on("blur", this.onBlur, this);
37037 this.el.relayEvent('keyup', this);
37039 // reference to original value for reset
37040 this.originalValue = this.getValue();
37044 onFocus : function(){
37045 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37046 this.el.addClass(this.focusClass);
37048 if(!this.hasFocus){
37049 this.hasFocus = true;
37050 this.startValue = this.getValue();
37051 this.fireEvent("focus", this);
37055 beforeBlur : Roo.emptyFn,
37058 onBlur : function(){
37060 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37061 this.el.removeClass(this.focusClass);
37063 this.hasFocus = false;
37064 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37067 var v = this.getValue();
37068 if(String(v) !== String(this.startValue)){
37069 this.fireEvent('change', this, v, this.startValue);
37071 this.fireEvent("blur", this);
37075 * Returns whether or not the field value is currently valid
37076 * @param {Boolean} preventMark True to disable marking the field invalid
37077 * @return {Boolean} True if the value is valid, else false
37079 isValid : function(preventMark){
37083 var restore = this.preventMark;
37084 this.preventMark = preventMark === true;
37085 var v = this.validateValue(this.processValue(this.getRawValue()));
37086 this.preventMark = restore;
37091 * Validates the field value
37092 * @return {Boolean} True if the value is valid, else false
37094 validate : function(){
37095 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37096 this.clearInvalid();
37102 processValue : function(value){
37107 // Subclasses should provide the validation implementation by overriding this
37108 validateValue : function(value){
37113 * Mark this field as invalid
37114 * @param {String} msg The validation message
37116 markInvalid : function(msg){
37117 if(!this.rendered || this.preventMark){ // not rendered
37120 this.el.addClass(this.invalidClass);
37121 msg = msg || this.invalidText;
37122 switch(this.msgTarget){
37124 this.el.dom.qtip = msg;
37125 this.el.dom.qclass = 'x-form-invalid-tip';
37126 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37127 Roo.QuickTips.enable();
37131 this.el.dom.title = msg;
37135 var elp = this.el.findParent('.x-form-element', 5, true);
37136 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37137 this.errorEl.setWidth(elp.getWidth(true)-20);
37139 this.errorEl.update(msg);
37140 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37143 if(!this.errorIcon){
37144 var elp = this.el.findParent('.x-form-element', 5, true);
37145 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37147 this.alignErrorIcon();
37148 this.errorIcon.dom.qtip = msg;
37149 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37150 this.errorIcon.show();
37151 this.on('resize', this.alignErrorIcon, this);
37154 var t = Roo.getDom(this.msgTarget);
37156 t.style.display = this.msgDisplay;
37159 this.fireEvent('invalid', this, msg);
37163 alignErrorIcon : function(){
37164 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37168 * Clear any invalid styles/messages for this field
37170 clearInvalid : function(){
37171 if(!this.rendered || this.preventMark){ // not rendered
37174 this.el.removeClass(this.invalidClass);
37175 switch(this.msgTarget){
37177 this.el.dom.qtip = '';
37180 this.el.dom.title = '';
37184 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37188 if(this.errorIcon){
37189 this.errorIcon.dom.qtip = '';
37190 this.errorIcon.hide();
37191 this.un('resize', this.alignErrorIcon, this);
37195 var t = Roo.getDom(this.msgTarget);
37197 t.style.display = 'none';
37200 this.fireEvent('valid', this);
37204 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37205 * @return {Mixed} value The field value
37207 getRawValue : function(){
37208 var v = this.el.getValue();
37214 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37215 * @return {Mixed} value The field value
37217 getValue : function(){
37218 var v = this.el.getValue();
37224 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37225 * @param {Mixed} value The value to set
37227 setRawValue : function(v){
37228 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37232 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37233 * @param {Mixed} value The value to set
37235 setValue : function(v){
37238 this.el.dom.value = (v === null || v === undefined ? '' : v);
37243 adjustSize : function(w, h){
37244 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37245 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37249 adjustWidth : function(tag, w){
37250 tag = tag.toLowerCase();
37251 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37252 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37253 if(tag == 'input'){
37256 if(tag == 'textarea'){
37259 }else if(Roo.isOpera){
37260 if(tag == 'input'){
37263 if(tag == 'textarea'){
37273 // anything other than normal should be considered experimental
37274 Roo.form.Field.msgFx = {
37276 show: function(msgEl, f){
37277 msgEl.setDisplayed('block');
37280 hide : function(msgEl, f){
37281 msgEl.setDisplayed(false).update('');
37286 show: function(msgEl, f){
37287 msgEl.slideIn('t', {stopFx:true});
37290 hide : function(msgEl, f){
37291 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37296 show: function(msgEl, f){
37297 msgEl.fixDisplay();
37298 msgEl.alignTo(f.el, 'tl-tr');
37299 msgEl.slideIn('l', {stopFx:true});
37302 hide : function(msgEl, f){
37303 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37308 * Ext JS Library 1.1.1
37309 * Copyright(c) 2006-2007, Ext JS, LLC.
37311 * Originally Released Under LGPL - original licence link has changed is not relivant.
37314 * <script type="text/javascript">
37319 * @class Roo.form.TextField
37320 * @extends Roo.form.Field
37321 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37322 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37324 * Creates a new TextField
37325 * @param {Object} config Configuration options
37327 Roo.form.TextField = function(config){
37328 Roo.form.TextField.superclass.constructor.call(this, config);
37332 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37333 * according to the default logic, but this event provides a hook for the developer to apply additional
37334 * logic at runtime to resize the field if needed.
37335 * @param {Roo.form.Field} this This text field
37336 * @param {Number} width The new field width
37342 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37344 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37348 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37352 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37356 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37360 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37364 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37366 disableKeyFilter : false,
37368 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37372 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37376 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37378 maxLength : Number.MAX_VALUE,
37380 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37382 minLengthText : "The minimum length for this field is {0}",
37384 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37386 maxLengthText : "The maximum length for this field is {0}",
37388 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37390 selectOnFocus : false,
37392 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37394 blankText : "This field is required",
37396 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37397 * If available, this function will be called only after the basic validators all return true, and will be passed the
37398 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37402 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37403 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37404 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37408 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37412 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37418 initEvents : function()
37420 if (this.emptyText) {
37421 this.el.attr('placeholder', this.emptyText);
37424 Roo.form.TextField.superclass.initEvents.call(this);
37425 if(this.validationEvent == 'keyup'){
37426 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37427 this.el.on('keyup', this.filterValidation, this);
37429 else if(this.validationEvent !== false){
37430 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37433 if(this.selectOnFocus){
37434 this.on("focus", this.preFocus, this);
37437 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37438 this.el.on("keypress", this.filterKeys, this);
37441 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37442 this.el.on("click", this.autoSize, this);
37444 if(this.el.is('input[type=password]') && Roo.isSafari){
37445 this.el.on('keydown', this.SafariOnKeyDown, this);
37449 processValue : function(value){
37450 if(this.stripCharsRe){
37451 var newValue = value.replace(this.stripCharsRe, '');
37452 if(newValue !== value){
37453 this.setRawValue(newValue);
37460 filterValidation : function(e){
37461 if(!e.isNavKeyPress()){
37462 this.validationTask.delay(this.validationDelay);
37467 onKeyUp : function(e){
37468 if(!e.isNavKeyPress()){
37474 * Resets the current field value to the originally-loaded value and clears any validation messages.
37477 reset : function(){
37478 Roo.form.TextField.superclass.reset.call(this);
37484 preFocus : function(){
37486 if(this.selectOnFocus){
37487 this.el.dom.select();
37493 filterKeys : function(e){
37494 var k = e.getKey();
37495 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37498 var c = e.getCharCode(), cc = String.fromCharCode(c);
37499 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37502 if(!this.maskRe.test(cc)){
37507 setValue : function(v){
37509 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37515 * Validates a value according to the field's validation rules and marks the field as invalid
37516 * if the validation fails
37517 * @param {Mixed} value The value to validate
37518 * @return {Boolean} True if the value is valid, else false
37520 validateValue : function(value){
37521 if(value.length < 1) { // if it's blank
37522 if(this.allowBlank){
37523 this.clearInvalid();
37526 this.markInvalid(this.blankText);
37530 if(value.length < this.minLength){
37531 this.markInvalid(String.format(this.minLengthText, this.minLength));
37534 if(value.length > this.maxLength){
37535 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37539 var vt = Roo.form.VTypes;
37540 if(!vt[this.vtype](value, this)){
37541 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37545 if(typeof this.validator == "function"){
37546 var msg = this.validator(value);
37548 this.markInvalid(msg);
37552 if(this.regex && !this.regex.test(value)){
37553 this.markInvalid(this.regexText);
37560 * Selects text in this field
37561 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37562 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37564 selectText : function(start, end){
37565 var v = this.getRawValue();
37567 start = start === undefined ? 0 : start;
37568 end = end === undefined ? v.length : end;
37569 var d = this.el.dom;
37570 if(d.setSelectionRange){
37571 d.setSelectionRange(start, end);
37572 }else if(d.createTextRange){
37573 var range = d.createTextRange();
37574 range.moveStart("character", start);
37575 range.moveEnd("character", v.length-end);
37582 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37583 * This only takes effect if grow = true, and fires the autosize event.
37585 autoSize : function(){
37586 if(!this.grow || !this.rendered){
37590 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37593 var v = el.dom.value;
37594 var d = document.createElement('div');
37595 d.appendChild(document.createTextNode(v));
37599 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37600 this.el.setWidth(w);
37601 this.fireEvent("autosize", this, w);
37605 SafariOnKeyDown : function(event)
37607 // this is a workaround for a password hang bug on chrome/ webkit.
37609 var isSelectAll = false;
37611 if(this.el.dom.selectionEnd > 0){
37612 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37614 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37615 event.preventDefault();
37620 if(isSelectAll){ // backspace and delete key
37622 event.preventDefault();
37623 // this is very hacky as keydown always get's upper case.
37625 var cc = String.fromCharCode(event.getCharCode());
37626 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37634 * Ext JS Library 1.1.1
37635 * Copyright(c) 2006-2007, Ext JS, LLC.
37637 * Originally Released Under LGPL - original licence link has changed is not relivant.
37640 * <script type="text/javascript">
37644 * @class Roo.form.Hidden
37645 * @extends Roo.form.TextField
37646 * Simple Hidden element used on forms
37648 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37651 * Creates a new Hidden form element.
37652 * @param {Object} config Configuration options
37657 // easy hidden field...
37658 Roo.form.Hidden = function(config){
37659 Roo.form.Hidden.superclass.constructor.call(this, config);
37662 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37664 inputType: 'hidden',
37667 labelSeparator: '',
37669 itemCls : 'x-form-item-display-none'
37677 * Ext JS Library 1.1.1
37678 * Copyright(c) 2006-2007, Ext JS, LLC.
37680 * Originally Released Under LGPL - original licence link has changed is not relivant.
37683 * <script type="text/javascript">
37687 * @class Roo.form.TriggerField
37688 * @extends Roo.form.TextField
37689 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37690 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37691 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37692 * for which you can provide a custom implementation. For example:
37694 var trigger = new Roo.form.TriggerField();
37695 trigger.onTriggerClick = myTriggerFn;
37696 trigger.applyTo('my-field');
37699 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37700 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37701 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37702 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37704 * Create a new TriggerField.
37705 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37706 * to the base TextField)
37708 Roo.form.TriggerField = function(config){
37709 this.mimicing = false;
37710 Roo.form.TriggerField.superclass.constructor.call(this, config);
37713 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37715 * @cfg {String} triggerClass A CSS class to apply to the trigger
37718 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37719 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37721 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37723 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37727 /** @cfg {Boolean} grow @hide */
37728 /** @cfg {Number} growMin @hide */
37729 /** @cfg {Number} growMax @hide */
37735 autoSize: Roo.emptyFn,
37739 deferHeight : true,
37742 actionMode : 'wrap',
37744 onResize : function(w, h){
37745 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37746 if(typeof w == 'number'){
37747 var x = w - this.trigger.getWidth();
37748 this.el.setWidth(this.adjustWidth('input', x));
37749 this.trigger.setStyle('left', x+'px');
37754 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37757 getResizeEl : function(){
37762 getPositionEl : function(){
37767 alignErrorIcon : function(){
37768 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37772 onRender : function(ct, position){
37773 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37774 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37775 this.trigger = this.wrap.createChild(this.triggerConfig ||
37776 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37777 if(this.hideTrigger){
37778 this.trigger.setDisplayed(false);
37780 this.initTrigger();
37782 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37787 initTrigger : function(){
37788 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37789 this.trigger.addClassOnOver('x-form-trigger-over');
37790 this.trigger.addClassOnClick('x-form-trigger-click');
37794 onDestroy : function(){
37796 this.trigger.removeAllListeners();
37797 this.trigger.remove();
37800 this.wrap.remove();
37802 Roo.form.TriggerField.superclass.onDestroy.call(this);
37806 onFocus : function(){
37807 Roo.form.TriggerField.superclass.onFocus.call(this);
37808 if(!this.mimicing){
37809 this.wrap.addClass('x-trigger-wrap-focus');
37810 this.mimicing = true;
37811 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37812 if(this.monitorTab){
37813 this.el.on("keydown", this.checkTab, this);
37819 checkTab : function(e){
37820 if(e.getKey() == e.TAB){
37821 this.triggerBlur();
37826 onBlur : function(){
37831 mimicBlur : function(e, t){
37832 if(!this.wrap.contains(t) && this.validateBlur()){
37833 this.triggerBlur();
37838 triggerBlur : function(){
37839 this.mimicing = false;
37840 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37841 if(this.monitorTab){
37842 this.el.un("keydown", this.checkTab, this);
37844 this.wrap.removeClass('x-trigger-wrap-focus');
37845 Roo.form.TriggerField.superclass.onBlur.call(this);
37849 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37850 validateBlur : function(e, t){
37855 onDisable : function(){
37856 Roo.form.TriggerField.superclass.onDisable.call(this);
37858 this.wrap.addClass('x-item-disabled');
37863 onEnable : function(){
37864 Roo.form.TriggerField.superclass.onEnable.call(this);
37866 this.wrap.removeClass('x-item-disabled');
37871 onShow : function(){
37872 var ae = this.getActionEl();
37875 ae.dom.style.display = '';
37876 ae.dom.style.visibility = 'visible';
37882 onHide : function(){
37883 var ae = this.getActionEl();
37884 ae.dom.style.display = 'none';
37888 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37889 * by an implementing function.
37891 * @param {EventObject} e
37893 onTriggerClick : Roo.emptyFn
37896 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37897 // to be extended by an implementing class. For an example of implementing this class, see the custom
37898 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37899 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37900 initComponent : function(){
37901 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37903 this.triggerConfig = {
37904 tag:'span', cls:'x-form-twin-triggers', cn:[
37905 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37906 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37910 getTrigger : function(index){
37911 return this.triggers[index];
37914 initTrigger : function(){
37915 var ts = this.trigger.select('.x-form-trigger', true);
37916 this.wrap.setStyle('overflow', 'hidden');
37917 var triggerField = this;
37918 ts.each(function(t, all, index){
37919 t.hide = function(){
37920 var w = triggerField.wrap.getWidth();
37921 this.dom.style.display = 'none';
37922 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37924 t.show = function(){
37925 var w = triggerField.wrap.getWidth();
37926 this.dom.style.display = '';
37927 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37929 var triggerIndex = 'Trigger'+(index+1);
37931 if(this['hide'+triggerIndex]){
37932 t.dom.style.display = 'none';
37934 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37935 t.addClassOnOver('x-form-trigger-over');
37936 t.addClassOnClick('x-form-trigger-click');
37938 this.triggers = ts.elements;
37941 onTrigger1Click : Roo.emptyFn,
37942 onTrigger2Click : Roo.emptyFn
37945 * Ext JS Library 1.1.1
37946 * Copyright(c) 2006-2007, Ext JS, LLC.
37948 * Originally Released Under LGPL - original licence link has changed is not relivant.
37951 * <script type="text/javascript">
37955 * @class Roo.form.TextArea
37956 * @extends Roo.form.TextField
37957 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37958 * support for auto-sizing.
37960 * Creates a new TextArea
37961 * @param {Object} config Configuration options
37963 Roo.form.TextArea = function(config){
37964 Roo.form.TextArea.superclass.constructor.call(this, config);
37965 // these are provided exchanges for backwards compat
37966 // minHeight/maxHeight were replaced by growMin/growMax to be
37967 // compatible with TextField growing config values
37968 if(this.minHeight !== undefined){
37969 this.growMin = this.minHeight;
37971 if(this.maxHeight !== undefined){
37972 this.growMax = this.maxHeight;
37976 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
37978 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
37982 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
37986 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
37987 * in the field (equivalent to setting overflow: hidden, defaults to false)
37989 preventScrollbars: false,
37991 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37992 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
37996 onRender : function(ct, position){
37998 this.defaultAutoCreate = {
38000 style:"width:300px;height:60px;",
38001 autocomplete: "off"
38004 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38006 this.textSizeEl = Roo.DomHelper.append(document.body, {
38007 tag: "pre", cls: "x-form-grow-sizer"
38009 if(this.preventScrollbars){
38010 this.el.setStyle("overflow", "hidden");
38012 this.el.setHeight(this.growMin);
38016 onDestroy : function(){
38017 if(this.textSizeEl){
38018 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38020 Roo.form.TextArea.superclass.onDestroy.call(this);
38024 onKeyUp : function(e){
38025 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38031 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38032 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38034 autoSize : function(){
38035 if(!this.grow || !this.textSizeEl){
38039 var v = el.dom.value;
38040 var ts = this.textSizeEl;
38043 ts.appendChild(document.createTextNode(v));
38046 Roo.fly(ts).setWidth(this.el.getWidth());
38048 v = "  ";
38051 v = v.replace(/\n/g, '<p> </p>');
38053 v += " \n ";
38056 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38057 if(h != this.lastHeight){
38058 this.lastHeight = h;
38059 this.el.setHeight(h);
38060 this.fireEvent("autosize", this, h);
38065 * Ext JS Library 1.1.1
38066 * Copyright(c) 2006-2007, Ext JS, LLC.
38068 * Originally Released Under LGPL - original licence link has changed is not relivant.
38071 * <script type="text/javascript">
38076 * @class Roo.form.NumberField
38077 * @extends Roo.form.TextField
38078 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38080 * Creates a new NumberField
38081 * @param {Object} config Configuration options
38083 Roo.form.NumberField = function(config){
38084 Roo.form.NumberField.superclass.constructor.call(this, config);
38087 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38089 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38091 fieldClass: "x-form-field x-form-num-field",
38093 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38095 allowDecimals : true,
38097 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38099 decimalSeparator : ".",
38101 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38103 decimalPrecision : 2,
38105 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38107 allowNegative : true,
38109 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38111 minValue : Number.NEGATIVE_INFINITY,
38113 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38115 maxValue : Number.MAX_VALUE,
38117 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38119 minText : "The minimum value for this field is {0}",
38121 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38123 maxText : "The maximum value for this field is {0}",
38125 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38126 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38128 nanText : "{0} is not a valid number",
38131 initEvents : function(){
38132 Roo.form.NumberField.superclass.initEvents.call(this);
38133 var allowed = "0123456789";
38134 if(this.allowDecimals){
38135 allowed += this.decimalSeparator;
38137 if(this.allowNegative){
38140 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38141 var keyPress = function(e){
38142 var k = e.getKey();
38143 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38146 var c = e.getCharCode();
38147 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38151 this.el.on("keypress", keyPress, this);
38155 validateValue : function(value){
38156 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38159 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38162 var num = this.parseValue(value);
38164 this.markInvalid(String.format(this.nanText, value));
38167 if(num < this.minValue){
38168 this.markInvalid(String.format(this.minText, this.minValue));
38171 if(num > this.maxValue){
38172 this.markInvalid(String.format(this.maxText, this.maxValue));
38178 getValue : function(){
38179 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38183 parseValue : function(value){
38184 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38185 return isNaN(value) ? '' : value;
38189 fixPrecision : function(value){
38190 var nan = isNaN(value);
38191 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38192 return nan ? '' : value;
38194 return parseFloat(value).toFixed(this.decimalPrecision);
38197 setValue : function(v){
38198 v = this.fixPrecision(v);
38199 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38203 decimalPrecisionFcn : function(v){
38204 return Math.floor(v);
38207 beforeBlur : function(){
38208 var v = this.parseValue(this.getRawValue());
38215 * Ext JS Library 1.1.1
38216 * Copyright(c) 2006-2007, Ext JS, LLC.
38218 * Originally Released Under LGPL - original licence link has changed is not relivant.
38221 * <script type="text/javascript">
38225 * @class Roo.form.DateField
38226 * @extends Roo.form.TriggerField
38227 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38229 * Create a new DateField
38230 * @param {Object} config
38232 Roo.form.DateField = function(config){
38233 Roo.form.DateField.superclass.constructor.call(this, config);
38239 * Fires when a date is selected
38240 * @param {Roo.form.DateField} combo This combo box
38241 * @param {Date} date The date selected
38248 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38249 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38250 this.ddMatch = null;
38251 if(this.disabledDates){
38252 var dd = this.disabledDates;
38254 for(var i = 0; i < dd.length; i++){
38256 if(i != dd.length-1) re += "|";
38258 this.ddMatch = new RegExp(re + ")");
38262 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38264 * @cfg {String} format
38265 * The default date format string which can be overriden for localization support. The format must be
38266 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38270 * @cfg {String} altFormats
38271 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38272 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38274 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38276 * @cfg {Array} disabledDays
38277 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38279 disabledDays : null,
38281 * @cfg {String} disabledDaysText
38282 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38284 disabledDaysText : "Disabled",
38286 * @cfg {Array} disabledDates
38287 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38288 * expression so they are very powerful. Some examples:
38290 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38291 * <li>["03/08", "09/16"] would disable those days for every year</li>
38292 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38293 * <li>["03/../2006"] would disable every day in March 2006</li>
38294 * <li>["^03"] would disable every day in every March</li>
38296 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38297 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38299 disabledDates : null,
38301 * @cfg {String} disabledDatesText
38302 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38304 disabledDatesText : "Disabled",
38306 * @cfg {Date/String} minValue
38307 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38308 * valid format (defaults to null).
38312 * @cfg {Date/String} maxValue
38313 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38314 * valid format (defaults to null).
38318 * @cfg {String} minText
38319 * The error text to display when the date in the cell is before minValue (defaults to
38320 * 'The date in this field must be after {minValue}').
38322 minText : "The date in this field must be equal to or after {0}",
38324 * @cfg {String} maxText
38325 * The error text to display when the date in the cell is after maxValue (defaults to
38326 * 'The date in this field must be before {maxValue}').
38328 maxText : "The date in this field must be equal to or before {0}",
38330 * @cfg {String} invalidText
38331 * The error text to display when the date in the field is invalid (defaults to
38332 * '{value} is not a valid date - it must be in the format {format}').
38334 invalidText : "{0} is not a valid date - it must be in the format {1}",
38336 * @cfg {String} triggerClass
38337 * An additional CSS class used to style the trigger button. The trigger will always get the
38338 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38339 * which displays a calendar icon).
38341 triggerClass : 'x-form-date-trigger',
38345 * @cfg {Boolean} useIso
38346 * if enabled, then the date field will use a hidden field to store the
38347 * real value as iso formated date. default (false)
38351 * @cfg {String/Object} autoCreate
38352 * A DomHelper element spec, or true for a default element spec (defaults to
38353 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38356 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38359 hiddenField: false,
38361 onRender : function(ct, position)
38363 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38365 //this.el.dom.removeAttribute('name');
38366 Roo.log("Changing name?");
38367 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38368 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38370 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38371 // prevent input submission
38372 this.hiddenName = this.name;
38379 validateValue : function(value)
38381 value = this.formatDate(value);
38382 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38383 Roo.log('super failed');
38386 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38389 var svalue = value;
38390 value = this.parseDate(value);
38392 Roo.log('parse date failed' + svalue);
38393 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38396 var time = value.getTime();
38397 if(this.minValue && time < this.minValue.getTime()){
38398 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38401 if(this.maxValue && time > this.maxValue.getTime()){
38402 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38405 if(this.disabledDays){
38406 var day = value.getDay();
38407 for(var i = 0; i < this.disabledDays.length; i++) {
38408 if(day === this.disabledDays[i]){
38409 this.markInvalid(this.disabledDaysText);
38414 var fvalue = this.formatDate(value);
38415 if(this.ddMatch && this.ddMatch.test(fvalue)){
38416 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38423 // Provides logic to override the default TriggerField.validateBlur which just returns true
38424 validateBlur : function(){
38425 return !this.menu || !this.menu.isVisible();
38428 getName: function()
38430 // returns hidden if it's set..
38431 if (!this.rendered) {return ''};
38432 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38437 * Returns the current date value of the date field.
38438 * @return {Date} The date value
38440 getValue : function(){
38442 return this.hiddenField ?
38443 this.hiddenField.value :
38444 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38448 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38449 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38450 * (the default format used is "m/d/y").
38453 //All of these calls set the same date value (May 4, 2006)
38455 //Pass a date object:
38456 var dt = new Date('5/4/06');
38457 dateField.setValue(dt);
38459 //Pass a date string (default format):
38460 dateField.setValue('5/4/06');
38462 //Pass a date string (custom format):
38463 dateField.format = 'Y-m-d';
38464 dateField.setValue('2006-5-4');
38466 * @param {String/Date} date The date or valid date string
38468 setValue : function(date){
38469 if (this.hiddenField) {
38470 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38472 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38473 // make sure the value field is always stored as a date..
38474 this.value = this.parseDate(date);
38480 parseDate : function(value){
38481 if(!value || value instanceof Date){
38484 var v = Date.parseDate(value, this.format);
38485 if (!v && this.useIso) {
38486 v = Date.parseDate(value, 'Y-m-d');
38488 if(!v && this.altFormats){
38489 if(!this.altFormatsArray){
38490 this.altFormatsArray = this.altFormats.split("|");
38492 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38493 v = Date.parseDate(value, this.altFormatsArray[i]);
38500 formatDate : function(date, fmt){
38501 return (!date || !(date instanceof Date)) ?
38502 date : date.dateFormat(fmt || this.format);
38507 select: function(m, d){
38510 this.fireEvent('select', this, d);
38512 show : function(){ // retain focus styling
38516 this.focus.defer(10, this);
38517 var ml = this.menuListeners;
38518 this.menu.un("select", ml.select, this);
38519 this.menu.un("show", ml.show, this);
38520 this.menu.un("hide", ml.hide, this);
38525 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38526 onTriggerClick : function(){
38530 if(this.menu == null){
38531 this.menu = new Roo.menu.DateMenu();
38533 Roo.apply(this.menu.picker, {
38534 showClear: this.allowBlank,
38535 minDate : this.minValue,
38536 maxDate : this.maxValue,
38537 disabledDatesRE : this.ddMatch,
38538 disabledDatesText : this.disabledDatesText,
38539 disabledDays : this.disabledDays,
38540 disabledDaysText : this.disabledDaysText,
38541 format : this.useIso ? 'Y-m-d' : this.format,
38542 minText : String.format(this.minText, this.formatDate(this.minValue)),
38543 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38545 this.menu.on(Roo.apply({}, this.menuListeners, {
38548 this.menu.picker.setValue(this.getValue() || new Date());
38549 this.menu.show(this.el, "tl-bl?");
38552 beforeBlur : function(){
38553 var v = this.parseDate(this.getRawValue());
38559 /** @cfg {Boolean} grow @hide */
38560 /** @cfg {Number} growMin @hide */
38561 /** @cfg {Number} growMax @hide */
38568 * Ext JS Library 1.1.1
38569 * Copyright(c) 2006-2007, Ext JS, LLC.
38571 * Originally Released Under LGPL - original licence link has changed is not relivant.
38574 * <script type="text/javascript">
38578 * @class Roo.form.MonthField
38579 * @extends Roo.form.TriggerField
38580 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38582 * Create a new MonthField
38583 * @param {Object} config
38585 Roo.form.MonthField = function(config){
38587 Roo.form.MonthField.superclass.constructor.call(this, config);
38593 * Fires when a date is selected
38594 * @param {Roo.form.MonthFieeld} combo This combo box
38595 * @param {Date} date The date selected
38602 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38603 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38604 this.ddMatch = null;
38605 if(this.disabledDates){
38606 var dd = this.disabledDates;
38608 for(var i = 0; i < dd.length; i++){
38610 if(i != dd.length-1) re += "|";
38612 this.ddMatch = new RegExp(re + ")");
38616 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38618 * @cfg {String} format
38619 * The default date format string which can be overriden for localization support. The format must be
38620 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38624 * @cfg {String} altFormats
38625 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38626 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38628 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38630 * @cfg {Array} disabledDays
38631 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38633 disabledDays : [0,1,2,3,4,5,6],
38635 * @cfg {String} disabledDaysText
38636 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38638 disabledDaysText : "Disabled",
38640 * @cfg {Array} disabledDates
38641 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38642 * expression so they are very powerful. Some examples:
38644 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38645 * <li>["03/08", "09/16"] would disable those days for every year</li>
38646 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38647 * <li>["03/../2006"] would disable every day in March 2006</li>
38648 * <li>["^03"] would disable every day in every March</li>
38650 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38651 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38653 disabledDates : null,
38655 * @cfg {String} disabledDatesText
38656 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38658 disabledDatesText : "Disabled",
38660 * @cfg {Date/String} minValue
38661 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38662 * valid format (defaults to null).
38666 * @cfg {Date/String} maxValue
38667 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38668 * valid format (defaults to null).
38672 * @cfg {String} minText
38673 * The error text to display when the date in the cell is before minValue (defaults to
38674 * 'The date in this field must be after {minValue}').
38676 minText : "The date in this field must be equal to or after {0}",
38678 * @cfg {String} maxTextf
38679 * The error text to display when the date in the cell is after maxValue (defaults to
38680 * 'The date in this field must be before {maxValue}').
38682 maxText : "The date in this field must be equal to or before {0}",
38684 * @cfg {String} invalidText
38685 * The error text to display when the date in the field is invalid (defaults to
38686 * '{value} is not a valid date - it must be in the format {format}').
38688 invalidText : "{0} is not a valid date - it must be in the format {1}",
38690 * @cfg {String} triggerClass
38691 * An additional CSS class used to style the trigger button. The trigger will always get the
38692 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38693 * which displays a calendar icon).
38695 triggerClass : 'x-form-date-trigger',
38699 * @cfg {Boolean} useIso
38700 * if enabled, then the date field will use a hidden field to store the
38701 * real value as iso formated date. default (true)
38705 * @cfg {String/Object} autoCreate
38706 * A DomHelper element spec, or true for a default element spec (defaults to
38707 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38710 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38713 hiddenField: false,
38715 hideMonthPicker : false,
38717 onRender : function(ct, position)
38719 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38721 this.el.dom.removeAttribute('name');
38722 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38724 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38725 // prevent input submission
38726 this.hiddenName = this.name;
38733 validateValue : function(value)
38735 value = this.formatDate(value);
38736 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38739 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38742 var svalue = value;
38743 value = this.parseDate(value);
38745 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38748 var time = value.getTime();
38749 if(this.minValue && time < this.minValue.getTime()){
38750 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38753 if(this.maxValue && time > this.maxValue.getTime()){
38754 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38757 /*if(this.disabledDays){
38758 var day = value.getDay();
38759 for(var i = 0; i < this.disabledDays.length; i++) {
38760 if(day === this.disabledDays[i]){
38761 this.markInvalid(this.disabledDaysText);
38767 var fvalue = this.formatDate(value);
38768 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38769 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38777 // Provides logic to override the default TriggerField.validateBlur which just returns true
38778 validateBlur : function(){
38779 return !this.menu || !this.menu.isVisible();
38783 * Returns the current date value of the date field.
38784 * @return {Date} The date value
38786 getValue : function(){
38790 return this.hiddenField ?
38791 this.hiddenField.value :
38792 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38796 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38797 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38798 * (the default format used is "m/d/y").
38801 //All of these calls set the same date value (May 4, 2006)
38803 //Pass a date object:
38804 var dt = new Date('5/4/06');
38805 monthField.setValue(dt);
38807 //Pass a date string (default format):
38808 monthField.setValue('5/4/06');
38810 //Pass a date string (custom format):
38811 monthField.format = 'Y-m-d';
38812 monthField.setValue('2006-5-4');
38814 * @param {String/Date} date The date or valid date string
38816 setValue : function(date){
38817 Roo.log('month setValue' + date);
38818 // can only be first of month..
38820 var val = this.parseDate(date);
38822 if (this.hiddenField) {
38823 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38825 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38826 this.value = this.parseDate(date);
38830 parseDate : function(value){
38831 if(!value || value instanceof Date){
38832 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38835 var v = Date.parseDate(value, this.format);
38836 if (!v && this.useIso) {
38837 v = Date.parseDate(value, 'Y-m-d');
38841 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38845 if(!v && this.altFormats){
38846 if(!this.altFormatsArray){
38847 this.altFormatsArray = this.altFormats.split("|");
38849 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38850 v = Date.parseDate(value, this.altFormatsArray[i]);
38857 formatDate : function(date, fmt){
38858 return (!date || !(date instanceof Date)) ?
38859 date : date.dateFormat(fmt || this.format);
38864 select: function(m, d){
38866 this.fireEvent('select', this, d);
38868 show : function(){ // retain focus styling
38872 this.focus.defer(10, this);
38873 var ml = this.menuListeners;
38874 this.menu.un("select", ml.select, this);
38875 this.menu.un("show", ml.show, this);
38876 this.menu.un("hide", ml.hide, this);
38880 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38881 onTriggerClick : function(){
38885 if(this.menu == null){
38886 this.menu = new Roo.menu.DateMenu();
38890 Roo.apply(this.menu.picker, {
38892 showClear: this.allowBlank,
38893 minDate : this.minValue,
38894 maxDate : this.maxValue,
38895 disabledDatesRE : this.ddMatch,
38896 disabledDatesText : this.disabledDatesText,
38898 format : this.useIso ? 'Y-m-d' : this.format,
38899 minText : String.format(this.minText, this.formatDate(this.minValue)),
38900 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38903 this.menu.on(Roo.apply({}, this.menuListeners, {
38911 // hide month picker get's called when we called by 'before hide';
38913 var ignorehide = true;
38914 p.hideMonthPicker = function(disableAnim){
38918 if(this.monthPicker){
38919 Roo.log("hideMonthPicker called");
38920 if(disableAnim === true){
38921 this.monthPicker.hide();
38923 this.monthPicker.slideOut('t', {duration:.2});
38924 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38925 p.fireEvent("select", this, this.value);
38931 Roo.log('picker set value');
38932 Roo.log(this.getValue());
38933 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
38934 m.show(this.el, 'tl-bl?');
38935 ignorehide = false;
38936 // this will trigger hideMonthPicker..
38939 // hidden the day picker
38940 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
38946 p.showMonthPicker.defer(100, p);
38952 beforeBlur : function(){
38953 var v = this.parseDate(this.getRawValue());
38959 /** @cfg {Boolean} grow @hide */
38960 /** @cfg {Number} growMin @hide */
38961 /** @cfg {Number} growMax @hide */
38968 * Ext JS Library 1.1.1
38969 * Copyright(c) 2006-2007, Ext JS, LLC.
38971 * Originally Released Under LGPL - original licence link has changed is not relivant.
38974 * <script type="text/javascript">
38979 * @class Roo.form.ComboBox
38980 * @extends Roo.form.TriggerField
38981 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
38983 * Create a new ComboBox.
38984 * @param {Object} config Configuration options
38986 Roo.form.ComboBox = function(config){
38987 Roo.form.ComboBox.superclass.constructor.call(this, config);
38991 * Fires when the dropdown list is expanded
38992 * @param {Roo.form.ComboBox} combo This combo box
38997 * Fires when the dropdown list is collapsed
38998 * @param {Roo.form.ComboBox} combo This combo box
39002 * @event beforeselect
39003 * Fires before a list item is selected. Return false to cancel the selection.
39004 * @param {Roo.form.ComboBox} combo This combo box
39005 * @param {Roo.data.Record} record The data record returned from the underlying store
39006 * @param {Number} index The index of the selected item in the dropdown list
39008 'beforeselect' : true,
39011 * Fires when a list item is selected
39012 * @param {Roo.form.ComboBox} combo This combo box
39013 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39014 * @param {Number} index The index of the selected item in the dropdown list
39018 * @event beforequery
39019 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39020 * The event object passed has these properties:
39021 * @param {Roo.form.ComboBox} combo This combo box
39022 * @param {String} query The query
39023 * @param {Boolean} forceAll true to force "all" query
39024 * @param {Boolean} cancel true to cancel the query
39025 * @param {Object} e The query event object
39027 'beforequery': true,
39030 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39031 * @param {Roo.form.ComboBox} combo This combo box
39036 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39037 * @param {Roo.form.ComboBox} combo This combo box
39038 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39044 if(this.transform){
39045 this.allowDomMove = false;
39046 var s = Roo.getDom(this.transform);
39047 if(!this.hiddenName){
39048 this.hiddenName = s.name;
39051 this.mode = 'local';
39052 var d = [], opts = s.options;
39053 for(var i = 0, len = opts.length;i < len; i++){
39055 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39057 this.value = value;
39059 d.push([value, o.text]);
39061 this.store = new Roo.data.SimpleStore({
39063 fields: ['value', 'text'],
39066 this.valueField = 'value';
39067 this.displayField = 'text';
39069 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39070 if(!this.lazyRender){
39071 this.target = true;
39072 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39073 s.parentNode.removeChild(s); // remove it
39074 this.render(this.el.parentNode);
39076 s.parentNode.removeChild(s); // remove it
39081 this.store = Roo.factory(this.store, Roo.data);
39084 this.selectedIndex = -1;
39085 if(this.mode == 'local'){
39086 if(config.queryDelay === undefined){
39087 this.queryDelay = 10;
39089 if(config.minChars === undefined){
39095 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39097 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39100 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39101 * rendering into an Roo.Editor, defaults to false)
39104 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39105 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39108 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39111 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39112 * the dropdown list (defaults to undefined, with no header element)
39116 * @cfg {String/Roo.Template} tpl The template to use to render the output
39120 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39122 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39124 listWidth: undefined,
39126 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39127 * mode = 'remote' or 'text' if mode = 'local')
39129 displayField: undefined,
39131 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39132 * mode = 'remote' or 'value' if mode = 'local').
39133 * Note: use of a valueField requires the user make a selection
39134 * in order for a value to be mapped.
39136 valueField: undefined,
39140 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39141 * field's data value (defaults to the underlying DOM element's name)
39143 hiddenName: undefined,
39145 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39149 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39151 selectedClass: 'x-combo-selected',
39153 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39154 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39155 * which displays a downward arrow icon).
39157 triggerClass : 'x-form-arrow-trigger',
39159 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39163 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39164 * anchor positions (defaults to 'tl-bl')
39166 listAlign: 'tl-bl?',
39168 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39172 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39173 * query specified by the allQuery config option (defaults to 'query')
39175 triggerAction: 'query',
39177 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39178 * (defaults to 4, does not apply if editable = false)
39182 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39183 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39187 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39188 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39192 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39193 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39197 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39198 * when editable = true (defaults to false)
39200 selectOnFocus:false,
39202 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39204 queryParam: 'query',
39206 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39207 * when mode = 'remote' (defaults to 'Loading...')
39209 loadingText: 'Loading...',
39211 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39215 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39219 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39220 * traditional select (defaults to true)
39224 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39228 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39232 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39233 * listWidth has a higher value)
39237 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39238 * allow the user to set arbitrary text into the field (defaults to false)
39240 forceSelection:false,
39242 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39243 * if typeAhead = true (defaults to 250)
39245 typeAheadDelay : 250,
39247 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39248 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39250 valueNotFoundText : undefined,
39252 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39254 blockFocus : false,
39257 * @cfg {Boolean} disableClear Disable showing of clear button.
39259 disableClear : false,
39261 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39263 alwaysQuery : false,
39269 // element that contains real text value.. (when hidden is used..)
39272 onRender : function(ct, position){
39273 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39274 if(this.hiddenName){
39275 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39277 this.hiddenField.value =
39278 this.hiddenValue !== undefined ? this.hiddenValue :
39279 this.value !== undefined ? this.value : '';
39281 // prevent input submission
39282 this.el.dom.removeAttribute('name');
39287 this.el.dom.setAttribute('autocomplete', 'off');
39290 var cls = 'x-combo-list';
39292 this.list = new Roo.Layer({
39293 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39296 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39297 this.list.setWidth(lw);
39298 this.list.swallowEvent('mousewheel');
39299 this.assetHeight = 0;
39302 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39303 this.assetHeight += this.header.getHeight();
39306 this.innerList = this.list.createChild({cls:cls+'-inner'});
39307 this.innerList.on('mouseover', this.onViewOver, this);
39308 this.innerList.on('mousemove', this.onViewMove, this);
39309 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39311 if(this.allowBlank && !this.pageSize && !this.disableClear){
39312 this.footer = this.list.createChild({cls:cls+'-ft'});
39313 this.pageTb = new Roo.Toolbar(this.footer);
39317 this.footer = this.list.createChild({cls:cls+'-ft'});
39318 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39319 {pageSize: this.pageSize});
39323 if (this.pageTb && this.allowBlank && !this.disableClear) {
39325 this.pageTb.add(new Roo.Toolbar.Fill(), {
39326 cls: 'x-btn-icon x-btn-clear',
39328 handler: function()
39331 _this.clearValue();
39332 _this.onSelect(false, -1);
39337 this.assetHeight += this.footer.getHeight();
39342 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39345 this.view = new Roo.View(this.innerList, this.tpl, {
39346 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39349 this.view.on('click', this.onViewClick, this);
39351 this.store.on('beforeload', this.onBeforeLoad, this);
39352 this.store.on('load', this.onLoad, this);
39353 this.store.on('loadexception', this.onLoadException, this);
39355 if(this.resizable){
39356 this.resizer = new Roo.Resizable(this.list, {
39357 pinned:true, handles:'se'
39359 this.resizer.on('resize', function(r, w, h){
39360 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39361 this.listWidth = w;
39362 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39363 this.restrictHeight();
39365 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39367 if(!this.editable){
39368 this.editable = true;
39369 this.setEditable(false);
39373 if (typeof(this.events.add.listeners) != 'undefined') {
39375 this.addicon = this.wrap.createChild(
39376 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39378 this.addicon.on('click', function(e) {
39379 this.fireEvent('add', this);
39382 if (typeof(this.events.edit.listeners) != 'undefined') {
39384 this.editicon = this.wrap.createChild(
39385 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39386 if (this.addicon) {
39387 this.editicon.setStyle('margin-left', '40px');
39389 this.editicon.on('click', function(e) {
39391 // we fire even if inothing is selected..
39392 this.fireEvent('edit', this, this.lastData );
39402 initEvents : function(){
39403 Roo.form.ComboBox.superclass.initEvents.call(this);
39405 this.keyNav = new Roo.KeyNav(this.el, {
39406 "up" : function(e){
39407 this.inKeyMode = true;
39411 "down" : function(e){
39412 if(!this.isExpanded()){
39413 this.onTriggerClick();
39415 this.inKeyMode = true;
39420 "enter" : function(e){
39421 this.onViewClick();
39425 "esc" : function(e){
39429 "tab" : function(e){
39430 this.onViewClick(false);
39431 this.fireEvent("specialkey", this, e);
39437 doRelay : function(foo, bar, hname){
39438 if(hname == 'down' || this.scope.isExpanded()){
39439 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39446 this.queryDelay = Math.max(this.queryDelay || 10,
39447 this.mode == 'local' ? 10 : 250);
39448 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39449 if(this.typeAhead){
39450 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39452 if(this.editable !== false){
39453 this.el.on("keyup", this.onKeyUp, this);
39455 if(this.forceSelection){
39456 this.on('blur', this.doForce, this);
39460 onDestroy : function(){
39462 this.view.setStore(null);
39463 this.view.el.removeAllListeners();
39464 this.view.el.remove();
39465 this.view.purgeListeners();
39468 this.list.destroy();
39471 this.store.un('beforeload', this.onBeforeLoad, this);
39472 this.store.un('load', this.onLoad, this);
39473 this.store.un('loadexception', this.onLoadException, this);
39475 Roo.form.ComboBox.superclass.onDestroy.call(this);
39479 fireKey : function(e){
39480 if(e.isNavKeyPress() && !this.list.isVisible()){
39481 this.fireEvent("specialkey", this, e);
39486 onResize: function(w, h){
39487 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39489 if(typeof w != 'number'){
39490 // we do not handle it!?!?
39493 var tw = this.trigger.getWidth();
39494 tw += this.addicon ? this.addicon.getWidth() : 0;
39495 tw += this.editicon ? this.editicon.getWidth() : 0;
39497 this.el.setWidth( this.adjustWidth('input', x));
39499 this.trigger.setStyle('left', x+'px');
39501 if(this.list && this.listWidth === undefined){
39502 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39503 this.list.setWidth(lw);
39504 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39512 * Allow or prevent the user from directly editing the field text. If false is passed,
39513 * the user will only be able to select from the items defined in the dropdown list. This method
39514 * is the runtime equivalent of setting the 'editable' config option at config time.
39515 * @param {Boolean} value True to allow the user to directly edit the field text
39517 setEditable : function(value){
39518 if(value == this.editable){
39521 this.editable = value;
39523 this.el.dom.setAttribute('readOnly', true);
39524 this.el.on('mousedown', this.onTriggerClick, this);
39525 this.el.addClass('x-combo-noedit');
39527 this.el.dom.setAttribute('readOnly', false);
39528 this.el.un('mousedown', this.onTriggerClick, this);
39529 this.el.removeClass('x-combo-noedit');
39534 onBeforeLoad : function(){
39535 if(!this.hasFocus){
39538 this.innerList.update(this.loadingText ?
39539 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39540 this.restrictHeight();
39541 this.selectedIndex = -1;
39545 onLoad : function(){
39546 if(!this.hasFocus){
39549 if(this.store.getCount() > 0){
39551 this.restrictHeight();
39552 if(this.lastQuery == this.allQuery){
39554 this.el.dom.select();
39556 if(!this.selectByValue(this.value, true)){
39557 this.select(0, true);
39561 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39562 this.taTask.delay(this.typeAheadDelay);
39566 this.onEmptyResults();
39571 onLoadException : function()
39574 Roo.log(this.store.reader.jsonData);
39575 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39576 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39582 onTypeAhead : function(){
39583 if(this.store.getCount() > 0){
39584 var r = this.store.getAt(0);
39585 var newValue = r.data[this.displayField];
39586 var len = newValue.length;
39587 var selStart = this.getRawValue().length;
39588 if(selStart != len){
39589 this.setRawValue(newValue);
39590 this.selectText(selStart, newValue.length);
39596 onSelect : function(record, index){
39597 if(this.fireEvent('beforeselect', this, record, index) !== false){
39598 this.setFromData(index > -1 ? record.data : false);
39600 this.fireEvent('select', this, record, index);
39605 * Returns the currently selected field value or empty string if no value is set.
39606 * @return {String} value The selected value
39608 getValue : function(){
39609 if(this.valueField){
39610 return typeof this.value != 'undefined' ? this.value : '';
39612 return Roo.form.ComboBox.superclass.getValue.call(this);
39617 * Clears any text/value currently set in the field
39619 clearValue : function(){
39620 if(this.hiddenField){
39621 this.hiddenField.value = '';
39624 this.setRawValue('');
39625 this.lastSelectionText = '';
39630 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39631 * will be displayed in the field. If the value does not match the data value of an existing item,
39632 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39633 * Otherwise the field will be blank (although the value will still be set).
39634 * @param {String} value The value to match
39636 setValue : function(v){
39638 if(this.valueField){
39639 var r = this.findRecord(this.valueField, v);
39641 text = r.data[this.displayField];
39642 }else if(this.valueNotFoundText !== undefined){
39643 text = this.valueNotFoundText;
39646 this.lastSelectionText = text;
39647 if(this.hiddenField){
39648 this.hiddenField.value = v;
39650 Roo.form.ComboBox.superclass.setValue.call(this, text);
39654 * @property {Object} the last set data for the element
39659 * Sets the value of the field based on a object which is related to the record format for the store.
39660 * @param {Object} value the value to set as. or false on reset?
39662 setFromData : function(o){
39663 var dv = ''; // display value
39664 var vv = ''; // value value..
39666 if (this.displayField) {
39667 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39669 // this is an error condition!!!
39670 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39673 if(this.valueField){
39674 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39676 if(this.hiddenField){
39677 this.hiddenField.value = vv;
39679 this.lastSelectionText = dv;
39680 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39684 // no hidden field.. - we store the value in 'value', but still display
39685 // display field!!!!
39686 this.lastSelectionText = dv;
39687 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39693 reset : function(){
39694 // overridden so that last data is reset..
39695 this.setValue(this.originalValue);
39696 this.clearInvalid();
39697 this.lastData = false;
39699 this.view.clearSelections();
39703 findRecord : function(prop, value){
39705 if(this.store.getCount() > 0){
39706 this.store.each(function(r){
39707 if(r.data[prop] == value){
39717 getName: function()
39719 // returns hidden if it's set..
39720 if (!this.rendered) {return ''};
39721 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39725 onViewMove : function(e, t){
39726 this.inKeyMode = false;
39730 onViewOver : function(e, t){
39731 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39734 var item = this.view.findItemFromChild(t);
39736 var index = this.view.indexOf(item);
39737 this.select(index, false);
39742 onViewClick : function(doFocus)
39744 var index = this.view.getSelectedIndexes()[0];
39745 var r = this.store.getAt(index);
39747 this.onSelect(r, index);
39749 if(doFocus !== false && !this.blockFocus){
39755 restrictHeight : function(){
39756 this.innerList.dom.style.height = '';
39757 var inner = this.innerList.dom;
39758 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39759 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39760 this.list.beginUpdate();
39761 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39762 this.list.alignTo(this.el, this.listAlign);
39763 this.list.endUpdate();
39767 onEmptyResults : function(){
39772 * Returns true if the dropdown list is expanded, else false.
39774 isExpanded : function(){
39775 return this.list.isVisible();
39779 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39780 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39781 * @param {String} value The data value of the item to select
39782 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39783 * selected item if it is not currently in view (defaults to true)
39784 * @return {Boolean} True if the value matched an item in the list, else false
39786 selectByValue : function(v, scrollIntoView){
39787 if(v !== undefined && v !== null){
39788 var r = this.findRecord(this.valueField || this.displayField, v);
39790 this.select(this.store.indexOf(r), scrollIntoView);
39798 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39799 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39800 * @param {Number} index The zero-based index of the list item to select
39801 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39802 * selected item if it is not currently in view (defaults to true)
39804 select : function(index, scrollIntoView){
39805 this.selectedIndex = index;
39806 this.view.select(index);
39807 if(scrollIntoView !== false){
39808 var el = this.view.getNode(index);
39810 this.innerList.scrollChildIntoView(el, false);
39816 selectNext : function(){
39817 var ct = this.store.getCount();
39819 if(this.selectedIndex == -1){
39821 }else if(this.selectedIndex < ct-1){
39822 this.select(this.selectedIndex+1);
39828 selectPrev : function(){
39829 var ct = this.store.getCount();
39831 if(this.selectedIndex == -1){
39833 }else if(this.selectedIndex != 0){
39834 this.select(this.selectedIndex-1);
39840 onKeyUp : function(e){
39841 if(this.editable !== false && !e.isSpecialKey()){
39842 this.lastKey = e.getKey();
39843 this.dqTask.delay(this.queryDelay);
39848 validateBlur : function(){
39849 return !this.list || !this.list.isVisible();
39853 initQuery : function(){
39854 this.doQuery(this.getRawValue());
39858 doForce : function(){
39859 if(this.el.dom.value.length > 0){
39860 this.el.dom.value =
39861 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39867 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39868 * query allowing the query action to be canceled if needed.
39869 * @param {String} query The SQL query to execute
39870 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39871 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39872 * saved in the current store (defaults to false)
39874 doQuery : function(q, forceAll){
39875 if(q === undefined || q === null){
39880 forceAll: forceAll,
39884 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39888 forceAll = qe.forceAll;
39889 if(forceAll === true || (q.length >= this.minChars)){
39890 if(this.lastQuery != q || this.alwaysQuery){
39891 this.lastQuery = q;
39892 if(this.mode == 'local'){
39893 this.selectedIndex = -1;
39895 this.store.clearFilter();
39897 this.store.filter(this.displayField, q);
39901 this.store.baseParams[this.queryParam] = q;
39903 params: this.getParams(q)
39908 this.selectedIndex = -1;
39915 getParams : function(q){
39917 //p[this.queryParam] = q;
39920 p.limit = this.pageSize;
39926 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39928 collapse : function(){
39929 if(!this.isExpanded()){
39933 Roo.get(document).un('mousedown', this.collapseIf, this);
39934 Roo.get(document).un('mousewheel', this.collapseIf, this);
39935 if (!this.editable) {
39936 Roo.get(document).un('keydown', this.listKeyPress, this);
39938 this.fireEvent('collapse', this);
39942 collapseIf : function(e){
39943 if(!e.within(this.wrap) && !e.within(this.list)){
39949 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39951 expand : function(){
39952 if(this.isExpanded() || !this.hasFocus){
39955 this.list.alignTo(this.el, this.listAlign);
39957 Roo.get(document).on('mousedown', this.collapseIf, this);
39958 Roo.get(document).on('mousewheel', this.collapseIf, this);
39959 if (!this.editable) {
39960 Roo.get(document).on('keydown', this.listKeyPress, this);
39963 this.fireEvent('expand', this);
39967 // Implements the default empty TriggerField.onTriggerClick function
39968 onTriggerClick : function(){
39972 if(this.isExpanded()){
39974 if (!this.blockFocus) {
39979 this.hasFocus = true;
39980 if(this.triggerAction == 'all') {
39981 this.doQuery(this.allQuery, true);
39983 this.doQuery(this.getRawValue());
39985 if (!this.blockFocus) {
39990 listKeyPress : function(e)
39992 //Roo.log('listkeypress');
39993 // scroll to first matching element based on key pres..
39994 if (e.isSpecialKey()) {
39997 var k = String.fromCharCode(e.getKey()).toUpperCase();
40000 var csel = this.view.getSelectedNodes();
40001 var cselitem = false;
40003 var ix = this.view.indexOf(csel[0]);
40004 cselitem = this.store.getAt(ix);
40005 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40011 this.store.each(function(v) {
40013 // start at existing selection.
40014 if (cselitem.id == v.id) {
40020 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40021 match = this.store.indexOf(v);
40026 if (match === false) {
40027 return true; // no more action?
40030 this.view.select(match);
40031 var sn = Roo.get(this.view.getSelectedNodes()[0])
40032 sn.scrollIntoView(sn.dom.parentNode, false);
40036 * @cfg {Boolean} grow
40040 * @cfg {Number} growMin
40044 * @cfg {Number} growMax
40052 * Copyright(c) 2010-2012, Roo J Solutions Limited
40059 * @class Roo.form.ComboBoxArray
40060 * @extends Roo.form.TextField
40061 * A facebook style adder... for lists of email / people / countries etc...
40062 * pick multiple items from a combo box, and shows each one.
40064 * Fred [x] Brian [x] [Pick another |v]
40067 * For this to work: it needs various extra information
40068 * - normal combo problay has
40070 * + displayField, valueField
40072 * For our purpose...
40075 * If we change from 'extends' to wrapping...
40082 * Create a new ComboBoxArray.
40083 * @param {Object} config Configuration options
40087 Roo.form.ComboBoxArray = function(config)
40090 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40092 this.items = new Roo.util.MixedCollection(false);
40094 // construct the child combo...
40104 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40107 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40112 // behavies liek a hiddne field
40113 inputType: 'hidden',
40115 * @cfg {Number} width The width of the box that displays the selected element
40122 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40126 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40128 hiddenName : false,
40131 // private the array of items that are displayed..
40133 // private - the hidden field el.
40135 // private - the filed el..
40138 //validateValue : function() { return true; }, // all values are ok!
40139 //onAddClick: function() { },
40141 onRender : function(ct, position)
40144 // create the standard hidden element
40145 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40148 // give fake names to child combo;
40149 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40150 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40152 this.combo = Roo.factory(this.combo, Roo.form);
40153 this.combo.onRender(ct, position);
40154 if (typeof(this.combo.width) != 'undefined') {
40155 this.combo.onResize(this.combo.width,0);
40158 this.combo.initEvents();
40160 // assigned so form know we need to do this..
40161 this.store = this.combo.store;
40162 this.valueField = this.combo.valueField;
40163 this.displayField = this.combo.displayField ;
40166 this.combo.wrap.addClass('x-cbarray-grp');
40168 var cbwrap = this.combo.wrap.createChild(
40169 {tag: 'div', cls: 'x-cbarray-cb'},
40174 this.hiddenEl = this.combo.wrap.createChild({
40175 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40177 this.el = this.combo.wrap.createChild({
40178 tag: 'input', type:'hidden' , name: this.name, value : ''
40180 // this.el.dom.removeAttribute("name");
40183 this.outerWrap = this.combo.wrap;
40184 this.wrap = cbwrap;
40186 this.outerWrap.setWidth(this.width);
40187 this.outerWrap.dom.removeChild(this.el.dom);
40189 this.wrap.dom.appendChild(this.el.dom);
40190 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40191 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40193 this.combo.trigger.setStyle('position','relative');
40194 this.combo.trigger.setStyle('left', '0px');
40195 this.combo.trigger.setStyle('top', '2px');
40197 this.combo.el.setStyle('vertical-align', 'text-bottom');
40199 //this.trigger.setStyle('vertical-align', 'top');
40201 // this should use the code from combo really... on('add' ....)
40205 this.adder = this.outerWrap.createChild(
40206 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40208 this.adder.on('click', function(e) {
40209 _t.fireEvent('adderclick', this, e);
40213 //this.adder.on('click', this.onAddClick, _t);
40216 this.combo.on('select', function(cb, rec, ix) {
40217 this.addItem(rec.data);
40220 cb.el.dom.value = '';
40221 //cb.lastData = rec.data;
40230 getName: function()
40232 // returns hidden if it's set..
40233 if (!this.rendered) {return ''};
40234 return this.hiddenName ? this.hiddenName : this.name;
40239 onResize: function(w, h){
40242 // not sure if this is needed..
40243 //this.combo.onResize(w,h);
40245 if(typeof w != 'number'){
40246 // we do not handle it!?!?
40249 var tw = this.combo.trigger.getWidth();
40250 tw += this.addicon ? this.addicon.getWidth() : 0;
40251 tw += this.editicon ? this.editicon.getWidth() : 0;
40253 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40255 this.combo.trigger.setStyle('left', '0px');
40257 if(this.list && this.listWidth === undefined){
40258 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40259 this.list.setWidth(lw);
40260 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40267 addItem: function(rec)
40269 var valueField = this.combo.valueField;
40270 var displayField = this.combo.displayField;
40271 if (this.items.indexOfKey(rec[valueField]) > -1) {
40272 //console.log("GOT " + rec.data.id);
40276 var x = new Roo.form.ComboBoxArray.Item({
40277 //id : rec[this.idField],
40279 displayField : displayField ,
40280 tipField : displayField ,
40284 this.items.add(rec[valueField],x);
40285 // add it before the element..
40286 this.updateHiddenEl();
40287 x.render(this.outerWrap, this.wrap.dom);
40288 // add the image handler..
40291 updateHiddenEl : function()
40294 if (!this.hiddenEl) {
40298 var idField = this.combo.valueField;
40300 this.items.each(function(f) {
40301 ar.push(f.data[idField]);
40304 this.hiddenEl.dom.value = ar.join(',');
40310 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40311 this.items.each(function(f) {
40314 this.el.dom.value = '';
40315 if (this.hiddenEl) {
40316 this.hiddenEl.dom.value = '';
40320 getValue: function()
40322 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40324 setValue: function(v) // not a valid action - must use addItems..
40331 if (this.store.isLocal && (typeof(v) == 'string')) {
40332 // then we can use the store to find the values..
40333 // comma seperated at present.. this needs to allow JSON based encoding..
40334 this.hiddenEl.value = v;
40336 Roo.each(v.split(','), function(k) {
40337 Roo.log("CHECK " + this.valueField + ',' + k);
40338 var li = this.store.query(this.valueField, k);
40343 add[this.valueField] = k;
40344 add[this.displayField] = li.item(0).data[this.displayField];
40350 if (typeof(v) == 'object') {
40351 // then let's assume it's an array of objects..
40352 Roo.each(v, function(l) {
40360 setFromData: function(v)
40362 // this recieves an object, if setValues is called.
40364 this.el.dom.value = v[this.displayField];
40365 this.hiddenEl.dom.value = v[this.valueField];
40366 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40369 var kv = v[this.valueField];
40370 var dv = v[this.displayField];
40371 kv = typeof(kv) != 'string' ? '' : kv;
40372 dv = typeof(dv) != 'string' ? '' : dv;
40375 var keys = kv.split(',');
40376 var display = dv.split(',');
40377 for (var i = 0 ; i < keys.length; i++) {
40380 add[this.valueField] = keys[i];
40381 add[this.displayField] = display[i];
40389 validateValue : function(value){
40390 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40399 * @class Roo.form.ComboBoxArray.Item
40400 * @extends Roo.BoxComponent
40401 * A selected item in the list
40402 * Fred [x] Brian [x] [Pick another |v]
40405 * Create a new item.
40406 * @param {Object} config Configuration options
40409 Roo.form.ComboBoxArray.Item = function(config) {
40410 config.id = Roo.id();
40411 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40414 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40417 displayField : false,
40421 defaultAutoCreate : {
40423 cls: 'x-cbarray-item',
40430 src : Roo.BLANK_IMAGE_URL ,
40438 onRender : function(ct, position)
40440 Roo.form.Field.superclass.onRender.call(this, ct, position);
40443 var cfg = this.getAutoCreate();
40444 this.el = ct.createChild(cfg, position);
40447 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40449 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40450 this.cb.renderer(this.data) :
40451 String.format('{0}',this.data[this.displayField]);
40454 this.el.child('div').dom.setAttribute('qtip',
40455 String.format('{0}',this.data[this.tipField])
40458 this.el.child('img').on('click', this.remove, this);
40462 remove : function()
40465 this.cb.items.remove(this);
40466 this.el.child('img').un('click', this.remove, this);
40468 this.cb.updateHiddenEl();
40474 * Ext JS Library 1.1.1
40475 * Copyright(c) 2006-2007, Ext JS, LLC.
40477 * Originally Released Under LGPL - original licence link has changed is not relivant.
40480 * <script type="text/javascript">
40483 * @class Roo.form.Checkbox
40484 * @extends Roo.form.Field
40485 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40487 * Creates a new Checkbox
40488 * @param {Object} config Configuration options
40490 Roo.form.Checkbox = function(config){
40491 Roo.form.Checkbox.superclass.constructor.call(this, config);
40495 * Fires when the checkbox is checked or unchecked.
40496 * @param {Roo.form.Checkbox} this This checkbox
40497 * @param {Boolean} checked The new checked value
40503 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40505 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40507 focusClass : undefined,
40509 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40511 fieldClass: "x-form-field",
40513 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40517 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40518 * {tag: "input", type: "checkbox", autocomplete: "off"})
40520 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40522 * @cfg {String} boxLabel The text that appears beside the checkbox
40526 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40530 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40532 valueOff: '0', // value when not checked..
40534 actionMode : 'viewEl',
40537 itemCls : 'x-menu-check-item x-form-item',
40538 groupClass : 'x-menu-group-item',
40539 inputType : 'hidden',
40542 inSetChecked: false, // check that we are not calling self...
40544 inputElement: false, // real input element?
40545 basedOn: false, // ????
40547 isFormField: true, // not sure where this is needed!!!!
40549 onResize : function(){
40550 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40551 if(!this.boxLabel){
40552 this.el.alignTo(this.wrap, 'c-c');
40556 initEvents : function(){
40557 Roo.form.Checkbox.superclass.initEvents.call(this);
40558 this.el.on("click", this.onClick, this);
40559 this.el.on("change", this.onClick, this);
40563 getResizeEl : function(){
40567 getPositionEl : function(){
40572 onRender : function(ct, position){
40573 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40575 if(this.inputValue !== undefined){
40576 this.el.dom.value = this.inputValue;
40579 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40580 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40581 var viewEl = this.wrap.createChild({
40582 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40583 this.viewEl = viewEl;
40584 this.wrap.on('click', this.onClick, this);
40586 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40587 this.el.on('propertychange', this.setFromHidden, this); //ie
40592 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40593 // viewEl.on('click', this.onClick, this);
40595 //if(this.checked){
40596 this.setChecked(this.checked);
40598 //this.checked = this.el.dom;
40604 initValue : Roo.emptyFn,
40607 * Returns the checked state of the checkbox.
40608 * @return {Boolean} True if checked, else false
40610 getValue : function(){
40612 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40614 return this.valueOff;
40619 onClick : function(){
40620 this.setChecked(!this.checked);
40622 //if(this.el.dom.checked != this.checked){
40623 // this.setValue(this.el.dom.checked);
40628 * Sets the checked state of the checkbox.
40629 * On is always based on a string comparison between inputValue and the param.
40630 * @param {Boolean/String} value - the value to set
40631 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40633 setValue : function(v,suppressEvent){
40636 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40637 //if(this.el && this.el.dom){
40638 // this.el.dom.checked = this.checked;
40639 // this.el.dom.defaultChecked = this.checked;
40641 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40642 //this.fireEvent("check", this, this.checked);
40645 setChecked : function(state,suppressEvent)
40647 if (this.inSetChecked) {
40648 this.checked = state;
40654 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40656 this.checked = state;
40657 if(suppressEvent !== true){
40658 this.fireEvent('check', this, state);
40660 this.inSetChecked = true;
40661 this.el.dom.value = state ? this.inputValue : this.valueOff;
40662 this.inSetChecked = false;
40665 // handle setting of hidden value by some other method!!?!?
40666 setFromHidden: function()
40671 //console.log("SET FROM HIDDEN");
40672 //alert('setFrom hidden');
40673 this.setValue(this.el.dom.value);
40676 onDestroy : function()
40679 Roo.get(this.viewEl).remove();
40682 Roo.form.Checkbox.superclass.onDestroy.call(this);
40687 * Ext JS Library 1.1.1
40688 * Copyright(c) 2006-2007, Ext JS, LLC.
40690 * Originally Released Under LGPL - original licence link has changed is not relivant.
40693 * <script type="text/javascript">
40697 * @class Roo.form.Radio
40698 * @extends Roo.form.Checkbox
40699 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40700 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40702 * Creates a new Radio
40703 * @param {Object} config Configuration options
40705 Roo.form.Radio = function(){
40706 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40708 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40709 inputType: 'radio',
40712 * If this radio is part of a group, it will return the selected value
40715 getGroupValue : function(){
40716 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40720 onRender : function(ct, position){
40721 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40723 if(this.inputValue !== undefined){
40724 this.el.dom.value = this.inputValue;
40727 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40728 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40729 //var viewEl = this.wrap.createChild({
40730 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40731 //this.viewEl = viewEl;
40732 //this.wrap.on('click', this.onClick, this);
40734 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40735 //this.el.on('propertychange', this.setFromHidden, this); //ie
40740 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40741 // viewEl.on('click', this.onClick, this);
40744 this.el.dom.checked = 'checked' ;
40750 });//<script type="text/javascript">
40753 * Ext JS Library 1.1.1
40754 * Copyright(c) 2006-2007, Ext JS, LLC.
40755 * licensing@extjs.com
40757 * http://www.extjs.com/license
40763 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
40764 * - IE ? - no idea how much works there.
40772 * @class Ext.form.HtmlEditor
40773 * @extends Ext.form.Field
40774 * Provides a lightweight HTML Editor component.
40776 * This has been tested on Fireforx / Chrome.. IE may not be so great..
40778 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
40779 * supported by this editor.</b><br/><br/>
40780 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
40781 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40783 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
40785 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
40789 * @cfg {String} createLinkText The default text for the create link prompt
40791 createLinkText : 'Please enter the URL for the link:',
40793 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
40795 defaultLinkValue : 'http:/'+'/',
40798 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40803 * @cfg {Number} height (in pixels)
40807 * @cfg {Number} width (in pixels)
40812 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40815 stylesheets: false,
40820 // private properties
40821 validationEvent : false,
40823 initialized : false,
40825 sourceEditMode : false,
40826 onFocus : Roo.emptyFn,
40828 hideMode:'offsets',
40830 defaultAutoCreate : { // modified by initCompnoent..
40832 style:"width:500px;height:300px;",
40833 autocomplete: "off"
40837 initComponent : function(){
40840 * @event initialize
40841 * Fires when the editor is fully initialized (including the iframe)
40842 * @param {HtmlEditor} this
40847 * Fires when the editor is first receives the focus. Any insertion must wait
40848 * until after this event.
40849 * @param {HtmlEditor} this
40853 * @event beforesync
40854 * Fires before the textarea is updated with content from the editor iframe. Return false
40855 * to cancel the sync.
40856 * @param {HtmlEditor} this
40857 * @param {String} html
40861 * @event beforepush
40862 * Fires before the iframe editor is updated with content from the textarea. Return false
40863 * to cancel the push.
40864 * @param {HtmlEditor} this
40865 * @param {String} html
40870 * Fires when the textarea is updated with content from the editor iframe.
40871 * @param {HtmlEditor} this
40872 * @param {String} html
40877 * Fires when the iframe editor is updated with content from the textarea.
40878 * @param {HtmlEditor} this
40879 * @param {String} html
40883 * @event editmodechange
40884 * Fires when the editor switches edit modes
40885 * @param {HtmlEditor} this
40886 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
40888 editmodechange: true,
40890 * @event editorevent
40891 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40892 * @param {HtmlEditor} this
40896 this.defaultAutoCreate = {
40898 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
40899 autocomplete: "off"
40904 * Protected method that will not generally be called directly. It
40905 * is called when the editor creates its toolbar. Override this method if you need to
40906 * add custom toolbar buttons.
40907 * @param {HtmlEditor} editor
40909 createToolbar : function(editor){
40910 if (!editor.toolbars || !editor.toolbars.length) {
40911 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
40914 for (var i =0 ; i < editor.toolbars.length;i++) {
40915 editor.toolbars[i] = Roo.factory(
40916 typeof(editor.toolbars[i]) == 'string' ?
40917 { xtype: editor.toolbars[i]} : editor.toolbars[i],
40918 Roo.form.HtmlEditor);
40919 editor.toolbars[i].init(editor);
40926 * Protected method that will not generally be called directly. It
40927 * is called when the editor initializes the iframe with HTML contents. Override this method if you
40928 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
40930 getDocMarkup : function(){
40933 if (this.stylesheets === false) {
40935 Roo.get(document.head).select('style').each(function(node) {
40936 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40939 Roo.get(document.head).select('link').each(function(node) {
40940 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40943 } else if (!this.stylesheets.length) {
40945 st = '<style type="text/css">' +
40946 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40949 Roo.each(this.stylesheets, function(s) {
40950 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
40955 st += '<style type="text/css">' +
40956 'IMG { cursor: pointer } ' +
40960 return '<html><head>' + st +
40961 //<style type="text/css">' +
40962 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40964 ' </head><body class="roo-htmleditor-body"></body></html>';
40968 onRender : function(ct, position)
40971 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
40972 this.el.dom.style.border = '0 none';
40973 this.el.dom.setAttribute('tabIndex', -1);
40974 this.el.addClass('x-hidden');
40975 if(Roo.isIE){ // fix IE 1px bogus margin
40976 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
40978 this.wrap = this.el.wrap({
40979 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
40982 if (this.resizable) {
40983 this.resizeEl = new Roo.Resizable(this.wrap, {
40987 minHeight : this.height,
40988 height: this.height,
40989 handles : this.resizable,
40992 resize : function(r, w, h) {
40993 _t.onResize(w,h); // -something
41000 this.frameId = Roo.id();
41002 this.createToolbar(this);
41006 var iframe = this.wrap.createChild({
41009 name: this.frameId,
41010 frameBorder : 'no',
41011 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41015 // console.log(iframe);
41016 //this.wrap.dom.appendChild(iframe);
41018 this.iframe = iframe.dom;
41020 this.assignDocWin();
41022 this.doc.designMode = 'on';
41025 this.doc.write(this.getDocMarkup());
41029 var task = { // must defer to wait for browser to be ready
41031 //console.log("run task?" + this.doc.readyState);
41032 this.assignDocWin();
41033 if(this.doc.body || this.doc.readyState == 'complete'){
41035 this.doc.designMode="on";
41039 Roo.TaskMgr.stop(task);
41040 this.initEditor.defer(10, this);
41047 Roo.TaskMgr.start(task);
41050 this.setSize(this.wrap.getSize());
41052 if (this.resizeEl) {
41053 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
41054 // should trigger onReize..
41059 onResize : function(w, h)
41061 //Roo.log('resize: ' +w + ',' + h );
41062 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
41063 if(this.el && this.iframe){
41064 if(typeof w == 'number'){
41065 var aw = w - this.wrap.getFrameWidth('lr');
41066 this.el.setWidth(this.adjustWidth('textarea', aw));
41067 this.iframe.style.width = aw + 'px';
41069 if(typeof h == 'number'){
41071 for (var i =0; i < this.toolbars.length;i++) {
41072 // fixme - ask toolbars for heights?
41073 tbh += this.toolbars[i].tb.el.getHeight();
41074 if (this.toolbars[i].footer) {
41075 tbh += this.toolbars[i].footer.el.getHeight();
41082 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
41083 ah -= 5; // knock a few pixes off for look..
41084 this.el.setHeight(this.adjustWidth('textarea', ah));
41085 this.iframe.style.height = ah + 'px';
41087 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
41094 * Toggles the editor between standard and source edit mode.
41095 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41097 toggleSourceEdit : function(sourceEditMode){
41099 this.sourceEditMode = sourceEditMode === true;
41101 if(this.sourceEditMode){
41103 // Roo.log(this.syncValue());
41105 this.iframe.className = 'x-hidden';
41106 this.el.removeClass('x-hidden');
41107 this.el.dom.removeAttribute('tabIndex');
41111 // Roo.log(this.pushValue());
41113 this.iframe.className = '';
41114 this.el.addClass('x-hidden');
41115 this.el.dom.setAttribute('tabIndex', -1);
41118 this.setSize(this.wrap.getSize());
41119 this.fireEvent('editmodechange', this, this.sourceEditMode);
41122 // private used internally
41123 createLink : function(){
41124 var url = prompt(this.createLinkText, this.defaultLinkValue);
41125 if(url && url != 'http:/'+'/'){
41126 this.relayCmd('createlink', url);
41130 // private (for BoxComponent)
41131 adjustSize : Roo.BoxComponent.prototype.adjustSize,
41133 // private (for BoxComponent)
41134 getResizeEl : function(){
41138 // private (for BoxComponent)
41139 getPositionEl : function(){
41144 initEvents : function(){
41145 this.originalValue = this.getValue();
41149 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
41152 markInvalid : Roo.emptyFn,
41154 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
41157 clearInvalid : Roo.emptyFn,
41159 setValue : function(v){
41160 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
41165 * Protected method that will not generally be called directly. If you need/want
41166 * custom HTML cleanup, this is the method you should override.
41167 * @param {String} html The HTML to be cleaned
41168 * return {String} The cleaned HTML
41170 cleanHtml : function(html){
41171 html = String(html);
41172 if(html.length > 5){
41173 if(Roo.isSafari){ // strip safari nonsense
41174 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41177 if(html == ' '){
41184 * Protected method that will not generally be called directly. Syncs the contents
41185 * of the editor iframe with the textarea.
41187 syncValue : function(){
41188 if(this.initialized){
41189 var bd = (this.doc.body || this.doc.documentElement);
41190 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41191 var html = bd.innerHTML;
41193 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41194 var m = bs.match(/text-align:(.*?);/i);
41196 html = '<div style="'+m[0]+'">' + html + '</div>';
41199 html = this.cleanHtml(html);
41200 // fix up the special chars.. normaly like back quotes in word...
41201 // however we do not want to do this with chinese..
41202 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41203 var cc = b.charCodeAt();
41205 (cc >= 0x4E00 && cc < 0xA000 ) ||
41206 (cc >= 0x3400 && cc < 0x4E00 ) ||
41207 (cc >= 0xf900 && cc < 0xfb00 )
41213 if(this.fireEvent('beforesync', this, html) !== false){
41214 this.el.dom.value = html;
41215 this.fireEvent('sync', this, html);
41221 * Protected method that will not generally be called directly. Pushes the value of the textarea
41222 * into the iframe editor.
41224 pushValue : function(){
41225 if(this.initialized){
41226 var v = this.el.dom.value;
41232 if(this.fireEvent('beforepush', this, v) !== false){
41233 var d = (this.doc.body || this.doc.documentElement);
41235 this.cleanUpPaste();
41236 this.el.dom.value = d.innerHTML;
41237 this.fireEvent('push', this, v);
41243 deferFocus : function(){
41244 this.focus.defer(10, this);
41248 focus : function(){
41249 if(this.win && !this.sourceEditMode){
41256 assignDocWin: function()
41258 var iframe = this.iframe;
41261 this.doc = iframe.contentWindow.document;
41262 this.win = iframe.contentWindow;
41264 if (!Roo.get(this.frameId)) {
41267 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41268 this.win = Roo.get(this.frameId).dom.contentWindow;
41273 initEditor : function(){
41274 //console.log("INIT EDITOR");
41275 this.assignDocWin();
41279 this.doc.designMode="on";
41281 this.doc.write(this.getDocMarkup());
41284 var dbody = (this.doc.body || this.doc.documentElement);
41285 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41286 // this copies styles from the containing element into thsi one..
41287 // not sure why we need all of this..
41288 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41289 ss['background-attachment'] = 'fixed'; // w3c
41290 dbody.bgProperties = 'fixed'; // ie
41291 Roo.DomHelper.applyStyles(dbody, ss);
41292 Roo.EventManager.on(this.doc, {
41293 //'mousedown': this.onEditorEvent,
41294 'mouseup': this.onEditorEvent,
41295 'dblclick': this.onEditorEvent,
41296 'click': this.onEditorEvent,
41297 'keyup': this.onEditorEvent,
41302 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41304 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41305 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41307 this.initialized = true;
41309 this.fireEvent('initialize', this);
41314 onDestroy : function(){
41320 for (var i =0; i < this.toolbars.length;i++) {
41321 // fixme - ask toolbars for heights?
41322 this.toolbars[i].onDestroy();
41325 this.wrap.dom.innerHTML = '';
41326 this.wrap.remove();
41331 onFirstFocus : function(){
41333 this.assignDocWin();
41336 this.activated = true;
41337 for (var i =0; i < this.toolbars.length;i++) {
41338 this.toolbars[i].onFirstFocus();
41341 if(Roo.isGecko){ // prevent silly gecko errors
41343 var s = this.win.getSelection();
41344 if(!s.focusNode || s.focusNode.nodeType != 3){
41345 var r = s.getRangeAt(0);
41346 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41351 this.execCmd('useCSS', true);
41352 this.execCmd('styleWithCSS', false);
41355 this.fireEvent('activate', this);
41359 adjustFont: function(btn){
41360 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41361 //if(Roo.isSafari){ // safari
41364 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41365 if(Roo.isSafari){ // safari
41366 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41367 v = (v < 10) ? 10 : v;
41368 v = (v > 48) ? 48 : v;
41369 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41374 v = Math.max(1, v+adjust);
41376 this.execCmd('FontSize', v );
41379 onEditorEvent : function(e){
41380 this.fireEvent('editorevent', this, e);
41381 // this.updateToolbar();
41382 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41385 insertTag : function(tg)
41387 // could be a bit smarter... -> wrap the current selected tRoo..
41388 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41390 range = this.createRange(this.getSelection());
41391 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41392 wrappingNode.appendChild(range.extractContents());
41393 range.insertNode(wrappingNode);
41400 this.execCmd("formatblock", tg);
41404 insertText : function(txt)
41408 var range = this.createRange();
41409 range.deleteContents();
41410 //alert(Sender.getAttribute('label'));
41412 range.insertNode(this.doc.createTextNode(txt));
41416 relayBtnCmd : function(btn){
41417 this.relayCmd(btn.cmd);
41421 * Executes a Midas editor command on the editor document and performs necessary focus and
41422 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41423 * @param {String} cmd The Midas command
41424 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41426 relayCmd : function(cmd, value){
41428 this.execCmd(cmd, value);
41429 this.fireEvent('editorevent', this);
41430 //this.updateToolbar();
41435 * Executes a Midas editor command directly on the editor document.
41436 * For visual commands, you should use {@link #relayCmd} instead.
41437 * <b>This should only be called after the editor is initialized.</b>
41438 * @param {String} cmd The Midas command
41439 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41441 execCmd : function(cmd, value){
41442 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41449 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41451 * @param {String} text | dom node..
41453 insertAtCursor : function(text)
41458 if(!this.activated){
41464 var r = this.doc.selection.createRange();
41475 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41479 // from jquery ui (MIT licenced)
41481 var win = this.win;
41483 if (win.getSelection && win.getSelection().getRangeAt) {
41484 range = win.getSelection().getRangeAt(0);
41485 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41486 range.insertNode(node);
41487 } else if (win.document.selection && win.document.selection.createRange) {
41488 // no firefox support
41489 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41490 win.document.selection.createRange().pasteHTML(txt);
41492 // no firefox support
41493 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41494 this.execCmd('InsertHTML', txt);
41503 mozKeyPress : function(e){
41505 var c = e.getCharCode(), cmd;
41508 c = String.fromCharCode(c).toLowerCase();
41522 this.cleanUpPaste.defer(100, this);
41530 e.preventDefault();
41538 fixKeys : function(){ // load time branching for fastest keydown performance
41540 return function(e){
41541 var k = e.getKey(), r;
41544 r = this.doc.selection.createRange();
41547 r.pasteHTML('    ');
41554 r = this.doc.selection.createRange();
41556 var target = r.parentElement();
41557 if(!target || target.tagName.toLowerCase() != 'li'){
41559 r.pasteHTML('<br />');
41565 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41566 this.cleanUpPaste.defer(100, this);
41572 }else if(Roo.isOpera){
41573 return function(e){
41574 var k = e.getKey();
41578 this.execCmd('InsertHTML','    ');
41581 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41582 this.cleanUpPaste.defer(100, this);
41587 }else if(Roo.isSafari){
41588 return function(e){
41589 var k = e.getKey();
41593 this.execCmd('InsertText','\t');
41597 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41598 this.cleanUpPaste.defer(100, this);
41606 getAllAncestors: function()
41608 var p = this.getSelectedNode();
41611 a.push(p); // push blank onto stack..
41612 p = this.getParentElement();
41616 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41620 a.push(this.doc.body);
41624 lastSelNode : false,
41627 getSelection : function()
41629 this.assignDocWin();
41630 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41633 getSelectedNode: function()
41635 // this may only work on Gecko!!!
41637 // should we cache this!!!!
41642 var range = this.createRange(this.getSelection()).cloneRange();
41645 var parent = range.parentElement();
41647 var testRange = range.duplicate();
41648 testRange.moveToElementText(parent);
41649 if (testRange.inRange(range)) {
41652 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41655 parent = parent.parentElement;
41660 // is ancestor a text element.
41661 var ac = range.commonAncestorContainer;
41662 if (ac.nodeType == 3) {
41663 ac = ac.parentNode;
41666 var ar = ac.childNodes;
41669 var other_nodes = [];
41670 var has_other_nodes = false;
41671 for (var i=0;i<ar.length;i++) {
41672 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41675 // fullly contained node.
41677 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41682 // probably selected..
41683 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41684 other_nodes.push(ar[i]);
41688 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41693 has_other_nodes = true;
41695 if (!nodes.length && other_nodes.length) {
41696 nodes= other_nodes;
41698 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41704 createRange: function(sel)
41706 // this has strange effects when using with
41707 // top toolbar - not sure if it's a great idea.
41708 //this.editor.contentWindow.focus();
41709 if (typeof sel != "undefined") {
41711 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41713 return this.doc.createRange();
41716 return this.doc.createRange();
41719 getParentElement: function()
41722 this.assignDocWin();
41723 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41725 var range = this.createRange(sel);
41728 var p = range.commonAncestorContainer;
41729 while (p.nodeType == 3) { // text node
41740 * Range intersection.. the hard stuff...
41744 * [ -- selected range --- ]
41748 * if end is before start or hits it. fail.
41749 * if start is after end or hits it fail.
41751 * if either hits (but other is outside. - then it's not
41757 // @see http://www.thismuchiknow.co.uk/?p=64.
41758 rangeIntersectsNode : function(range, node)
41760 var nodeRange = node.ownerDocument.createRange();
41762 nodeRange.selectNode(node);
41764 nodeRange.selectNodeContents(node);
41767 var rangeStartRange = range.cloneRange();
41768 rangeStartRange.collapse(true);
41770 var rangeEndRange = range.cloneRange();
41771 rangeEndRange.collapse(false);
41773 var nodeStartRange = nodeRange.cloneRange();
41774 nodeStartRange.collapse(true);
41776 var nodeEndRange = nodeRange.cloneRange();
41777 nodeEndRange.collapse(false);
41779 return rangeStartRange.compareBoundaryPoints(
41780 Range.START_TO_START, nodeEndRange) == -1 &&
41781 rangeEndRange.compareBoundaryPoints(
41782 Range.START_TO_START, nodeStartRange) == 1;
41786 rangeCompareNode : function(range, node)
41788 var nodeRange = node.ownerDocument.createRange();
41790 nodeRange.selectNode(node);
41792 nodeRange.selectNodeContents(node);
41796 range.collapse(true);
41798 nodeRange.collapse(true);
41800 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41801 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41803 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41805 var nodeIsBefore = ss == 1;
41806 var nodeIsAfter = ee == -1;
41808 if (nodeIsBefore && nodeIsAfter)
41810 if (!nodeIsBefore && nodeIsAfter)
41811 return 1; //right trailed.
41813 if (nodeIsBefore && !nodeIsAfter)
41814 return 2; // left trailed.
41819 // private? - in a new class?
41820 cleanUpPaste : function()
41822 // cleans up the whole document..
41823 Roo.log('cleanuppaste');
41824 this.cleanUpChildren(this.doc.body);
41825 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41826 if (clean != this.doc.body.innerHTML) {
41827 this.doc.body.innerHTML = clean;
41832 cleanWordChars : function(input) {// change the chars to hex code
41833 var he = Roo.form.HtmlEditor;
41835 var output = input;
41836 Roo.each(he.swapCodes, function(sw) {
41837 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41839 output = output.replace(swapper, sw[1]);
41846 cleanUpChildren : function (n)
41848 if (!n.childNodes.length) {
41851 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41852 this.cleanUpChild(n.childNodes[i]);
41859 cleanUpChild : function (node)
41862 //console.log(node);
41863 if (node.nodeName == "#text") {
41864 // clean up silly Windows -- stuff?
41867 if (node.nodeName == "#comment") {
41868 node.parentNode.removeChild(node);
41869 // clean up silly Windows -- stuff?
41873 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
41875 node.parentNode.removeChild(node);
41880 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
41882 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41883 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41885 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41886 // remove_keep_children = true;
41889 if (remove_keep_children) {
41890 this.cleanUpChildren(node);
41891 // inserts everything just before this node...
41892 while (node.childNodes.length) {
41893 var cn = node.childNodes[0];
41894 node.removeChild(cn);
41895 node.parentNode.insertBefore(cn, node);
41897 node.parentNode.removeChild(node);
41901 if (!node.attributes || !node.attributes.length) {
41902 this.cleanUpChildren(node);
41906 function cleanAttr(n,v)
41909 if (v.match(/^\./) || v.match(/^\//)) {
41912 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41915 if (v.match(/^#/)) {
41918 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41919 node.removeAttribute(n);
41923 function cleanStyle(n,v)
41925 if (v.match(/expression/)) { //XSS?? should we even bother..
41926 node.removeAttribute(n);
41929 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.form.HtmlEditor.cwhite : ed.cwhite;
41930 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.form.HtmlEditor.cblack : ed.cblack;
41933 var parts = v.split(/;/);
41936 Roo.each(parts, function(p) {
41937 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41941 var l = p.split(':').shift().replace(/\s+/g,'');
41942 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41945 if ( cblack.indexOf(l) > -1) {
41946 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41947 //node.removeAttribute(n);
41951 // only allow 'c whitelisted system attributes'
41952 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41953 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41954 //node.removeAttribute(n);
41964 if (clean.length) {
41965 node.setAttribute(n, clean.join(';'));
41967 node.removeAttribute(n);
41973 for (var i = node.attributes.length-1; i > -1 ; i--) {
41974 var a = node.attributes[i];
41977 if (a.name.toLowerCase().substr(0,2)=='on') {
41978 node.removeAttribute(a.name);
41981 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
41982 node.removeAttribute(a.name);
41985 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
41986 cleanAttr(a.name,a.value); // fixme..
41989 if (a.name == 'style') {
41990 cleanStyle(a.name,a.value);
41993 /// clean up MS crap..
41994 // tecnically this should be a list of valid class'es..
41997 if (a.name == 'class') {
41998 if (a.value.match(/^Mso/)) {
41999 node.className = '';
42002 if (a.value.match(/body/)) {
42003 node.className = '';
42014 this.cleanUpChildren(node);
42020 // hide stuff that is not compatible
42034 * @event specialkey
42038 * @cfg {String} fieldClass @hide
42041 * @cfg {String} focusClass @hide
42044 * @cfg {String} autoCreate @hide
42047 * @cfg {String} inputType @hide
42050 * @cfg {String} invalidClass @hide
42053 * @cfg {String} invalidText @hide
42056 * @cfg {String} msgFx @hide
42059 * @cfg {String} validateOnBlur @hide
42063 Roo.form.HtmlEditor.white = [
42064 'area', 'br', 'img', 'input', 'hr', 'wbr',
42066 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42067 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42068 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42069 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42070 'table', 'ul', 'xmp',
42072 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42075 'dir', 'menu', 'ol', 'ul', 'dl',
42081 Roo.form.HtmlEditor.black = [
42082 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42084 'base', 'basefont', 'bgsound', 'blink', 'body',
42085 'frame', 'frameset', 'head', 'html', 'ilayer',
42086 'iframe', 'layer', 'link', 'meta', 'object',
42087 'script', 'style' ,'title', 'xml' // clean later..
42089 Roo.form.HtmlEditor.clean = [
42090 'script', 'style', 'title', 'xml'
42092 Roo.form.HtmlEditor.remove = [
42097 Roo.form.HtmlEditor.ablack = [
42101 Roo.form.HtmlEditor.aclean = [
42102 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42106 Roo.form.HtmlEditor.pwhite= [
42107 'http', 'https', 'mailto'
42110 // white listed style attributes.
42111 Roo.form.HtmlEditor.cwhite= [
42112 // 'text-align', /// default is to allow most things..
42118 // black listed style attributes.
42119 Roo.form.HtmlEditor.cblack= [
42120 // 'font-size' -- this can be set by the project
42124 Roo.form.HtmlEditor.swapCodes =[
42135 // <script type="text/javascript">
42138 * Ext JS Library 1.1.1
42139 * Copyright(c) 2006-2007, Ext JS, LLC.
42145 * @class Roo.form.HtmlEditorToolbar1
42150 new Roo.form.HtmlEditor({
42153 new Roo.form.HtmlEditorToolbar1({
42154 disable : { fonts: 1 , format: 1, ..., ... , ...],
42160 * @cfg {Object} disable List of elements to disable..
42161 * @cfg {Array} btns List of additional buttons.
42165 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42168 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42171 Roo.apply(this, config);
42173 // default disabled, based on 'good practice'..
42174 this.disable = this.disable || {};
42175 Roo.applyIf(this.disable, {
42178 specialElements : true
42182 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42183 // dont call parent... till later.
42186 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42194 * @cfg {Object} disable List of toolbar elements to disable
42199 * @cfg {Array} fontFamilies An array of available font families
42217 // "á" , ?? a acute?
42222 "°" // , // degrees
42224 // "é" , // e ecute
42225 // "ú" , // u ecute?
42228 specialElements : [
42230 text: "Insert Table",
42233 ihtml : '<table><tr><td>Cell</td></tr></table>'
42237 text: "Insert Image",
42240 ihtml : '<img src="about:blank"/>'
42249 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42250 "input:submit", "input:button", "select", "textarea", "label" ],
42253 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42255 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42263 * @cfg {String} defaultFont default font to use.
42265 defaultFont: 'tahoma',
42267 fontSelect : false,
42270 formatCombo : false,
42272 init : function(editor)
42274 this.editor = editor;
42277 var fid = editor.frameId;
42279 function btn(id, toggle, handler){
42280 var xid = fid + '-'+ id ;
42284 cls : 'x-btn-icon x-edit-'+id,
42285 enableToggle:toggle !== false,
42286 scope: editor, // was editor...
42287 handler:handler||editor.relayBtnCmd,
42288 clickEvent:'mousedown',
42289 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42296 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
42298 // stop form submits
42299 tb.el.on('click', function(e){
42300 e.preventDefault(); // what does this do?
42303 if(!this.disable.font) { // && !Roo.isSafari){
42304 /* why no safari for fonts
42305 editor.fontSelect = tb.el.createChild({
42308 cls:'x-font-select',
42309 html: this.createFontOptions()
42312 editor.fontSelect.on('change', function(){
42313 var font = editor.fontSelect.dom.value;
42314 editor.relayCmd('fontname', font);
42315 editor.deferFocus();
42319 editor.fontSelect.dom,
42325 if(!this.disable.formats){
42326 this.formatCombo = new Roo.form.ComboBox({
42327 store: new Roo.data.SimpleStore({
42330 data : this.formats // from states.js
42334 //autoCreate : {tag: "div", size: "20"},
42335 displayField:'tag',
42339 triggerAction: 'all',
42340 emptyText:'Add tag',
42341 selectOnFocus:true,
42344 'select': function(c, r, i) {
42345 editor.insertTag(r.get('tag'));
42351 tb.addField(this.formatCombo);
42355 if(!this.disable.format){
42362 if(!this.disable.fontSize){
42367 btn('increasefontsize', false, editor.adjustFont),
42368 btn('decreasefontsize', false, editor.adjustFont)
42373 if(!this.disable.colors){
42376 id:editor.frameId +'-forecolor',
42377 cls:'x-btn-icon x-edit-forecolor',
42378 clickEvent:'mousedown',
42379 tooltip: this.buttonTips['forecolor'] || undefined,
42381 menu : new Roo.menu.ColorMenu({
42382 allowReselect: true,
42383 focus: Roo.emptyFn,
42386 selectHandler: function(cp, color){
42387 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
42388 editor.deferFocus();
42391 clickEvent:'mousedown'
42394 id:editor.frameId +'backcolor',
42395 cls:'x-btn-icon x-edit-backcolor',
42396 clickEvent:'mousedown',
42397 tooltip: this.buttonTips['backcolor'] || undefined,
42399 menu : new Roo.menu.ColorMenu({
42400 focus: Roo.emptyFn,
42403 allowReselect: true,
42404 selectHandler: function(cp, color){
42406 editor.execCmd('useCSS', false);
42407 editor.execCmd('hilitecolor', color);
42408 editor.execCmd('useCSS', true);
42409 editor.deferFocus();
42411 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
42412 Roo.isSafari || Roo.isIE ? '#'+color : color);
42413 editor.deferFocus();
42417 clickEvent:'mousedown'
42422 // now add all the items...
42425 if(!this.disable.alignments){
42428 btn('justifyleft'),
42429 btn('justifycenter'),
42430 btn('justifyright')
42434 //if(!Roo.isSafari){
42435 if(!this.disable.links){
42438 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
42442 if(!this.disable.lists){
42445 btn('insertorderedlist'),
42446 btn('insertunorderedlist')
42449 if(!this.disable.sourceEdit){
42452 btn('sourceedit', true, function(btn){
42453 this.toggleSourceEdit(btn.pressed);
42460 // special menu.. - needs to be tidied up..
42461 if (!this.disable.special) {
42464 cls: 'x-edit-none',
42470 for (var i =0; i < this.specialChars.length; i++) {
42471 smenu.menu.items.push({
42473 html: this.specialChars[i],
42474 handler: function(a,b) {
42475 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
42476 //editor.insertAtCursor(a.html);
42490 if (!this.disable.cleanStyles) {
42492 cls: 'x-btn-icon x-btn-clear',
42498 for (var i =0; i < this.cleanStyles.length; i++) {
42499 cmenu.menu.items.push({
42500 actiontype : this.cleanStyles[i],
42501 html: 'Remove ' + this.cleanStyles[i],
42502 handler: function(a,b) {
42505 var c = Roo.get(editor.doc.body);
42506 c.select('[style]').each(function(s) {
42507 s.dom.style.removeProperty(a.actiontype);
42518 if (!this.disable.specialElements) {
42521 cls: 'x-edit-none',
42526 for (var i =0; i < this.specialElements.length; i++) {
42527 semenu.menu.items.push(
42529 handler: function(a,b) {
42530 editor.insertAtCursor(this.ihtml);
42532 }, this.specialElements[i])
42544 for(var i =0; i< this.btns.length;i++) {
42545 var b = Roo.factory(this.btns[i],Roo.form);
42546 b.cls = 'x-edit-none';
42555 // disable everything...
42557 this.tb.items.each(function(item){
42558 if(item.id != editor.frameId+ '-sourceedit'){
42562 this.rendered = true;
42564 // the all the btns;
42565 editor.on('editorevent', this.updateToolbar, this);
42566 // other toolbars need to implement this..
42567 //editor.on('editmodechange', this.updateToolbar, this);
42573 * Protected method that will not generally be called directly. It triggers
42574 * a toolbar update by reading the markup state of the current selection in the editor.
42576 updateToolbar: function(){
42578 if(!this.editor.activated){
42579 this.editor.onFirstFocus();
42583 var btns = this.tb.items.map,
42584 doc = this.editor.doc,
42585 frameId = this.editor.frameId;
42587 if(!this.disable.font && !Roo.isSafari){
42589 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
42590 if(name != this.fontSelect.dom.value){
42591 this.fontSelect.dom.value = name;
42595 if(!this.disable.format){
42596 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
42597 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
42598 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
42600 if(!this.disable.alignments){
42601 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
42602 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
42603 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
42605 if(!Roo.isSafari && !this.disable.lists){
42606 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
42607 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
42610 var ans = this.editor.getAllAncestors();
42611 if (this.formatCombo) {
42614 var store = this.formatCombo.store;
42615 this.formatCombo.setValue("");
42616 for (var i =0; i < ans.length;i++) {
42617 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
42619 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
42627 // hides menus... - so this cant be on a menu...
42628 Roo.menu.MenuMgr.hideAll();
42630 //this.editorsyncValue();
42634 createFontOptions : function(){
42635 var buf = [], fs = this.fontFamilies, ff, lc;
42639 for(var i = 0, len = fs.length; i< len; i++){
42641 lc = ff.toLowerCase();
42643 '<option value="',lc,'" style="font-family:',ff,';"',
42644 (this.defaultFont == lc ? ' selected="true">' : '>'),
42649 return buf.join('');
42652 toggleSourceEdit : function(sourceEditMode){
42653 if(sourceEditMode === undefined){
42654 sourceEditMode = !this.sourceEditMode;
42656 this.sourceEditMode = sourceEditMode === true;
42657 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
42658 // just toggle the button?
42659 if(btn.pressed !== this.editor.sourceEditMode){
42660 btn.toggle(this.editor.sourceEditMode);
42664 if(this.sourceEditMode){
42665 this.tb.items.each(function(item){
42666 if(item.cmd != 'sourceedit'){
42672 if(this.initialized){
42673 this.tb.items.each(function(item){
42679 // tell the editor that it's been pressed..
42680 this.editor.toggleSourceEdit(sourceEditMode);
42684 * Object collection of toolbar tooltips for the buttons in the editor. The key
42685 * is the command id associated with that button and the value is a valid QuickTips object.
42690 title: 'Bold (Ctrl+B)',
42691 text: 'Make the selected text bold.',
42692 cls: 'x-html-editor-tip'
42695 title: 'Italic (Ctrl+I)',
42696 text: 'Make the selected text italic.',
42697 cls: 'x-html-editor-tip'
42705 title: 'Bold (Ctrl+B)',
42706 text: 'Make the selected text bold.',
42707 cls: 'x-html-editor-tip'
42710 title: 'Italic (Ctrl+I)',
42711 text: 'Make the selected text italic.',
42712 cls: 'x-html-editor-tip'
42715 title: 'Underline (Ctrl+U)',
42716 text: 'Underline the selected text.',
42717 cls: 'x-html-editor-tip'
42719 increasefontsize : {
42720 title: 'Grow Text',
42721 text: 'Increase the font size.',
42722 cls: 'x-html-editor-tip'
42724 decreasefontsize : {
42725 title: 'Shrink Text',
42726 text: 'Decrease the font size.',
42727 cls: 'x-html-editor-tip'
42730 title: 'Text Highlight Color',
42731 text: 'Change the background color of the selected text.',
42732 cls: 'x-html-editor-tip'
42735 title: 'Font Color',
42736 text: 'Change the color of the selected text.',
42737 cls: 'x-html-editor-tip'
42740 title: 'Align Text Left',
42741 text: 'Align text to the left.',
42742 cls: 'x-html-editor-tip'
42745 title: 'Center Text',
42746 text: 'Center text in the editor.',
42747 cls: 'x-html-editor-tip'
42750 title: 'Align Text Right',
42751 text: 'Align text to the right.',
42752 cls: 'x-html-editor-tip'
42754 insertunorderedlist : {
42755 title: 'Bullet List',
42756 text: 'Start a bulleted list.',
42757 cls: 'x-html-editor-tip'
42759 insertorderedlist : {
42760 title: 'Numbered List',
42761 text: 'Start a numbered list.',
42762 cls: 'x-html-editor-tip'
42765 title: 'Hyperlink',
42766 text: 'Make the selected text a hyperlink.',
42767 cls: 'x-html-editor-tip'
42770 title: 'Source Edit',
42771 text: 'Switch to source editing mode.',
42772 cls: 'x-html-editor-tip'
42776 onDestroy : function(){
42779 this.tb.items.each(function(item){
42781 item.menu.removeAll();
42783 item.menu.el.destroy();
42791 onFirstFocus: function() {
42792 this.tb.items.each(function(item){
42801 // <script type="text/javascript">
42804 * Ext JS Library 1.1.1
42805 * Copyright(c) 2006-2007, Ext JS, LLC.
42812 * @class Roo.form.HtmlEditor.ToolbarContext
42817 new Roo.form.HtmlEditor({
42820 { xtype: 'ToolbarStandard', styles : {} }
42821 { xtype: 'ToolbarContext', disable : {} }
42827 * @config : {Object} disable List of elements to disable.. (not done yet.)
42828 * @config : {Object} styles Map of styles available.
42832 Roo.form.HtmlEditor.ToolbarContext = function(config)
42835 Roo.apply(this, config);
42836 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42837 // dont call parent... till later.
42838 this.styles = this.styles || {};
42843 Roo.form.HtmlEditor.ToolbarContext.types = {
42855 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42921 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
42926 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
42936 style : 'fontFamily',
42937 displayField: 'display',
42938 optname : 'font-family',
42987 // should we really allow this??
42988 // should this just be
42999 style : 'fontFamily',
43000 displayField: 'display',
43001 optname : 'font-family',
43008 style : 'fontFamily',
43009 displayField: 'display',
43010 optname : 'font-family',
43017 style : 'fontFamily',
43018 displayField: 'display',
43019 optname : 'font-family',
43030 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43031 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43033 Roo.form.HtmlEditor.ToolbarContext.options = {
43035 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43036 [ 'Courier New', 'Courier New'],
43037 [ 'Tahoma', 'Tahoma'],
43038 [ 'Times New Roman,serif', 'Times'],
43039 [ 'Verdana','Verdana' ]
43043 // fixme - these need to be configurable..
43046 Roo.form.HtmlEditor.ToolbarContext.types
43049 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43057 * @cfg {Object} disable List of toolbar elements to disable
43062 * @cfg {Object} styles List of styles
43063 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43065 * These must be defined in the page, so they get rendered correctly..
43076 init : function(editor)
43078 this.editor = editor;
43081 var fid = editor.frameId;
43083 function btn(id, toggle, handler){
43084 var xid = fid + '-'+ id ;
43088 cls : 'x-btn-icon x-edit-'+id,
43089 enableToggle:toggle !== false,
43090 scope: editor, // was editor...
43091 handler:handler||editor.relayBtnCmd,
43092 clickEvent:'mousedown',
43093 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43097 // create a new element.
43098 var wdiv = editor.wrap.createChild({
43100 }, editor.wrap.dom.firstChild.nextSibling, true);
43102 // can we do this more than once??
43104 // stop form submits
43107 // disable everything...
43108 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43109 this.toolbars = {};
43111 for (var i in ty) {
43113 this.toolbars[i] = this.buildToolbar(ty[i],i);
43115 this.tb = this.toolbars.BODY;
43117 this.buildFooter();
43118 this.footer.show();
43119 editor.on('hide', function( ) { this.footer.hide() }, this);
43120 editor.on('show', function( ) { this.footer.show() }, this);
43123 this.rendered = true;
43125 // the all the btns;
43126 editor.on('editorevent', this.updateToolbar, this);
43127 // other toolbars need to implement this..
43128 //editor.on('editmodechange', this.updateToolbar, this);
43134 * Protected method that will not generally be called directly. It triggers
43135 * a toolbar update by reading the markup state of the current selection in the editor.
43137 updateToolbar: function(editor,ev,sel){
43140 // capture mouse up - this is handy for selecting images..
43141 // perhaps should go somewhere else...
43142 if(!this.editor.activated){
43143 this.editor.onFirstFocus();
43147 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43148 // selectNode - might want to handle IE?
43150 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43151 ev.target && ev.target.tagName == 'IMG') {
43152 // they have click on an image...
43153 // let's see if we can change the selection...
43156 var nodeRange = sel.ownerDocument.createRange();
43158 nodeRange.selectNode(sel);
43160 nodeRange.selectNodeContents(sel);
43162 //nodeRange.collapse(true);
43163 var s = editor.win.getSelection();
43164 s.removeAllRanges();
43165 s.addRange(nodeRange);
43169 var updateFooter = sel ? false : true;
43172 var ans = this.editor.getAllAncestors();
43175 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43178 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
43179 sel = sel ? sel : this.editor.doc.body;
43180 sel = sel.tagName.length ? sel : this.editor.doc.body;
43183 // pick a menu that exists..
43184 var tn = sel.tagName.toUpperCase();
43185 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43187 tn = sel.tagName.toUpperCase();
43189 var lastSel = this.tb.selectedNode
43191 this.tb.selectedNode = sel;
43193 // if current menu does not match..
43194 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43197 ///console.log("show: " + tn);
43198 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43201 this.tb.items.first().el.innerHTML = tn + ': ';
43204 // update attributes
43205 if (this.tb.fields) {
43206 this.tb.fields.each(function(e) {
43208 e.setValue(sel.style[e.stylename]);
43211 e.setValue(sel.getAttribute(e.attrname));
43215 var hasStyles = false;
43216 for(var i in this.styles) {
43223 var st = this.tb.fields.item(0);
43225 st.store.removeAll();
43228 var cn = sel.className.split(/\s+/);
43231 if (this.styles['*']) {
43233 Roo.each(this.styles['*'], function(v) {
43234 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43237 if (this.styles[tn]) {
43238 Roo.each(this.styles[tn], function(v) {
43239 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43243 st.store.loadData(avs);
43247 // flag our selected Node.
43248 this.tb.selectedNode = sel;
43251 Roo.menu.MenuMgr.hideAll();
43255 if (!updateFooter) {
43256 //this.footDisp.dom.innerHTML = '';
43259 // update the footer
43263 this.footerEls = ans.reverse();
43264 Roo.each(this.footerEls, function(a,i) {
43265 if (!a) { return; }
43266 html += html.length ? ' > ' : '';
43268 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
43273 var sz = this.footDisp.up('td').getSize();
43274 this.footDisp.dom.style.width = (sz.width -10) + 'px';
43275 this.footDisp.dom.style.marginLeft = '5px';
43277 this.footDisp.dom.style.overflow = 'hidden';
43279 this.footDisp.dom.innerHTML = html;
43281 //this.editorsyncValue();
43288 onDestroy : function(){
43291 this.tb.items.each(function(item){
43293 item.menu.removeAll();
43295 item.menu.el.destroy();
43303 onFirstFocus: function() {
43304 // need to do this for all the toolbars..
43305 this.tb.items.each(function(item){
43309 buildToolbar: function(tlist, nm)
43311 var editor = this.editor;
43312 // create a new element.
43313 var wdiv = editor.wrap.createChild({
43315 }, editor.wrap.dom.firstChild.nextSibling, true);
43318 var tb = new Roo.Toolbar(wdiv);
43321 tb.add(nm+ ": ");
43324 for(var i in this.styles) {
43329 if (styles && styles.length) {
43331 // this needs a multi-select checkbox...
43332 tb.addField( new Roo.form.ComboBox({
43333 store: new Roo.data.SimpleStore({
43335 fields: ['val', 'selected'],
43338 name : '-roo-edit-className',
43339 attrname : 'className',
43340 displayField: 'val',
43344 triggerAction: 'all',
43345 emptyText:'Select Style',
43346 selectOnFocus:true,
43349 'select': function(c, r, i) {
43350 // initial support only for on class per el..
43351 tb.selectedNode.className = r ? r.get('val') : '';
43352 editor.syncValue();
43359 var tbc = Roo.form.HtmlEditor.ToolbarContext;
43360 var tbops = tbc.options;
43362 for (var i in tlist) {
43364 var item = tlist[i];
43365 tb.add(item.title + ": ");
43368 //optname == used so you can configure the options available..
43369 var opts = item.opts ? item.opts : false;
43370 if (item.optname) {
43371 opts = tbops[item.optname];
43376 // opts == pulldown..
43377 tb.addField( new Roo.form.ComboBox({
43378 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
43380 fields: ['val', 'display'],
43383 name : '-roo-edit-' + i,
43385 stylename : item.style ? item.style : false,
43386 displayField: item.displayField ? item.displayField : 'val',
43387 valueField : 'val',
43389 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
43391 triggerAction: 'all',
43392 emptyText:'Select',
43393 selectOnFocus:true,
43394 width: item.width ? item.width : 130,
43396 'select': function(c, r, i) {
43398 tb.selectedNode.style[c.stylename] = r.get('val');
43401 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
43410 tb.addField( new Roo.form.TextField({
43413 //allowBlank:false,
43418 tb.addField( new Roo.form.TextField({
43419 name: '-roo-edit-' + i,
43426 'change' : function(f, nv, ov) {
43427 tb.selectedNode.setAttribute(f.attrname, nv);
43436 text: 'Remove Tag',
43439 click : function ()
43442 // undo does not work.
43444 var sn = tb.selectedNode;
43446 var pn = sn.parentNode;
43448 var stn = sn.childNodes[0];
43449 var en = sn.childNodes[sn.childNodes.length - 1 ];
43450 while (sn.childNodes.length) {
43451 var node = sn.childNodes[0];
43452 sn.removeChild(node);
43454 pn.insertBefore(node, sn);
43457 pn.removeChild(sn);
43458 var range = editor.createRange();
43460 range.setStart(stn,0);
43461 range.setEnd(en,0); //????
43462 //range.selectNode(sel);
43465 var selection = editor.getSelection();
43466 selection.removeAllRanges();
43467 selection.addRange(range);
43471 //_this.updateToolbar(null, null, pn);
43472 _this.updateToolbar(null, null, null);
43473 _this.footDisp.dom.innerHTML = '';
43483 tb.el.on('click', function(e){
43484 e.preventDefault(); // what does this do?
43486 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
43489 // dont need to disable them... as they will get hidden
43494 buildFooter : function()
43497 var fel = this.editor.wrap.createChild();
43498 this.footer = new Roo.Toolbar(fel);
43499 // toolbar has scrolly on left / right?
43500 var footDisp= new Roo.Toolbar.Fill();
43506 handler : function() {
43507 _t.footDisp.scrollTo('left',0,true)
43511 this.footer.add( footDisp );
43516 handler : function() {
43518 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
43522 var fel = Roo.get(footDisp.el);
43523 fel.addClass('x-editor-context');
43524 this.footDispWrap = fel;
43525 this.footDispWrap.overflow = 'hidden';
43527 this.footDisp = fel.createChild();
43528 this.footDispWrap.on('click', this.onContextClick, this)
43532 onContextClick : function (ev,dom)
43534 ev.preventDefault();
43535 var cn = dom.className;
43537 if (!cn.match(/x-ed-loc-/)) {
43540 var n = cn.split('-').pop();
43541 var ans = this.footerEls;
43545 var range = this.editor.createRange();
43547 range.selectNodeContents(sel);
43548 //range.selectNode(sel);
43551 var selection = this.editor.getSelection();
43552 selection.removeAllRanges();
43553 selection.addRange(range);
43557 this.updateToolbar(null, null, sel);
43574 * Ext JS Library 1.1.1
43575 * Copyright(c) 2006-2007, Ext JS, LLC.
43577 * Originally Released Under LGPL - original licence link has changed is not relivant.
43580 * <script type="text/javascript">
43584 * @class Roo.form.BasicForm
43585 * @extends Roo.util.Observable
43586 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
43588 * @param {String/HTMLElement/Roo.Element} el The form element or its id
43589 * @param {Object} config Configuration options
43591 Roo.form.BasicForm = function(el, config){
43592 this.allItems = [];
43593 this.childForms = [];
43594 Roo.apply(this, config);
43596 * The Roo.form.Field items in this form.
43597 * @type MixedCollection
43601 this.items = new Roo.util.MixedCollection(false, function(o){
43602 return o.id || (o.id = Roo.id());
43606 * @event beforeaction
43607 * Fires before any action is performed. Return false to cancel the action.
43608 * @param {Form} this
43609 * @param {Action} action The action to be performed
43611 beforeaction: true,
43613 * @event actionfailed
43614 * Fires when an action fails.
43615 * @param {Form} this
43616 * @param {Action} action The action that failed
43618 actionfailed : true,
43620 * @event actioncomplete
43621 * Fires when an action is completed.
43622 * @param {Form} this
43623 * @param {Action} action The action that completed
43625 actioncomplete : true
43630 Roo.form.BasicForm.superclass.constructor.call(this);
43633 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
43635 * @cfg {String} method
43636 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
43639 * @cfg {DataReader} reader
43640 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
43641 * This is optional as there is built-in support for processing JSON.
43644 * @cfg {DataReader} errorReader
43645 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
43646 * This is completely optional as there is built-in support for processing JSON.
43649 * @cfg {String} url
43650 * The URL to use for form actions if one isn't supplied in the action options.
43653 * @cfg {Boolean} fileUpload
43654 * Set to true if this form is a file upload.
43658 * @cfg {Object} baseParams
43659 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
43664 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
43669 activeAction : null,
43672 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
43673 * or setValues() data instead of when the form was first created.
43675 trackResetOnLoad : false,
43679 * childForms - used for multi-tab forms
43682 childForms : false,
43685 * allItems - full list of fields.
43691 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
43692 * element by passing it or its id or mask the form itself by passing in true.
43695 waitMsgTarget : false,
43698 initEl : function(el){
43699 this.el = Roo.get(el);
43700 this.id = this.el.id || Roo.id();
43701 this.el.on('submit', this.onSubmit, this);
43702 this.el.addClass('x-form');
43706 onSubmit : function(e){
43711 * Returns true if client-side validation on the form is successful.
43714 isValid : function(){
43716 this.items.each(function(f){
43725 * Returns true if any fields in this form have changed since their original load.
43728 isDirty : function(){
43730 this.items.each(function(f){
43740 * Performs a predefined action (submit or load) or custom actions you define on this form.
43741 * @param {String} actionName The name of the action type
43742 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
43743 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
43744 * accept other config options):
43746 Property Type Description
43747 ---------------- --------------- ----------------------------------------------------------------------------------
43748 url String The url for the action (defaults to the form's url)
43749 method String The form method to use (defaults to the form's method, or POST if not defined)
43750 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
43751 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
43752 validate the form on the client (defaults to false)
43754 * @return {BasicForm} this
43756 doAction : function(action, options){
43757 if(typeof action == 'string'){
43758 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
43760 if(this.fireEvent('beforeaction', this, action) !== false){
43761 this.beforeAction(action);
43762 action.run.defer(100, action);
43768 * Shortcut to do a submit action.
43769 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43770 * @return {BasicForm} this
43772 submit : function(options){
43773 this.doAction('submit', options);
43778 * Shortcut to do a load action.
43779 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43780 * @return {BasicForm} this
43782 load : function(options){
43783 this.doAction('load', options);
43788 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
43789 * @param {Record} record The record to edit
43790 * @return {BasicForm} this
43792 updateRecord : function(record){
43793 record.beginEdit();
43794 var fs = record.fields;
43795 fs.each(function(f){
43796 var field = this.findField(f.name);
43798 record.set(f.name, field.getValue());
43806 * Loads an Roo.data.Record into this form.
43807 * @param {Record} record The record to load
43808 * @return {BasicForm} this
43810 loadRecord : function(record){
43811 this.setValues(record.data);
43816 beforeAction : function(action){
43817 var o = action.options;
43820 if(this.waitMsgTarget === true){
43821 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
43822 }else if(this.waitMsgTarget){
43823 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
43824 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
43826 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
43832 afterAction : function(action, success){
43833 this.activeAction = null;
43834 var o = action.options;
43836 if(this.waitMsgTarget === true){
43838 }else if(this.waitMsgTarget){
43839 this.waitMsgTarget.unmask();
43841 Roo.MessageBox.updateProgress(1);
43842 Roo.MessageBox.hide();
43849 Roo.callback(o.success, o.scope, [this, action]);
43850 this.fireEvent('actioncomplete', this, action);
43854 // failure condition..
43855 // we have a scenario where updates need confirming.
43856 // eg. if a locking scenario exists..
43857 // we look for { errors : { needs_confirm : true }} in the response.
43859 (typeof(action.result) != 'undefined') &&
43860 (typeof(action.result.errors) != 'undefined') &&
43861 (typeof(action.result.errors.needs_confirm) != 'undefined')
43864 Roo.MessageBox.confirm(
43865 "Change requires confirmation",
43866 action.result.errorMsg,
43871 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
43881 Roo.callback(o.failure, o.scope, [this, action]);
43882 // show an error message if no failed handler is set..
43883 if (!this.hasListener('actionfailed')) {
43884 Roo.MessageBox.alert("Error",
43885 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
43886 action.result.errorMsg :
43887 "Saving Failed, please check your entries or try again"
43891 this.fireEvent('actionfailed', this, action);
43897 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
43898 * @param {String} id The value to search for
43901 findField : function(id){
43902 var field = this.items.get(id);
43904 this.items.each(function(f){
43905 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
43911 return field || null;
43915 * Add a secondary form to this one,
43916 * Used to provide tabbed forms. One form is primary, with hidden values
43917 * which mirror the elements from the other forms.
43919 * @param {Roo.form.Form} form to add.
43922 addForm : function(form)
43925 if (this.childForms.indexOf(form) > -1) {
43929 this.childForms.push(form);
43931 Roo.each(form.allItems, function (fe) {
43933 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
43934 if (this.findField(n)) { // already added..
43937 var add = new Roo.form.Hidden({
43940 add.render(this.el);
43947 * Mark fields in this form invalid in bulk.
43948 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
43949 * @return {BasicForm} this
43951 markInvalid : function(errors){
43952 if(errors instanceof Array){
43953 for(var i = 0, len = errors.length; i < len; i++){
43954 var fieldError = errors[i];
43955 var f = this.findField(fieldError.id);
43957 f.markInvalid(fieldError.msg);
43963 if(typeof errors[id] != 'function' && (field = this.findField(id))){
43964 field.markInvalid(errors[id]);
43968 Roo.each(this.childForms || [], function (f) {
43969 f.markInvalid(errors);
43976 * Set values for fields in this form in bulk.
43977 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
43978 * @return {BasicForm} this
43980 setValues : function(values){
43981 if(values instanceof Array){ // array of objects
43982 for(var i = 0, len = values.length; i < len; i++){
43984 var f = this.findField(v.id);
43986 f.setValue(v.value);
43987 if(this.trackResetOnLoad){
43988 f.originalValue = f.getValue();
43992 }else{ // object hash
43995 if(typeof values[id] != 'function' && (field = this.findField(id))){
43997 if (field.setFromData &&
43998 field.valueField &&
43999 field.displayField &&
44000 // combos' with local stores can
44001 // be queried via setValue()
44002 // to set their value..
44003 (field.store && !field.store.isLocal)
44007 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44008 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44009 field.setFromData(sd);
44012 field.setValue(values[id]);
44016 if(this.trackResetOnLoad){
44017 field.originalValue = field.getValue();
44023 Roo.each(this.childForms || [], function (f) {
44024 f.setValues(values);
44031 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44032 * they are returned as an array.
44033 * @param {Boolean} asString
44036 getValues : function(asString){
44037 if (this.childForms) {
44038 // copy values from the child forms
44039 Roo.each(this.childForms, function (f) {
44040 this.setValues(f.getValues());
44046 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44047 if(asString === true){
44050 return Roo.urlDecode(fs);
44054 * Returns the fields in this form as an object with key/value pairs.
44055 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44058 getFieldValues : function(with_hidden)
44060 if (this.childForms) {
44061 // copy values from the child forms
44062 // should this call getFieldValues - probably not as we do not currently copy
44063 // hidden fields when we generate..
44064 Roo.each(this.childForms, function (f) {
44065 this.setValues(f.getValues());
44070 this.items.each(function(f){
44071 if (!f.getName()) {
44074 var v = f.getValue();
44075 if (f.inputType =='radio') {
44076 if (typeof(ret[f.getName()]) == 'undefined') {
44077 ret[f.getName()] = ''; // empty..
44080 if (!f.el.dom.checked) {
44084 v = f.el.dom.value;
44088 // not sure if this supported any more..
44089 if ((typeof(v) == 'object') && f.getRawValue) {
44090 v = f.getRawValue() ; // dates..
44092 // combo boxes where name != hiddenName...
44093 if (f.name != f.getName()) {
44094 ret[f.name] = f.getRawValue();
44096 ret[f.getName()] = v;
44103 * Clears all invalid messages in this form.
44104 * @return {BasicForm} this
44106 clearInvalid : function(){
44107 this.items.each(function(f){
44111 Roo.each(this.childForms || [], function (f) {
44120 * Resets this form.
44121 * @return {BasicForm} this
44123 reset : function(){
44124 this.items.each(function(f){
44128 Roo.each(this.childForms || [], function (f) {
44137 * Add Roo.form components to this form.
44138 * @param {Field} field1
44139 * @param {Field} field2 (optional)
44140 * @param {Field} etc (optional)
44141 * @return {BasicForm} this
44144 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44150 * Removes a field from the items collection (does NOT remove its markup).
44151 * @param {Field} field
44152 * @return {BasicForm} this
44154 remove : function(field){
44155 this.items.remove(field);
44160 * Looks at the fields in this form, checks them for an id attribute,
44161 * and calls applyTo on the existing dom element with that id.
44162 * @return {BasicForm} this
44164 render : function(){
44165 this.items.each(function(f){
44166 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44174 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44175 * @param {Object} values
44176 * @return {BasicForm} this
44178 applyToFields : function(o){
44179 this.items.each(function(f){
44186 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44187 * @param {Object} values
44188 * @return {BasicForm} this
44190 applyIfToFields : function(o){
44191 this.items.each(function(f){
44199 Roo.BasicForm = Roo.form.BasicForm;/*
44201 * Ext JS Library 1.1.1
44202 * Copyright(c) 2006-2007, Ext JS, LLC.
44204 * Originally Released Under LGPL - original licence link has changed is not relivant.
44207 * <script type="text/javascript">
44211 * @class Roo.form.Form
44212 * @extends Roo.form.BasicForm
44213 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44215 * @param {Object} config Configuration options
44217 Roo.form.Form = function(config){
44219 if (config.items) {
44220 xitems = config.items;
44221 delete config.items;
44225 Roo.form.Form.superclass.constructor.call(this, null, config);
44226 this.url = this.url || this.action;
44228 this.root = new Roo.form.Layout(Roo.applyIf({
44232 this.active = this.root;
44234 * Array of all the buttons that have been added to this form via {@link addButton}
44238 this.allItems = [];
44241 * @event clientvalidation
44242 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
44243 * @param {Form} this
44244 * @param {Boolean} valid true if the form has passed client-side validation
44246 clientvalidation: true,
44249 * Fires when the form is rendered
44250 * @param {Roo.form.Form} form
44255 if (this.progressUrl) {
44256 // push a hidden field onto the list of fields..
44260 name : 'UPLOAD_IDENTIFIER'
44265 Roo.each(xitems, this.addxtype, this);
44271 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
44273 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
44276 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
44279 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
44281 buttonAlign:'center',
44284 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
44289 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
44290 * This property cascades to child containers if not set.
44295 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
44296 * fires a looping event with that state. This is required to bind buttons to the valid
44297 * state using the config value formBind:true on the button.
44299 monitorValid : false,
44302 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
44307 * @cfg {String} progressUrl - Url to return progress data
44310 progressUrl : false,
44313 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
44314 * fields are added and the column is closed. If no fields are passed the column remains open
44315 * until end() is called.
44316 * @param {Object} config The config to pass to the column
44317 * @param {Field} field1 (optional)
44318 * @param {Field} field2 (optional)
44319 * @param {Field} etc (optional)
44320 * @return Column The column container object
44322 column : function(c){
44323 var col = new Roo.form.Column(c);
44325 if(arguments.length > 1){ // duplicate code required because of Opera
44326 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44333 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
44334 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
44335 * until end() is called.
44336 * @param {Object} config The config to pass to the fieldset
44337 * @param {Field} field1 (optional)
44338 * @param {Field} field2 (optional)
44339 * @param {Field} etc (optional)
44340 * @return FieldSet The fieldset container object
44342 fieldset : function(c){
44343 var fs = new Roo.form.FieldSet(c);
44345 if(arguments.length > 1){ // duplicate code required because of Opera
44346 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44353 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
44354 * fields are added and the container is closed. If no fields are passed the container remains open
44355 * until end() is called.
44356 * @param {Object} config The config to pass to the Layout
44357 * @param {Field} field1 (optional)
44358 * @param {Field} field2 (optional)
44359 * @param {Field} etc (optional)
44360 * @return Layout The container object
44362 container : function(c){
44363 var l = new Roo.form.Layout(c);
44365 if(arguments.length > 1){ // duplicate code required because of Opera
44366 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44373 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
44374 * @param {Object} container A Roo.form.Layout or subclass of Layout
44375 * @return {Form} this
44377 start : function(c){
44378 // cascade label info
44379 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
44380 this.active.stack.push(c);
44381 c.ownerCt = this.active;
44387 * Closes the current open container
44388 * @return {Form} this
44391 if(this.active == this.root){
44394 this.active = this.active.ownerCt;
44399 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
44400 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
44401 * as the label of the field.
44402 * @param {Field} field1
44403 * @param {Field} field2 (optional)
44404 * @param {Field} etc. (optional)
44405 * @return {Form} this
44408 this.active.stack.push.apply(this.active.stack, arguments);
44409 this.allItems.push.apply(this.allItems,arguments);
44411 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
44412 if(a[i].isFormField){
44417 Roo.form.Form.superclass.add.apply(this, r);
44427 * Find any element that has been added to a form, using it's ID or name
44428 * This can include framesets, columns etc. along with regular fields..
44429 * @param {String} id - id or name to find.
44431 * @return {Element} e - or false if nothing found.
44433 findbyId : function(id)
44439 Roo.each(this.allItems, function(f){
44440 if (f.id == id || f.name == id ){
44451 * Render this form into the passed container. This should only be called once!
44452 * @param {String/HTMLElement/Element} container The element this component should be rendered into
44453 * @return {Form} this
44455 render : function(ct)
44461 var o = this.autoCreate || {
44463 method : this.method || 'POST',
44464 id : this.id || Roo.id()
44466 this.initEl(ct.createChild(o));
44468 this.root.render(this.el);
44472 this.items.each(function(f){
44473 f.render('x-form-el-'+f.id);
44476 if(this.buttons.length > 0){
44477 // tables are required to maintain order and for correct IE layout
44478 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
44479 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
44480 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
44482 var tr = tb.getElementsByTagName('tr')[0];
44483 for(var i = 0, len = this.buttons.length; i < len; i++) {
44484 var b = this.buttons[i];
44485 var td = document.createElement('td');
44486 td.className = 'x-form-btn-td';
44487 b.render(tr.appendChild(td));
44490 if(this.monitorValid){ // initialize after render
44491 this.startMonitoring();
44493 this.fireEvent('rendered', this);
44498 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
44499 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
44500 * object or a valid Roo.DomHelper element config
44501 * @param {Function} handler The function called when the button is clicked
44502 * @param {Object} scope (optional) The scope of the handler function
44503 * @return {Roo.Button}
44505 addButton : function(config, handler, scope){
44509 minWidth: this.minButtonWidth,
44512 if(typeof config == "string"){
44515 Roo.apply(bc, config);
44517 var btn = new Roo.Button(null, bc);
44518 this.buttons.push(btn);
44523 * Adds a series of form elements (using the xtype property as the factory method.
44524 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
44525 * @param {Object} config
44528 addxtype : function()
44530 var ar = Array.prototype.slice.call(arguments, 0);
44532 for(var i = 0; i < ar.length; i++) {
44534 continue; // skip -- if this happends something invalid got sent, we
44535 // should ignore it, as basically that interface element will not show up
44536 // and that should be pretty obvious!!
44539 if (Roo.form[ar[i].xtype]) {
44541 var fe = Roo.factory(ar[i], Roo.form);
44547 fe.store.form = this;
44552 this.allItems.push(fe);
44553 if (fe.items && fe.addxtype) {
44554 fe.addxtype.apply(fe, fe.items);
44564 // console.log('adding ' + ar[i].xtype);
44566 if (ar[i].xtype == 'Button') {
44567 //console.log('adding button');
44568 //console.log(ar[i]);
44569 this.addButton(ar[i]);
44570 this.allItems.push(fe);
44574 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
44575 alert('end is not supported on xtype any more, use items');
44577 // //console.log('adding end');
44585 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
44586 * option "monitorValid"
44588 startMonitoring : function(){
44591 Roo.TaskMgr.start({
44592 run : this.bindHandler,
44593 interval : this.monitorPoll || 200,
44600 * Stops monitoring of the valid state of this form
44602 stopMonitoring : function(){
44603 this.bound = false;
44607 bindHandler : function(){
44609 return false; // stops binding
44612 this.items.each(function(f){
44613 if(!f.isValid(true)){
44618 for(var i = 0, len = this.buttons.length; i < len; i++){
44619 var btn = this.buttons[i];
44620 if(btn.formBind === true && btn.disabled === valid){
44621 btn.setDisabled(!valid);
44624 this.fireEvent('clientvalidation', this, valid);
44638 Roo.Form = Roo.form.Form;
44641 * Ext JS Library 1.1.1
44642 * Copyright(c) 2006-2007, Ext JS, LLC.
44644 * Originally Released Under LGPL - original licence link has changed is not relivant.
44647 * <script type="text/javascript">
44651 * @class Roo.form.Action
44652 * Internal Class used to handle form actions
44654 * @param {Roo.form.BasicForm} el The form element or its id
44655 * @param {Object} config Configuration options
44659 // define the action interface
44660 Roo.form.Action = function(form, options){
44662 this.options = options || {};
44665 * Client Validation Failed
44668 Roo.form.Action.CLIENT_INVALID = 'client';
44670 * Server Validation Failed
44673 Roo.form.Action.SERVER_INVALID = 'server';
44675 * Connect to Server Failed
44678 Roo.form.Action.CONNECT_FAILURE = 'connect';
44680 * Reading Data from Server Failed
44683 Roo.form.Action.LOAD_FAILURE = 'load';
44685 Roo.form.Action.prototype = {
44687 failureType : undefined,
44688 response : undefined,
44689 result : undefined,
44691 // interface method
44692 run : function(options){
44696 // interface method
44697 success : function(response){
44701 // interface method
44702 handleResponse : function(response){
44706 // default connection failure
44707 failure : function(response){
44709 this.response = response;
44710 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44711 this.form.afterAction(this, false);
44714 processResponse : function(response){
44715 this.response = response;
44716 if(!response.responseText){
44719 this.result = this.handleResponse(response);
44720 return this.result;
44723 // utility functions used internally
44724 getUrl : function(appendParams){
44725 var url = this.options.url || this.form.url || this.form.el.dom.action;
44727 var p = this.getParams();
44729 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
44735 getMethod : function(){
44736 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
44739 getParams : function(){
44740 var bp = this.form.baseParams;
44741 var p = this.options.params;
44743 if(typeof p == "object"){
44744 p = Roo.urlEncode(Roo.applyIf(p, bp));
44745 }else if(typeof p == 'string' && bp){
44746 p += '&' + Roo.urlEncode(bp);
44749 p = Roo.urlEncode(bp);
44754 createCallback : function(){
44756 success: this.success,
44757 failure: this.failure,
44759 timeout: (this.form.timeout*1000),
44760 upload: this.form.fileUpload ? this.success : undefined
44765 Roo.form.Action.Submit = function(form, options){
44766 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
44769 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
44772 haveProgress : false,
44773 uploadComplete : false,
44775 // uploadProgress indicator.
44776 uploadProgress : function()
44778 if (!this.form.progressUrl) {
44782 if (!this.haveProgress) {
44783 Roo.MessageBox.progress("Uploading", "Uploading");
44785 if (this.uploadComplete) {
44786 Roo.MessageBox.hide();
44790 this.haveProgress = true;
44792 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
44794 var c = new Roo.data.Connection();
44796 url : this.form.progressUrl,
44801 success : function(req){
44802 //console.log(data);
44806 rdata = Roo.decode(req.responseText)
44808 Roo.log("Invalid data from server..");
44812 if (!rdata || !rdata.success) {
44814 Roo.MessageBox.alert(Roo.encode(rdata));
44817 var data = rdata.data;
44819 if (this.uploadComplete) {
44820 Roo.MessageBox.hide();
44825 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
44826 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
44829 this.uploadProgress.defer(2000,this);
44832 failure: function(data) {
44833 Roo.log('progress url failed ');
44844 // run get Values on the form, so it syncs any secondary forms.
44845 this.form.getValues();
44847 var o = this.options;
44848 var method = this.getMethod();
44849 var isPost = method == 'POST';
44850 if(o.clientValidation === false || this.form.isValid()){
44852 if (this.form.progressUrl) {
44853 this.form.findField('UPLOAD_IDENTIFIER').setValue(
44854 (new Date() * 1) + '' + Math.random());
44859 Roo.Ajax.request(Roo.apply(this.createCallback(), {
44860 form:this.form.el.dom,
44861 url:this.getUrl(!isPost),
44863 params:isPost ? this.getParams() : null,
44864 isUpload: this.form.fileUpload
44867 this.uploadProgress();
44869 }else if (o.clientValidation !== false){ // client validation failed
44870 this.failureType = Roo.form.Action.CLIENT_INVALID;
44871 this.form.afterAction(this, false);
44875 success : function(response)
44877 this.uploadComplete= true;
44878 if (this.haveProgress) {
44879 Roo.MessageBox.hide();
44883 var result = this.processResponse(response);
44884 if(result === true || result.success){
44885 this.form.afterAction(this, true);
44889 this.form.markInvalid(result.errors);
44890 this.failureType = Roo.form.Action.SERVER_INVALID;
44892 this.form.afterAction(this, false);
44894 failure : function(response)
44896 this.uploadComplete= true;
44897 if (this.haveProgress) {
44898 Roo.MessageBox.hide();
44901 this.response = response;
44902 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44903 this.form.afterAction(this, false);
44906 handleResponse : function(response){
44907 if(this.form.errorReader){
44908 var rs = this.form.errorReader.read(response);
44911 for(var i = 0, len = rs.records.length; i < len; i++) {
44912 var r = rs.records[i];
44913 errors[i] = r.data;
44916 if(errors.length < 1){
44920 success : rs.success,
44926 ret = Roo.decode(response.responseText);
44930 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
44940 Roo.form.Action.Load = function(form, options){
44941 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
44942 this.reader = this.form.reader;
44945 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
44950 Roo.Ajax.request(Roo.apply(
44951 this.createCallback(), {
44952 method:this.getMethod(),
44953 url:this.getUrl(false),
44954 params:this.getParams()
44958 success : function(response){
44960 var result = this.processResponse(response);
44961 if(result === true || !result.success || !result.data){
44962 this.failureType = Roo.form.Action.LOAD_FAILURE;
44963 this.form.afterAction(this, false);
44966 this.form.clearInvalid();
44967 this.form.setValues(result.data);
44968 this.form.afterAction(this, true);
44971 handleResponse : function(response){
44972 if(this.form.reader){
44973 var rs = this.form.reader.read(response);
44974 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
44976 success : rs.success,
44980 return Roo.decode(response.responseText);
44984 Roo.form.Action.ACTION_TYPES = {
44985 'load' : Roo.form.Action.Load,
44986 'submit' : Roo.form.Action.Submit
44989 * Ext JS Library 1.1.1
44990 * Copyright(c) 2006-2007, Ext JS, LLC.
44992 * Originally Released Under LGPL - original licence link has changed is not relivant.
44995 * <script type="text/javascript">
44999 * @class Roo.form.Layout
45000 * @extends Roo.Component
45001 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45003 * @param {Object} config Configuration options
45005 Roo.form.Layout = function(config){
45007 if (config.items) {
45008 xitems = config.items;
45009 delete config.items;
45011 Roo.form.Layout.superclass.constructor.call(this, config);
45013 Roo.each(xitems, this.addxtype, this);
45017 Roo.extend(Roo.form.Layout, Roo.Component, {
45019 * @cfg {String/Object} autoCreate
45020 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45023 * @cfg {String/Object/Function} style
45024 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45025 * a function which returns such a specification.
45028 * @cfg {String} labelAlign
45029 * Valid values are "left," "top" and "right" (defaults to "left")
45032 * @cfg {Number} labelWidth
45033 * Fixed width in pixels of all field labels (defaults to undefined)
45036 * @cfg {Boolean} clear
45037 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45041 * @cfg {String} labelSeparator
45042 * The separator to use after field labels (defaults to ':')
45044 labelSeparator : ':',
45046 * @cfg {Boolean} hideLabels
45047 * True to suppress the display of field labels in this layout (defaults to false)
45049 hideLabels : false,
45052 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45057 onRender : function(ct, position){
45058 if(this.el){ // from markup
45059 this.el = Roo.get(this.el);
45060 }else { // generate
45061 var cfg = this.getAutoCreate();
45062 this.el = ct.createChild(cfg, position);
45065 this.el.applyStyles(this.style);
45067 if(this.labelAlign){
45068 this.el.addClass('x-form-label-'+this.labelAlign);
45070 if(this.hideLabels){
45071 this.labelStyle = "display:none";
45072 this.elementStyle = "padding-left:0;";
45074 if(typeof this.labelWidth == 'number'){
45075 this.labelStyle = "width:"+this.labelWidth+"px;";
45076 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45078 if(this.labelAlign == 'top'){
45079 this.labelStyle = "width:auto;";
45080 this.elementStyle = "padding-left:0;";
45083 var stack = this.stack;
45084 var slen = stack.length;
45086 if(!this.fieldTpl){
45087 var t = new Roo.Template(
45088 '<div class="x-form-item {5}">',
45089 '<label for="{0}" style="{2}">{1}{4}</label>',
45090 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45092 '</div><div class="x-form-clear-left"></div>'
45094 t.disableFormats = true;
45096 Roo.form.Layout.prototype.fieldTpl = t;
45098 for(var i = 0; i < slen; i++) {
45099 if(stack[i].isFormField){
45100 this.renderField(stack[i]);
45102 this.renderComponent(stack[i]);
45107 this.el.createChild({cls:'x-form-clear'});
45112 renderField : function(f){
45113 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45116 f.labelStyle||this.labelStyle||'', //2
45117 this.elementStyle||'', //3
45118 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45119 f.itemCls||this.itemCls||'' //5
45120 ], true).getPrevSibling());
45124 renderComponent : function(c){
45125 c.render(c.isLayout ? this.el : this.el.createChild());
45128 * Adds a object form elements (using the xtype property as the factory method.)
45129 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45130 * @param {Object} config
45132 addxtype : function(o)
45134 // create the lement.
45135 o.form = this.form;
45136 var fe = Roo.factory(o, Roo.form);
45137 this.form.allItems.push(fe);
45138 this.stack.push(fe);
45140 if (fe.isFormField) {
45141 this.form.items.add(fe);
45149 * @class Roo.form.Column
45150 * @extends Roo.form.Layout
45151 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45153 * @param {Object} config Configuration options
45155 Roo.form.Column = function(config){
45156 Roo.form.Column.superclass.constructor.call(this, config);
45159 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45161 * @cfg {Number/String} width
45162 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45165 * @cfg {String/Object} autoCreate
45166 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45170 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45173 onRender : function(ct, position){
45174 Roo.form.Column.superclass.onRender.call(this, ct, position);
45176 this.el.setWidth(this.width);
45183 * @class Roo.form.Row
45184 * @extends Roo.form.Layout
45185 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45187 * @param {Object} config Configuration options
45191 Roo.form.Row = function(config){
45192 Roo.form.Row.superclass.constructor.call(this, config);
45195 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45197 * @cfg {Number/String} width
45198 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45201 * @cfg {Number/String} height
45202 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45204 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45208 onRender : function(ct, position){
45209 //console.log('row render');
45211 var t = new Roo.Template(
45212 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45213 '<label for="{0}" style="{2}">{1}{4}</label>',
45214 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45218 t.disableFormats = true;
45220 Roo.form.Layout.prototype.rowTpl = t;
45222 this.fieldTpl = this.rowTpl;
45224 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
45225 var labelWidth = 100;
45227 if ((this.labelAlign != 'top')) {
45228 if (typeof this.labelWidth == 'number') {
45229 labelWidth = this.labelWidth
45231 this.padWidth = 20 + labelWidth;
45235 Roo.form.Column.superclass.onRender.call(this, ct, position);
45237 this.el.setWidth(this.width);
45240 this.el.setHeight(this.height);
45245 renderField : function(f){
45246 f.fieldEl = this.fieldTpl.append(this.el, [
45247 f.id, f.fieldLabel,
45248 f.labelStyle||this.labelStyle||'',
45249 this.elementStyle||'',
45250 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
45251 f.itemCls||this.itemCls||'',
45252 f.width ? f.width + this.padWidth : 160 + this.padWidth
45259 * @class Roo.form.FieldSet
45260 * @extends Roo.form.Layout
45261 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
45263 * @param {Object} config Configuration options
45265 Roo.form.FieldSet = function(config){
45266 Roo.form.FieldSet.superclass.constructor.call(this, config);
45269 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
45271 * @cfg {String} legend
45272 * The text to display as the legend for the FieldSet (defaults to '')
45275 * @cfg {String/Object} autoCreate
45276 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
45280 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
45283 onRender : function(ct, position){
45284 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
45286 this.setLegend(this.legend);
45291 setLegend : function(text){
45293 this.el.child('legend').update(text);
45298 * Ext JS Library 1.1.1
45299 * Copyright(c) 2006-2007, Ext JS, LLC.
45301 * Originally Released Under LGPL - original licence link has changed is not relivant.
45304 * <script type="text/javascript">
45307 * @class Roo.form.VTypes
45308 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
45311 Roo.form.VTypes = function(){
45312 // closure these in so they are only created once.
45313 var alpha = /^[a-zA-Z_]+$/;
45314 var alphanum = /^[a-zA-Z0-9_]+$/;
45315 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
45316 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
45318 // All these messages and functions are configurable
45321 * The function used to validate email addresses
45322 * @param {String} value The email address
45324 'email' : function(v){
45325 return email.test(v);
45328 * The error text to display when the email validation function returns false
45331 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
45333 * The keystroke filter mask to be applied on email input
45336 'emailMask' : /[a-z0-9_\.\-@]/i,
45339 * The function used to validate URLs
45340 * @param {String} value The URL
45342 'url' : function(v){
45343 return url.test(v);
45346 * The error text to display when the url validation function returns false
45349 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
45352 * The function used to validate alpha values
45353 * @param {String} value The value
45355 'alpha' : function(v){
45356 return alpha.test(v);
45359 * The error text to display when the alpha validation function returns false
45362 'alphaText' : 'This field should only contain letters and _',
45364 * The keystroke filter mask to be applied on alpha input
45367 'alphaMask' : /[a-z_]/i,
45370 * The function used to validate alphanumeric values
45371 * @param {String} value The value
45373 'alphanum' : function(v){
45374 return alphanum.test(v);
45377 * The error text to display when the alphanumeric validation function returns false
45380 'alphanumText' : 'This field should only contain letters, numbers and _',
45382 * The keystroke filter mask to be applied on alphanumeric input
45385 'alphanumMask' : /[a-z0-9_]/i
45387 }();//<script type="text/javascript">
45390 * @class Roo.form.FCKeditor
45391 * @extends Roo.form.TextArea
45392 * Wrapper around the FCKEditor http://www.fckeditor.net
45394 * Creates a new FCKeditor
45395 * @param {Object} config Configuration options
45397 Roo.form.FCKeditor = function(config){
45398 Roo.form.FCKeditor.superclass.constructor.call(this, config);
45401 * @event editorinit
45402 * Fired when the editor is initialized - you can add extra handlers here..
45403 * @param {FCKeditor} this
45404 * @param {Object} the FCK object.
45411 Roo.form.FCKeditor.editors = { };
45412 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
45414 //defaultAutoCreate : {
45415 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
45419 * @cfg {Object} fck options - see fck manual for details.
45424 * @cfg {Object} fck toolbar set (Basic or Default)
45426 toolbarSet : 'Basic',
45428 * @cfg {Object} fck BasePath
45430 basePath : '/fckeditor/',
45438 onRender : function(ct, position)
45441 this.defaultAutoCreate = {
45443 style:"width:300px;height:60px;",
45444 autocomplete: "off"
45447 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
45450 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
45451 if(this.preventScrollbars){
45452 this.el.setStyle("overflow", "hidden");
45454 this.el.setHeight(this.growMin);
45457 //console.log('onrender' + this.getId() );
45458 Roo.form.FCKeditor.editors[this.getId()] = this;
45461 this.replaceTextarea() ;
45465 getEditor : function() {
45466 return this.fckEditor;
45469 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
45470 * @param {Mixed} value The value to set
45474 setValue : function(value)
45476 //console.log('setValue: ' + value);
45478 if(typeof(value) == 'undefined') { // not sure why this is happending...
45481 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45483 //if(!this.el || !this.getEditor()) {
45484 // this.value = value;
45485 //this.setValue.defer(100,this,[value]);
45489 if(!this.getEditor()) {
45493 this.getEditor().SetData(value);
45500 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
45501 * @return {Mixed} value The field value
45503 getValue : function()
45506 if (this.frame && this.frame.dom.style.display == 'none') {
45507 return Roo.form.FCKeditor.superclass.getValue.call(this);
45510 if(!this.el || !this.getEditor()) {
45512 // this.getValue.defer(100,this);
45517 var value=this.getEditor().GetData();
45518 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45519 return Roo.form.FCKeditor.superclass.getValue.call(this);
45525 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
45526 * @return {Mixed} value The field value
45528 getRawValue : function()
45530 if (this.frame && this.frame.dom.style.display == 'none') {
45531 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45534 if(!this.el || !this.getEditor()) {
45535 //this.getRawValue.defer(100,this);
45542 var value=this.getEditor().GetData();
45543 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
45544 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45548 setSize : function(w,h) {
45552 //if (this.frame && this.frame.dom.style.display == 'none') {
45553 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45556 //if(!this.el || !this.getEditor()) {
45557 // this.setSize.defer(100,this, [w,h]);
45563 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45565 this.frame.dom.setAttribute('width', w);
45566 this.frame.dom.setAttribute('height', h);
45567 this.frame.setSize(w,h);
45571 toggleSourceEdit : function(value) {
45575 this.el.dom.style.display = value ? '' : 'none';
45576 this.frame.dom.style.display = value ? 'none' : '';
45581 focus: function(tag)
45583 if (this.frame.dom.style.display == 'none') {
45584 return Roo.form.FCKeditor.superclass.focus.call(this);
45586 if(!this.el || !this.getEditor()) {
45587 this.focus.defer(100,this, [tag]);
45594 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
45595 this.getEditor().Focus();
45597 if (!this.getEditor().Selection.GetSelection()) {
45598 this.focus.defer(100,this, [tag]);
45603 var r = this.getEditor().EditorDocument.createRange();
45604 r.setStart(tgs[0],0);
45605 r.setEnd(tgs[0],0);
45606 this.getEditor().Selection.GetSelection().removeAllRanges();
45607 this.getEditor().Selection.GetSelection().addRange(r);
45608 this.getEditor().Focus();
45615 replaceTextarea : function()
45617 if ( document.getElementById( this.getId() + '___Frame' ) )
45619 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
45621 // We must check the elements firstly using the Id and then the name.
45622 var oTextarea = document.getElementById( this.getId() );
45624 var colElementsByName = document.getElementsByName( this.getId() ) ;
45626 oTextarea.style.display = 'none' ;
45628 if ( oTextarea.tabIndex ) {
45629 this.TabIndex = oTextarea.tabIndex ;
45632 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
45633 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
45634 this.frame = Roo.get(this.getId() + '___Frame')
45637 _getConfigHtml : function()
45641 for ( var o in this.fckconfig ) {
45642 sConfig += sConfig.length > 0 ? '&' : '';
45643 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
45646 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
45650 _getIFrameHtml : function()
45652 var sFile = 'fckeditor.html' ;
45653 /* no idea what this is about..
45656 if ( (/fcksource=true/i).test( window.top.location.search ) )
45657 sFile = 'fckeditor.original.html' ;
45662 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
45663 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
45666 var html = '<iframe id="' + this.getId() +
45667 '___Frame" src="' + sLink +
45668 '" width="' + this.width +
45669 '" height="' + this.height + '"' +
45670 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
45671 ' frameborder="0" scrolling="no"></iframe>' ;
45676 _insertHtmlBefore : function( html, element )
45678 if ( element.insertAdjacentHTML ) {
45680 element.insertAdjacentHTML( 'beforeBegin', html ) ;
45682 var oRange = document.createRange() ;
45683 oRange.setStartBefore( element ) ;
45684 var oFragment = oRange.createContextualFragment( html );
45685 element.parentNode.insertBefore( oFragment, element ) ;
45698 //Roo.reg('fckeditor', Roo.form.FCKeditor);
45700 function FCKeditor_OnComplete(editorInstance){
45701 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
45702 f.fckEditor = editorInstance;
45703 //console.log("loaded");
45704 f.fireEvent('editorinit', f, editorInstance);
45724 //<script type="text/javascript">
45726 * @class Roo.form.GridField
45727 * @extends Roo.form.Field
45728 * Embed a grid (or editable grid into a form)
45731 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
45733 * xgrid.store = Roo.data.Store
45734 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
45735 * xgrid.store.reader = Roo.data.JsonReader
45739 * Creates a new GridField
45740 * @param {Object} config Configuration options
45742 Roo.form.GridField = function(config){
45743 Roo.form.GridField.superclass.constructor.call(this, config);
45747 Roo.extend(Roo.form.GridField, Roo.form.Field, {
45749 * @cfg {Number} width - used to restrict width of grid..
45753 * @cfg {Number} height - used to restrict height of grid..
45757 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
45763 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45764 * {tag: "input", type: "checkbox", autocomplete: "off"})
45766 // defaultAutoCreate : { tag: 'div' },
45767 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45769 * @cfg {String} addTitle Text to include for adding a title.
45773 onResize : function(){
45774 Roo.form.Field.superclass.onResize.apply(this, arguments);
45777 initEvents : function(){
45778 // Roo.form.Checkbox.superclass.initEvents.call(this);
45779 // has no events...
45784 getResizeEl : function(){
45788 getPositionEl : function(){
45793 onRender : function(ct, position){
45795 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
45796 var style = this.style;
45799 Roo.form.GridField.superclass.onRender.call(this, ct, position);
45800 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
45801 this.viewEl = this.wrap.createChild({ tag: 'div' });
45803 this.viewEl.applyStyles(style);
45806 this.viewEl.setWidth(this.width);
45809 this.viewEl.setHeight(this.height);
45811 //if(this.inputValue !== undefined){
45812 //this.setValue(this.value);
45815 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
45818 this.grid.render();
45819 this.grid.getDataSource().on('remove', this.refreshValue, this);
45820 this.grid.getDataSource().on('update', this.refreshValue, this);
45821 this.grid.on('afteredit', this.refreshValue, this);
45827 * Sets the value of the item.
45828 * @param {String} either an object or a string..
45830 setValue : function(v){
45832 v = v || []; // empty set..
45833 // this does not seem smart - it really only affects memoryproxy grids..
45834 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
45835 var ds = this.grid.getDataSource();
45836 // assumes a json reader..
45838 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
45839 ds.loadData( data);
45841 // clear selection so it does not get stale.
45842 if (this.grid.sm) {
45843 this.grid.sm.clearSelections();
45846 Roo.form.GridField.superclass.setValue.call(this, v);
45847 this.refreshValue();
45848 // should load data in the grid really....
45852 refreshValue: function() {
45854 this.grid.getDataSource().each(function(r) {
45857 this.el.dom.value = Roo.encode(val);
45865 * Ext JS Library 1.1.1
45866 * Copyright(c) 2006-2007, Ext JS, LLC.
45868 * Originally Released Under LGPL - original licence link has changed is not relivant.
45871 * <script type="text/javascript">
45874 * @class Roo.form.DisplayField
45875 * @extends Roo.form.Field
45876 * A generic Field to display non-editable data.
45878 * Creates a new Display Field item.
45879 * @param {Object} config Configuration options
45881 Roo.form.DisplayField = function(config){
45882 Roo.form.DisplayField.superclass.constructor.call(this, config);
45886 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
45887 inputType: 'hidden',
45893 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45895 focusClass : undefined,
45897 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45899 fieldClass: 'x-form-field',
45902 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
45904 valueRenderer: undefined,
45908 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45909 * {tag: "input", type: "checkbox", autocomplete: "off"})
45912 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45914 onResize : function(){
45915 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
45919 initEvents : function(){
45920 // Roo.form.Checkbox.superclass.initEvents.call(this);
45921 // has no events...
45926 getResizeEl : function(){
45930 getPositionEl : function(){
45935 onRender : function(ct, position){
45937 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
45938 //if(this.inputValue !== undefined){
45939 this.wrap = this.el.wrap();
45941 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
45943 if (this.bodyStyle) {
45944 this.viewEl.applyStyles(this.bodyStyle);
45946 //this.viewEl.setStyle('padding', '2px');
45948 this.setValue(this.value);
45953 initValue : Roo.emptyFn,
45958 onClick : function(){
45963 * Sets the checked state of the checkbox.
45964 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
45966 setValue : function(v){
45968 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
45969 // this might be called before we have a dom element..
45970 if (!this.viewEl) {
45973 this.viewEl.dom.innerHTML = html;
45974 Roo.form.DisplayField.superclass.setValue.call(this, v);
45984 * @class Roo.form.DayPicker
45985 * @extends Roo.form.Field
45986 * A Day picker show [M] [T] [W] ....
45988 * Creates a new Day Picker
45989 * @param {Object} config Configuration options
45991 Roo.form.DayPicker= function(config){
45992 Roo.form.DayPicker.superclass.constructor.call(this, config);
45996 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
45998 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46000 focusClass : undefined,
46002 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46004 fieldClass: "x-form-field",
46007 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46008 * {tag: "input", type: "checkbox", autocomplete: "off"})
46010 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46013 actionMode : 'viewEl',
46017 inputType : 'hidden',
46020 inputElement: false, // real input element?
46021 basedOn: false, // ????
46023 isFormField: true, // not sure where this is needed!!!!
46025 onResize : function(){
46026 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46027 if(!this.boxLabel){
46028 this.el.alignTo(this.wrap, 'c-c');
46032 initEvents : function(){
46033 Roo.form.Checkbox.superclass.initEvents.call(this);
46034 this.el.on("click", this.onClick, this);
46035 this.el.on("change", this.onClick, this);
46039 getResizeEl : function(){
46043 getPositionEl : function(){
46049 onRender : function(ct, position){
46050 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46052 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46054 var r1 = '<table><tr>';
46055 var r2 = '<tr class="x-form-daypick-icons">';
46056 for (var i=0; i < 7; i++) {
46057 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46058 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46061 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46062 viewEl.select('img').on('click', this.onClick, this);
46063 this.viewEl = viewEl;
46066 // this will not work on Chrome!!!
46067 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46068 this.el.on('propertychange', this.setFromHidden, this); //ie
46076 initValue : Roo.emptyFn,
46079 * Returns the checked state of the checkbox.
46080 * @return {Boolean} True if checked, else false
46082 getValue : function(){
46083 return this.el.dom.value;
46088 onClick : function(e){
46089 //this.setChecked(!this.checked);
46090 Roo.get(e.target).toggleClass('x-menu-item-checked');
46091 this.refreshValue();
46092 //if(this.el.dom.checked != this.checked){
46093 // this.setValue(this.el.dom.checked);
46098 refreshValue : function()
46101 this.viewEl.select('img',true).each(function(e,i,n) {
46102 val += e.is(".x-menu-item-checked") ? String(n) : '';
46104 this.setValue(val, true);
46108 * Sets the checked state of the checkbox.
46109 * On is always based on a string comparison between inputValue and the param.
46110 * @param {Boolean/String} value - the value to set
46111 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46113 setValue : function(v,suppressEvent){
46114 if (!this.el.dom) {
46117 var old = this.el.dom.value ;
46118 this.el.dom.value = v;
46119 if (suppressEvent) {
46123 // update display..
46124 this.viewEl.select('img',true).each(function(e,i,n) {
46126 var on = e.is(".x-menu-item-checked");
46127 var newv = v.indexOf(String(n)) > -1;
46129 e.toggleClass('x-menu-item-checked');
46135 this.fireEvent('change', this, v, old);
46140 // handle setting of hidden value by some other method!!?!?
46141 setFromHidden: function()
46146 //console.log("SET FROM HIDDEN");
46147 //alert('setFrom hidden');
46148 this.setValue(this.el.dom.value);
46151 onDestroy : function()
46154 Roo.get(this.viewEl).remove();
46157 Roo.form.DayPicker.superclass.onDestroy.call(this);
46161 * RooJS Library 1.1.1
46162 * Copyright(c) 2008-2011 Alan Knowles
46169 * @class Roo.form.ComboCheck
46170 * @extends Roo.form.ComboBox
46171 * A combobox for multiple select items.
46173 * FIXME - could do with a reset button..
46176 * Create a new ComboCheck
46177 * @param {Object} config Configuration options
46179 Roo.form.ComboCheck = function(config){
46180 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46181 // should verify some data...
46183 // hiddenName = required..
46184 // displayField = required
46185 // valudField == required
46186 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46188 Roo.each(req, function(e) {
46189 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46190 throw "Roo.form.ComboCheck : missing value for: " + e;
46197 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46202 selectedClass: 'x-menu-item-checked',
46205 onRender : function(ct, position){
46211 var cls = 'x-combo-list';
46214 this.tpl = new Roo.Template({
46215 html : '<div class="'+cls+'-item x-menu-check-item">' +
46216 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
46217 '<span>{' + this.displayField + '}</span>' +
46224 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
46225 this.view.singleSelect = false;
46226 this.view.multiSelect = true;
46227 this.view.toggleSelect = true;
46228 this.pageTb.add(new Roo.Toolbar.Fill(), {
46231 handler: function()
46238 onViewOver : function(e, t){
46244 onViewClick : function(doFocus,index){
46248 select: function () {
46249 //Roo.log("SELECT CALLED");
46252 selectByValue : function(xv, scrollIntoView){
46253 var ar = this.getValueArray();
46256 Roo.each(ar, function(v) {
46257 if(v === undefined || v === null){
46260 var r = this.findRecord(this.valueField, v);
46262 sels.push(this.store.indexOf(r))
46266 this.view.select(sels);
46272 onSelect : function(record, index){
46273 // Roo.log("onselect Called");
46274 // this is only called by the clear button now..
46275 this.view.clearSelections();
46276 this.setValue('[]');
46277 if (this.value != this.valueBefore) {
46278 this.fireEvent('change', this, this.value, this.valueBefore);
46279 this.valueBefore = this.value;
46282 getValueArray : function()
46287 //Roo.log(this.value);
46288 if (typeof(this.value) == 'undefined') {
46291 var ar = Roo.decode(this.value);
46292 return ar instanceof Array ? ar : []; //?? valid?
46295 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
46300 expand : function ()
46303 Roo.form.ComboCheck.superclass.expand.call(this);
46304 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
46305 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
46310 collapse : function(){
46311 Roo.form.ComboCheck.superclass.collapse.call(this);
46312 var sl = this.view.getSelectedIndexes();
46313 var st = this.store;
46317 Roo.each(sl, function(i) {
46319 nv.push(r.get(this.valueField));
46321 this.setValue(Roo.encode(nv));
46322 if (this.value != this.valueBefore) {
46324 this.fireEvent('change', this, this.value, this.valueBefore);
46325 this.valueBefore = this.value;
46330 setValue : function(v){
46334 var vals = this.getValueArray();
46336 Roo.each(vals, function(k) {
46337 var r = this.findRecord(this.valueField, k);
46339 tv.push(r.data[this.displayField]);
46340 }else if(this.valueNotFoundText !== undefined){
46341 tv.push( this.valueNotFoundText );
46346 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
46347 this.hiddenField.value = v;
46353 * Ext JS Library 1.1.1
46354 * Copyright(c) 2006-2007, Ext JS, LLC.
46356 * Originally Released Under LGPL - original licence link has changed is not relivant.
46359 * <script type="text/javascript">
46363 * @class Roo.form.Signature
46364 * @extends Roo.form.Field
46368 * @param {Object} config Configuration options
46371 Roo.form.Signature = function(config){
46372 Roo.form.Signature.superclass.constructor.call(this, config);
46374 this.addEvents({// not in used??
46377 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
46378 * @param {Roo.form.Signature} combo This combo box
46383 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
46384 * @param {Roo.form.ComboBox} combo This combo box
46385 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
46391 Roo.extend(Roo.form.Signature, Roo.form.Field, {
46393 * @cfg {Object} labels Label to use when rendering a form.
46397 * confirm : "Confirm"
46402 confirm : "Confirm"
46405 * @cfg {Number} width The signature panel width (defaults to 300)
46409 * @cfg {Number} height The signature panel height (defaults to 100)
46413 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
46415 allowBlank : false,
46418 // {Object} signPanel The signature SVG panel element (defaults to {})
46420 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
46421 isMouseDown : false,
46422 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
46423 isConfirmed : false,
46424 // {String} signatureTmp SVG mapping string (defaults to empty string)
46428 defaultAutoCreate : { // modified by initCompnoent..
46434 onRender : function(ct, position){
46436 Roo.form.Signature.superclass.onRender.call(this, ct, position);
46438 this.wrap = this.el.wrap({
46439 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
46442 this.createToolbar(this);
46443 this.signPanel = this.wrap.createChild({
46445 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
46449 this.svgID = Roo.id();
46450 this.svgEl = this.signPanel.createChild({
46451 xmlns : 'http://www.w3.org/2000/svg',
46453 id : this.svgID + "-svg",
46455 height: this.height,
46456 viewBox: '0 0 '+this.width+' '+this.height,
46460 id: this.svgID + "-svg-r",
46462 height: this.height,
46467 id: this.svgID + "-svg-l",
46469 y1: (this.height*0.8), // start set the line in 80% of height
46470 x2: this.width, // end
46471 y2: (this.height*0.8), // end set the line in 80% of height
46473 'stroke-width': "1",
46474 'stroke-dasharray': "3",
46475 'shape-rendering': "crispEdges",
46476 'pointer-events': "none"
46480 id: this.svgID + "-svg-p",
46482 'stroke-width': "3",
46484 'pointer-events': 'none'
46489 this.svgBox = this.svgEl.dom.getScreenCTM();
46491 createSVG : function(){
46492 var svg = this.signPanel;
46493 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
46496 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
46497 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
46498 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
46499 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
46500 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
46501 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
46502 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
46505 isTouchEvent : function(e){
46506 return e.type.match(/^touch/);
46508 getCoords : function (e) {
46509 var pt = this.svgEl.dom.createSVGPoint();
46512 if (this.isTouchEvent(e)) {
46513 pt.x = e.targetTouches[0].clientX
46514 pt.y = e.targetTouches[0].clientY;
46516 var a = this.svgEl.dom.getScreenCTM();
46517 var b = a.inverse();
46518 var mx = pt.matrixTransform(b);
46519 return mx.x + ',' + mx.y;
46521 //mouse event headler
46522 down : function (e) {
46523 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
46524 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
46526 this.isMouseDown = true;
46528 e.preventDefault();
46530 move : function (e) {
46531 if (this.isMouseDown) {
46532 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
46533 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
46536 e.preventDefault();
46538 up : function (e) {
46539 this.isMouseDown = false;
46540 var sp = this.signatureTmp.split(' ');
46543 if(!sp[sp.length-2].match(/^L/)){
46547 this.signatureTmp = sp.join(" ");
46550 if(this.getValue() != this.signatureTmp){
46551 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46552 this.isConfirmed = false;
46554 e.preventDefault();
46558 * Protected method that will not generally be called directly. It
46559 * is called when the editor creates its toolbar. Override this method if you need to
46560 * add custom toolbar buttons.
46561 * @param {HtmlEditor} editor
46563 createToolbar : function(editor){
46564 function btn(id, toggle, handler){
46565 var xid = fid + '-'+ id ;
46569 cls : 'x-btn-icon x-edit-'+id,
46570 enableToggle:toggle !== false,
46571 scope: editor, // was editor...
46572 handler:handler||editor.relayBtnCmd,
46573 clickEvent:'mousedown',
46574 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46580 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46584 cls : ' x-signature-btn x-signature-'+id,
46585 scope: editor, // was editor...
46586 handler: this.reset,
46587 clickEvent:'mousedown',
46588 text: this.labels.clear
46595 cls : ' x-signature-btn x-signature-'+id,
46596 scope: editor, // was editor...
46597 handler: this.confirmHandler,
46598 clickEvent:'mousedown',
46599 text: this.labels.confirm
46606 * when user is clicked confirm then show this image.....
46608 * @return {String} Image Data URI
46610 getImageDataURI : function(){
46611 var svg = this.svgEl.dom.parentNode.innerHTML;
46612 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
46617 * @return {Boolean} this.isConfirmed
46619 getConfirmed : function(){
46620 return this.isConfirmed;
46624 * @return {Number} this.width
46626 getWidth : function(){
46631 * @return {Number} this.height
46633 getHeight : function(){
46634 return this.height;
46637 getSignature : function(){
46638 return this.signatureTmp;
46641 reset : function(){
46642 this.signatureTmp = '';
46643 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46644 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
46645 this.isConfirmed = false;
46646 Roo.form.Signature.superclass.reset.call(this);
46648 setSignature : function(s){
46649 this.signatureTmp = s;
46650 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46651 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
46653 this.isConfirmed = false;
46654 Roo.form.Signature.superclass.reset.call(this);
46657 // Roo.log(this.signPanel.dom.contentWindow.up())
46660 setConfirmed : function(){
46664 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
46667 confirmHandler : function(){
46668 if(!this.getSignature()){
46672 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
46673 this.setValue(this.getSignature());
46674 this.isConfirmed = true;
46676 this.fireEvent('confirm', this);
46679 // Subclasses should provide the validation implementation by overriding this
46680 validateValue : function(value){
46681 if(this.allowBlank){
46685 if(this.isConfirmed){
46692 * Ext JS Library 1.1.1
46693 * Copyright(c) 2006-2007, Ext JS, LLC.
46695 * Originally Released Under LGPL - original licence link has changed is not relivant.
46698 * <script type="text/javascript">
46703 * @class Roo.form.ComboBox
46704 * @extends Roo.form.TriggerField
46705 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
46707 * Create a new ComboBox.
46708 * @param {Object} config Configuration options
46710 Roo.form.Select = function(config){
46711 Roo.form.Select.superclass.constructor.call(this, config);
46715 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
46717 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
46720 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
46721 * rendering into an Roo.Editor, defaults to false)
46724 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
46725 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
46728 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
46731 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
46732 * the dropdown list (defaults to undefined, with no header element)
46736 * @cfg {String/Roo.Template} tpl The template to use to render the output
46740 defaultAutoCreate : {tag: "select" },
46742 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
46744 listWidth: undefined,
46746 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
46747 * mode = 'remote' or 'text' if mode = 'local')
46749 displayField: undefined,
46751 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
46752 * mode = 'remote' or 'value' if mode = 'local').
46753 * Note: use of a valueField requires the user make a selection
46754 * in order for a value to be mapped.
46756 valueField: undefined,
46760 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
46761 * field's data value (defaults to the underlying DOM element's name)
46763 hiddenName: undefined,
46765 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
46769 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
46771 selectedClass: 'x-combo-selected',
46773 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
46774 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
46775 * which displays a downward arrow icon).
46777 triggerClass : 'x-form-arrow-trigger',
46779 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
46783 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
46784 * anchor positions (defaults to 'tl-bl')
46786 listAlign: 'tl-bl?',
46788 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
46792 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
46793 * query specified by the allQuery config option (defaults to 'query')
46795 triggerAction: 'query',
46797 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
46798 * (defaults to 4, does not apply if editable = false)
46802 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
46803 * delay (typeAheadDelay) if it matches a known value (defaults to false)
46807 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
46808 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
46812 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
46813 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
46817 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
46818 * when editable = true (defaults to false)
46820 selectOnFocus:false,
46822 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
46824 queryParam: 'query',
46826 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
46827 * when mode = 'remote' (defaults to 'Loading...')
46829 loadingText: 'Loading...',
46831 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
46835 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
46839 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
46840 * traditional select (defaults to true)
46844 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
46848 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
46852 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
46853 * listWidth has a higher value)
46857 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
46858 * allow the user to set arbitrary text into the field (defaults to false)
46860 forceSelection:false,
46862 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
46863 * if typeAhead = true (defaults to 250)
46865 typeAheadDelay : 250,
46867 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
46868 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
46870 valueNotFoundText : undefined,
46873 * @cfg {String} defaultValue The value displayed after loading the store.
46878 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
46880 blockFocus : false,
46883 * @cfg {Boolean} disableClear Disable showing of clear button.
46885 disableClear : false,
46887 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
46889 alwaysQuery : false,
46895 // element that contains real text value.. (when hidden is used..)
46898 onRender : function(ct, position){
46899 Roo.form.Field.prototype.onRender.call(this, ct, position);
46902 this.store.on('beforeload', this.onBeforeLoad, this);
46903 this.store.on('load', this.onLoad, this);
46904 this.store.on('loadexception', this.onLoadException, this);
46905 this.store.load({});
46913 initEvents : function(){
46914 //Roo.form.ComboBox.superclass.initEvents.call(this);
46918 onDestroy : function(){
46921 this.store.un('beforeload', this.onBeforeLoad, this);
46922 this.store.un('load', this.onLoad, this);
46923 this.store.un('loadexception', this.onLoadException, this);
46925 //Roo.form.ComboBox.superclass.onDestroy.call(this);
46929 fireKey : function(e){
46930 if(e.isNavKeyPress() && !this.list.isVisible()){
46931 this.fireEvent("specialkey", this, e);
46936 onResize: function(w, h){
46944 * Allow or prevent the user from directly editing the field text. If false is passed,
46945 * the user will only be able to select from the items defined in the dropdown list. This method
46946 * is the runtime equivalent of setting the 'editable' config option at config time.
46947 * @param {Boolean} value True to allow the user to directly edit the field text
46949 setEditable : function(value){
46954 onBeforeLoad : function(){
46956 Roo.log("Select before load");
46959 this.innerList.update(this.loadingText ?
46960 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
46961 //this.restrictHeight();
46962 this.selectedIndex = -1;
46966 onLoad : function(){
46969 var dom = this.el.dom;
46970 dom.innerHTML = '';
46971 var od = dom.ownerDocument;
46973 if (this.emptyText) {
46974 var op = od.createElement('option');
46975 op.setAttribute('value', '');
46976 op.innerHTML = String.format('{0}', this.emptyText);
46977 dom.appendChild(op);
46979 if(this.store.getCount() > 0){
46981 var vf = this.valueField;
46982 var df = this.displayField;
46983 this.store.data.each(function(r) {
46984 // which colmsn to use... testing - cdoe / title..
46985 var op = od.createElement('option');
46986 op.setAttribute('value', r.data[vf]);
46987 op.innerHTML = String.format('{0}', r.data[df]);
46988 dom.appendChild(op);
46990 if (typeof(this.defaultValue != 'undefined')) {
46991 this.setValue(this.defaultValue);
46996 //this.onEmptyResults();
47001 onLoadException : function()
47003 dom.innerHTML = '';
47005 Roo.log("Select on load exception");
47009 Roo.log(this.store.reader.jsonData);
47010 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47011 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47017 onTypeAhead : function(){
47022 onSelect : function(record, index){
47023 Roo.log('on select?');
47025 if(this.fireEvent('beforeselect', this, record, index) !== false){
47026 this.setFromData(index > -1 ? record.data : false);
47028 this.fireEvent('select', this, record, index);
47033 * Returns the currently selected field value or empty string if no value is set.
47034 * @return {String} value The selected value
47036 getValue : function(){
47037 var dom = this.el.dom;
47038 this.value = dom.options[dom.selectedIndex].value;
47044 * Clears any text/value currently set in the field
47046 clearValue : function(){
47048 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47053 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47054 * will be displayed in the field. If the value does not match the data value of an existing item,
47055 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47056 * Otherwise the field will be blank (although the value will still be set).
47057 * @param {String} value The value to match
47059 setValue : function(v){
47060 var d = this.el.dom;
47061 for (var i =0; i < d.options.length;i++) {
47062 if (v == d.options[i].value) {
47063 d.selectedIndex = i;
47071 * @property {Object} the last set data for the element
47076 * Sets the value of the field based on a object which is related to the record format for the store.
47077 * @param {Object} value the value to set as. or false on reset?
47079 setFromData : function(o){
47080 Roo.log('setfrom data?');
47086 reset : function(){
47090 findRecord : function(prop, value){
47095 if(this.store.getCount() > 0){
47096 this.store.each(function(r){
47097 if(r.data[prop] == value){
47107 getName: function()
47109 // returns hidden if it's set..
47110 if (!this.rendered) {return ''};
47111 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47119 onEmptyResults : function(){
47120 Roo.log('empty results');
47125 * Returns true if the dropdown list is expanded, else false.
47127 isExpanded : function(){
47132 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47133 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47134 * @param {String} value The data value of the item to select
47135 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47136 * selected item if it is not currently in view (defaults to true)
47137 * @return {Boolean} True if the value matched an item in the list, else false
47139 selectByValue : function(v, scrollIntoView){
47140 Roo.log('select By Value');
47143 if(v !== undefined && v !== null){
47144 var r = this.findRecord(this.valueField || this.displayField, v);
47146 this.select(this.store.indexOf(r), scrollIntoView);
47154 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47155 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47156 * @param {Number} index The zero-based index of the list item to select
47157 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47158 * selected item if it is not currently in view (defaults to true)
47160 select : function(index, scrollIntoView){
47161 Roo.log('select ');
47164 this.selectedIndex = index;
47165 this.view.select(index);
47166 if(scrollIntoView !== false){
47167 var el = this.view.getNode(index);
47169 this.innerList.scrollChildIntoView(el, false);
47177 validateBlur : function(){
47184 initQuery : function(){
47185 this.doQuery(this.getRawValue());
47189 doForce : function(){
47190 if(this.el.dom.value.length > 0){
47191 this.el.dom.value =
47192 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47198 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47199 * query allowing the query action to be canceled if needed.
47200 * @param {String} query The SQL query to execute
47201 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47202 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47203 * saved in the current store (defaults to false)
47205 doQuery : function(q, forceAll){
47207 Roo.log('doQuery?');
47208 if(q === undefined || q === null){
47213 forceAll: forceAll,
47217 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
47221 forceAll = qe.forceAll;
47222 if(forceAll === true || (q.length >= this.minChars)){
47223 if(this.lastQuery != q || this.alwaysQuery){
47224 this.lastQuery = q;
47225 if(this.mode == 'local'){
47226 this.selectedIndex = -1;
47228 this.store.clearFilter();
47230 this.store.filter(this.displayField, q);
47234 this.store.baseParams[this.queryParam] = q;
47236 params: this.getParams(q)
47241 this.selectedIndex = -1;
47248 getParams : function(q){
47250 //p[this.queryParam] = q;
47253 p.limit = this.pageSize;
47259 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
47261 collapse : function(){
47266 collapseIf : function(e){
47271 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
47273 expand : function(){
47281 * @cfg {Boolean} grow
47285 * @cfg {Number} growMin
47289 * @cfg {Number} growMax
47297 setWidth : function()
47301 getResizeEl : function(){
47304 });//<script type="text/javasscript">
47308 * @class Roo.DDView
47309 * A DnD enabled version of Roo.View.
47310 * @param {Element/String} container The Element in which to create the View.
47311 * @param {String} tpl The template string used to create the markup for each element of the View
47312 * @param {Object} config The configuration properties. These include all the config options of
47313 * {@link Roo.View} plus some specific to this class.<br>
47315 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
47316 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
47318 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
47319 .x-view-drag-insert-above {
47320 border-top:1px dotted #3366cc;
47322 .x-view-drag-insert-below {
47323 border-bottom:1px dotted #3366cc;
47329 Roo.DDView = function(container, tpl, config) {
47330 Roo.DDView.superclass.constructor.apply(this, arguments);
47331 this.getEl().setStyle("outline", "0px none");
47332 this.getEl().unselectable();
47333 if (this.dragGroup) {
47334 this.setDraggable(this.dragGroup.split(","));
47336 if (this.dropGroup) {
47337 this.setDroppable(this.dropGroup.split(","));
47339 if (this.deletable) {
47340 this.setDeletable();
47342 this.isDirtyFlag = false;
47348 Roo.extend(Roo.DDView, Roo.View, {
47349 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
47350 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
47351 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
47352 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
47356 reset: Roo.emptyFn,
47358 clearInvalid: Roo.form.Field.prototype.clearInvalid,
47360 validate: function() {
47364 destroy: function() {
47365 this.purgeListeners();
47366 this.getEl.removeAllListeners();
47367 this.getEl().remove();
47368 if (this.dragZone) {
47369 if (this.dragZone.destroy) {
47370 this.dragZone.destroy();
47373 if (this.dropZone) {
47374 if (this.dropZone.destroy) {
47375 this.dropZone.destroy();
47380 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
47381 getName: function() {
47385 /** Loads the View from a JSON string representing the Records to put into the Store. */
47386 setValue: function(v) {
47388 throw "DDView.setValue(). DDView must be constructed with a valid Store";
47391 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
47392 this.store.proxy = new Roo.data.MemoryProxy(data);
47396 /** @return {String} a parenthesised list of the ids of the Records in the View. */
47397 getValue: function() {
47399 this.store.each(function(rec) {
47400 result += rec.id + ',';
47402 return result.substr(0, result.length - 1) + ')';
47405 getIds: function() {
47406 var i = 0, result = new Array(this.store.getCount());
47407 this.store.each(function(rec) {
47408 result[i++] = rec.id;
47413 isDirty: function() {
47414 return this.isDirtyFlag;
47418 * Part of the Roo.dd.DropZone interface. If no target node is found, the
47419 * whole Element becomes the target, and this causes the drop gesture to append.
47421 getTargetFromEvent : function(e) {
47422 var target = e.getTarget();
47423 while ((target !== null) && (target.parentNode != this.el.dom)) {
47424 target = target.parentNode;
47427 target = this.el.dom.lastChild || this.el.dom;
47433 * Create the drag data which consists of an object which has the property "ddel" as
47434 * the drag proxy element.
47436 getDragData : function(e) {
47437 var target = this.findItemFromChild(e.getTarget());
47439 this.handleSelection(e);
47440 var selNodes = this.getSelectedNodes();
47443 copy: this.copy || (this.allowCopy && e.ctrlKey),
47447 var selectedIndices = this.getSelectedIndexes();
47448 for (var i = 0; i < selectedIndices.length; i++) {
47449 dragData.records.push(this.store.getAt(selectedIndices[i]));
47451 if (selNodes.length == 1) {
47452 dragData.ddel = target.cloneNode(true); // the div element
47454 var div = document.createElement('div'); // create the multi element drag "ghost"
47455 div.className = 'multi-proxy';
47456 for (var i = 0, len = selNodes.length; i < len; i++) {
47457 div.appendChild(selNodes[i].cloneNode(true));
47459 dragData.ddel = div;
47461 //console.log(dragData)
47462 //console.log(dragData.ddel.innerHTML)
47465 //console.log('nodragData')
47469 /** Specify to which ddGroup items in this DDView may be dragged. */
47470 setDraggable: function(ddGroup) {
47471 if (ddGroup instanceof Array) {
47472 Roo.each(ddGroup, this.setDraggable, this);
47475 if (this.dragZone) {
47476 this.dragZone.addToGroup(ddGroup);
47478 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
47479 containerScroll: true,
47483 // Draggability implies selection. DragZone's mousedown selects the element.
47484 if (!this.multiSelect) { this.singleSelect = true; }
47486 // Wire the DragZone's handlers up to methods in *this*
47487 this.dragZone.getDragData = this.getDragData.createDelegate(this);
47491 /** Specify from which ddGroup this DDView accepts drops. */
47492 setDroppable: function(ddGroup) {
47493 if (ddGroup instanceof Array) {
47494 Roo.each(ddGroup, this.setDroppable, this);
47497 if (this.dropZone) {
47498 this.dropZone.addToGroup(ddGroup);
47500 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
47501 containerScroll: true,
47505 // Wire the DropZone's handlers up to methods in *this*
47506 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
47507 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
47508 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
47509 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
47510 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
47514 /** Decide whether to drop above or below a View node. */
47515 getDropPoint : function(e, n, dd){
47516 if (n == this.el.dom) { return "above"; }
47517 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
47518 var c = t + (b - t) / 2;
47519 var y = Roo.lib.Event.getPageY(e);
47527 onNodeEnter : function(n, dd, e, data){
47531 onNodeOver : function(n, dd, e, data){
47532 var pt = this.getDropPoint(e, n, dd);
47533 // set the insert point style on the target node
47534 var dragElClass = this.dropNotAllowed;
47537 if (pt == "above"){
47538 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
47539 targetElClass = "x-view-drag-insert-above";
47541 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
47542 targetElClass = "x-view-drag-insert-below";
47544 if (this.lastInsertClass != targetElClass){
47545 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
47546 this.lastInsertClass = targetElClass;
47549 return dragElClass;
47552 onNodeOut : function(n, dd, e, data){
47553 this.removeDropIndicators(n);
47556 onNodeDrop : function(n, dd, e, data){
47557 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
47560 var pt = this.getDropPoint(e, n, dd);
47561 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
47562 if (pt == "below") { insertAt++; }
47563 for (var i = 0; i < data.records.length; i++) {
47564 var r = data.records[i];
47565 var dup = this.store.getById(r.id);
47566 if (dup && (dd != this.dragZone)) {
47567 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
47570 this.store.insert(insertAt++, r.copy());
47572 data.source.isDirtyFlag = true;
47574 this.store.insert(insertAt++, r);
47576 this.isDirtyFlag = true;
47579 this.dragZone.cachedTarget = null;
47583 removeDropIndicators : function(n){
47585 Roo.fly(n).removeClass([
47586 "x-view-drag-insert-above",
47587 "x-view-drag-insert-below"]);
47588 this.lastInsertClass = "_noclass";
47593 * Utility method. Add a delete option to the DDView's context menu.
47594 * @param {String} imageUrl The URL of the "delete" icon image.
47596 setDeletable: function(imageUrl) {
47597 if (!this.singleSelect && !this.multiSelect) {
47598 this.singleSelect = true;
47600 var c = this.getContextMenu();
47601 this.contextMenu.on("itemclick", function(item) {
47604 this.remove(this.getSelectedIndexes());
47608 this.contextMenu.add({
47615 /** Return the context menu for this DDView. */
47616 getContextMenu: function() {
47617 if (!this.contextMenu) {
47618 // Create the View's context menu
47619 this.contextMenu = new Roo.menu.Menu({
47620 id: this.id + "-contextmenu"
47622 this.el.on("contextmenu", this.showContextMenu, this);
47624 return this.contextMenu;
47627 disableContextMenu: function() {
47628 if (this.contextMenu) {
47629 this.el.un("contextmenu", this.showContextMenu, this);
47633 showContextMenu: function(e, item) {
47634 item = this.findItemFromChild(e.getTarget());
47637 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
47638 this.contextMenu.showAt(e.getXY());
47643 * Remove {@link Roo.data.Record}s at the specified indices.
47644 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
47646 remove: function(selectedIndices) {
47647 selectedIndices = [].concat(selectedIndices);
47648 for (var i = 0; i < selectedIndices.length; i++) {
47649 var rec = this.store.getAt(selectedIndices[i]);
47650 this.store.remove(rec);
47655 * Double click fires the event, but also, if this is draggable, and there is only one other
47656 * related DropZone, it transfers the selected node.
47658 onDblClick : function(e){
47659 var item = this.findItemFromChild(e.getTarget());
47661 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
47664 if (this.dragGroup) {
47665 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
47666 while (targets.indexOf(this.dropZone) > -1) {
47667 targets.remove(this.dropZone);
47669 if (targets.length == 1) {
47670 this.dragZone.cachedTarget = null;
47671 var el = Roo.get(targets[0].getEl());
47672 var box = el.getBox(true);
47673 targets[0].onNodeDrop(el.dom, {
47675 xy: [box.x, box.y + box.height - 1]
47676 }, null, this.getDragData(e));
47682 handleSelection: function(e) {
47683 this.dragZone.cachedTarget = null;
47684 var item = this.findItemFromChild(e.getTarget());
47686 this.clearSelections(true);
47689 if (item && (this.multiSelect || this.singleSelect)){
47690 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
47691 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
47692 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
47693 this.unselect(item);
47695 this.select(item, this.multiSelect && e.ctrlKey);
47696 this.lastSelection = item;
47701 onItemClick : function(item, index, e){
47702 if(this.fireEvent("beforeclick", this, index, item, e) === false){
47708 unselect : function(nodeInfo, suppressEvent){
47709 var node = this.getNode(nodeInfo);
47710 if(node && this.isSelected(node)){
47711 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
47712 Roo.fly(node).removeClass(this.selectedClass);
47713 this.selections.remove(node);
47714 if(!suppressEvent){
47715 this.fireEvent("selectionchange", this, this.selections);
47723 * Ext JS Library 1.1.1
47724 * Copyright(c) 2006-2007, Ext JS, LLC.
47726 * Originally Released Under LGPL - original licence link has changed is not relivant.
47729 * <script type="text/javascript">
47733 * @class Roo.LayoutManager
47734 * @extends Roo.util.Observable
47735 * Base class for layout managers.
47737 Roo.LayoutManager = function(container, config){
47738 Roo.LayoutManager.superclass.constructor.call(this);
47739 this.el = Roo.get(container);
47740 // ie scrollbar fix
47741 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
47742 document.body.scroll = "no";
47743 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
47744 this.el.position('relative');
47746 this.id = this.el.id;
47747 this.el.addClass("x-layout-container");
47748 /** false to disable window resize monitoring @type Boolean */
47749 this.monitorWindowResize = true;
47754 * Fires when a layout is performed.
47755 * @param {Roo.LayoutManager} this
47759 * @event regionresized
47760 * Fires when the user resizes a region.
47761 * @param {Roo.LayoutRegion} region The resized region
47762 * @param {Number} newSize The new size (width for east/west, height for north/south)
47764 "regionresized" : true,
47766 * @event regioncollapsed
47767 * Fires when a region is collapsed.
47768 * @param {Roo.LayoutRegion} region The collapsed region
47770 "regioncollapsed" : true,
47772 * @event regionexpanded
47773 * Fires when a region is expanded.
47774 * @param {Roo.LayoutRegion} region The expanded region
47776 "regionexpanded" : true
47778 this.updating = false;
47779 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47782 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
47784 * Returns true if this layout is currently being updated
47785 * @return {Boolean}
47787 isUpdating : function(){
47788 return this.updating;
47792 * Suspend the LayoutManager from doing auto-layouts while
47793 * making multiple add or remove calls
47795 beginUpdate : function(){
47796 this.updating = true;
47800 * Restore auto-layouts and optionally disable the manager from performing a layout
47801 * @param {Boolean} noLayout true to disable a layout update
47803 endUpdate : function(noLayout){
47804 this.updating = false;
47810 layout: function(){
47814 onRegionResized : function(region, newSize){
47815 this.fireEvent("regionresized", region, newSize);
47819 onRegionCollapsed : function(region){
47820 this.fireEvent("regioncollapsed", region);
47823 onRegionExpanded : function(region){
47824 this.fireEvent("regionexpanded", region);
47828 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
47829 * performs box-model adjustments.
47830 * @return {Object} The size as an object {width: (the width), height: (the height)}
47832 getViewSize : function(){
47834 if(this.el.dom != document.body){
47835 size = this.el.getSize();
47837 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
47839 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
47840 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
47845 * Returns the Element this layout is bound to.
47846 * @return {Roo.Element}
47848 getEl : function(){
47853 * Returns the specified region.
47854 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
47855 * @return {Roo.LayoutRegion}
47857 getRegion : function(target){
47858 return this.regions[target.toLowerCase()];
47861 onWindowResize : function(){
47862 if(this.monitorWindowResize){
47868 * Ext JS Library 1.1.1
47869 * Copyright(c) 2006-2007, Ext JS, LLC.
47871 * Originally Released Under LGPL - original licence link has changed is not relivant.
47874 * <script type="text/javascript">
47877 * @class Roo.BorderLayout
47878 * @extends Roo.LayoutManager
47879 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
47880 * please see: <br><br>
47881 * <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>
47882 * <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>
47885 var layout = new Roo.BorderLayout(document.body, {
47919 preferredTabWidth: 150
47924 var CP = Roo.ContentPanel;
47926 layout.beginUpdate();
47927 layout.add("north", new CP("north", "North"));
47928 layout.add("south", new CP("south", {title: "South", closable: true}));
47929 layout.add("west", new CP("west", {title: "West"}));
47930 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
47931 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
47932 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
47933 layout.getRegion("center").showPanel("center1");
47934 layout.endUpdate();
47937 <b>The container the layout is rendered into can be either the body element or any other element.
47938 If it is not the body element, the container needs to either be an absolute positioned element,
47939 or you will need to add "position:relative" to the css of the container. You will also need to specify
47940 the container size if it is not the body element.</b>
47943 * Create a new BorderLayout
47944 * @param {String/HTMLElement/Element} container The container this layout is bound to
47945 * @param {Object} config Configuration options
47947 Roo.BorderLayout = function(container, config){
47948 config = config || {};
47949 Roo.BorderLayout.superclass.constructor.call(this, container, config);
47950 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
47951 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
47952 var target = this.factory.validRegions[i];
47953 if(config[target]){
47954 this.addRegion(target, config[target]);
47959 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
47961 * Creates and adds a new region if it doesn't already exist.
47962 * @param {String} target The target region key (north, south, east, west or center).
47963 * @param {Object} config The regions config object
47964 * @return {BorderLayoutRegion} The new region
47966 addRegion : function(target, config){
47967 if(!this.regions[target]){
47968 var r = this.factory.create(target, this, config);
47969 this.bindRegion(target, r);
47971 return this.regions[target];
47975 bindRegion : function(name, r){
47976 this.regions[name] = r;
47977 r.on("visibilitychange", this.layout, this);
47978 r.on("paneladded", this.layout, this);
47979 r.on("panelremoved", this.layout, this);
47980 r.on("invalidated", this.layout, this);
47981 r.on("resized", this.onRegionResized, this);
47982 r.on("collapsed", this.onRegionCollapsed, this);
47983 r.on("expanded", this.onRegionExpanded, this);
47987 * Performs a layout update.
47989 layout : function(){
47990 if(this.updating) return;
47991 var size = this.getViewSize();
47992 var w = size.width;
47993 var h = size.height;
47998 //var x = 0, y = 0;
48000 var rs = this.regions;
48001 var north = rs["north"];
48002 var south = rs["south"];
48003 var west = rs["west"];
48004 var east = rs["east"];
48005 var center = rs["center"];
48006 //if(this.hideOnLayout){ // not supported anymore
48007 //c.el.setStyle("display", "none");
48009 if(north && north.isVisible()){
48010 var b = north.getBox();
48011 var m = north.getMargins();
48012 b.width = w - (m.left+m.right);
48015 centerY = b.height + b.y + m.bottom;
48016 centerH -= centerY;
48017 north.updateBox(this.safeBox(b));
48019 if(south && south.isVisible()){
48020 var b = south.getBox();
48021 var m = south.getMargins();
48022 b.width = w - (m.left+m.right);
48024 var totalHeight = (b.height + m.top + m.bottom);
48025 b.y = h - totalHeight + m.top;
48026 centerH -= totalHeight;
48027 south.updateBox(this.safeBox(b));
48029 if(west && west.isVisible()){
48030 var b = west.getBox();
48031 var m = west.getMargins();
48032 b.height = centerH - (m.top+m.bottom);
48034 b.y = centerY + m.top;
48035 var totalWidth = (b.width + m.left + m.right);
48036 centerX += totalWidth;
48037 centerW -= totalWidth;
48038 west.updateBox(this.safeBox(b));
48040 if(east && east.isVisible()){
48041 var b = east.getBox();
48042 var m = east.getMargins();
48043 b.height = centerH - (m.top+m.bottom);
48044 var totalWidth = (b.width + m.left + m.right);
48045 b.x = w - totalWidth + m.left;
48046 b.y = centerY + m.top;
48047 centerW -= totalWidth;
48048 east.updateBox(this.safeBox(b));
48051 var m = center.getMargins();
48053 x: centerX + m.left,
48054 y: centerY + m.top,
48055 width: centerW - (m.left+m.right),
48056 height: centerH - (m.top+m.bottom)
48058 //if(this.hideOnLayout){
48059 //center.el.setStyle("display", "block");
48061 center.updateBox(this.safeBox(centerBox));
48064 this.fireEvent("layout", this);
48068 safeBox : function(box){
48069 box.width = Math.max(0, box.width);
48070 box.height = Math.max(0, box.height);
48075 * Adds a ContentPanel (or subclass) to this layout.
48076 * @param {String} target The target region key (north, south, east, west or center).
48077 * @param {Roo.ContentPanel} panel The panel to add
48078 * @return {Roo.ContentPanel} The added panel
48080 add : function(target, panel){
48082 target = target.toLowerCase();
48083 return this.regions[target].add(panel);
48087 * Remove a ContentPanel (or subclass) to this layout.
48088 * @param {String} target The target region key (north, south, east, west or center).
48089 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48090 * @return {Roo.ContentPanel} The removed panel
48092 remove : function(target, panel){
48093 target = target.toLowerCase();
48094 return this.regions[target].remove(panel);
48098 * Searches all regions for a panel with the specified id
48099 * @param {String} panelId
48100 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48102 findPanel : function(panelId){
48103 var rs = this.regions;
48104 for(var target in rs){
48105 if(typeof rs[target] != "function"){
48106 var p = rs[target].getPanel(panelId);
48116 * Searches all regions for a panel with the specified id and activates (shows) it.
48117 * @param {String/ContentPanel} panelId The panels id or the panel itself
48118 * @return {Roo.ContentPanel} The shown panel or null
48120 showPanel : function(panelId) {
48121 var rs = this.regions;
48122 for(var target in rs){
48123 var r = rs[target];
48124 if(typeof r != "function"){
48125 if(r.hasPanel(panelId)){
48126 return r.showPanel(panelId);
48134 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48135 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48137 restoreState : function(provider){
48139 provider = Roo.state.Manager;
48141 var sm = new Roo.LayoutStateManager();
48142 sm.init(this, provider);
48146 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48147 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48148 * a valid ContentPanel config object. Example:
48150 // Create the main layout
48151 var layout = new Roo.BorderLayout('main-ct', {
48162 // Create and add multiple ContentPanels at once via configs
48165 id: 'source-files',
48167 title:'Ext Source Files',
48180 * @param {Object} regions An object containing ContentPanel configs by region name
48182 batchAdd : function(regions){
48183 this.beginUpdate();
48184 for(var rname in regions){
48185 var lr = this.regions[rname];
48187 this.addTypedPanels(lr, regions[rname]);
48194 addTypedPanels : function(lr, ps){
48195 if(typeof ps == 'string'){
48196 lr.add(new Roo.ContentPanel(ps));
48198 else if(ps instanceof Array){
48199 for(var i =0, len = ps.length; i < len; i++){
48200 this.addTypedPanels(lr, ps[i]);
48203 else if(!ps.events){ // raw config?
48205 delete ps.el; // prevent conflict
48206 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48208 else { // panel object assumed!
48213 * Adds a xtype elements to the layout.
48217 xtype : 'ContentPanel',
48224 xtype : 'NestedLayoutPanel',
48230 items : [ ... list of content panels or nested layout panels.. ]
48234 * @param {Object} cfg Xtype definition of item to add.
48236 addxtype : function(cfg)
48238 // basically accepts a pannel...
48239 // can accept a layout region..!?!?
48240 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
48242 if (!cfg.xtype.match(/Panel$/)) {
48247 if (typeof(cfg.region) == 'undefined') {
48248 Roo.log("Failed to add Panel, region was not set");
48252 var region = cfg.region;
48258 xitems = cfg.items;
48265 case 'ContentPanel': // ContentPanel (el, cfg)
48266 case 'ScrollPanel': // ContentPanel (el, cfg)
48268 if(cfg.autoCreate) {
48269 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48271 var el = this.el.createChild();
48272 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
48275 this.add(region, ret);
48279 case 'TreePanel': // our new panel!
48280 cfg.el = this.el.createChild();
48281 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48282 this.add(region, ret);
48285 case 'NestedLayoutPanel':
48286 // create a new Layout (which is a Border Layout...
48287 var el = this.el.createChild();
48288 var clayout = cfg.layout;
48290 clayout.items = clayout.items || [];
48291 // replace this exitems with the clayout ones..
48292 xitems = clayout.items;
48295 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
48296 cfg.background = false;
48298 var layout = new Roo.BorderLayout(el, clayout);
48300 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
48301 //console.log('adding nested layout panel ' + cfg.toSource());
48302 this.add(region, ret);
48303 nb = {}; /// find first...
48308 // needs grid and region
48310 //var el = this.getRegion(region).el.createChild();
48311 var el = this.el.createChild();
48312 // create the grid first...
48314 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
48316 if (region == 'center' && this.active ) {
48317 cfg.background = false;
48319 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
48321 this.add(region, ret);
48322 if (cfg.background) {
48323 ret.on('activate', function(gp) {
48324 if (!gp.grid.rendered) {
48339 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
48341 // GridPanel (grid, cfg)
48344 this.beginUpdate();
48348 Roo.each(xitems, function(i) {
48349 region = nb && i.region ? i.region : false;
48351 var add = ret.addxtype(i);
48354 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
48355 if (!i.background) {
48356 abn[region] = nb[region] ;
48363 // make the last non-background panel active..
48364 //if (nb) { Roo.log(abn); }
48367 for(var r in abn) {
48368 region = this.getRegion(r);
48370 // tried using nb[r], but it does not work..
48372 region.showPanel(abn[r]);
48383 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
48384 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
48385 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
48386 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
48389 var CP = Roo.ContentPanel;
48391 var layout = Roo.BorderLayout.create({
48395 panels: [new CP("north", "North")]
48404 panels: [new CP("west", {title: "West"})]
48413 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
48422 panels: [new CP("south", {title: "South", closable: true})]
48429 preferredTabWidth: 150,
48431 new CP("center1", {title: "Close Me", closable: true}),
48432 new CP("center2", {title: "Center Panel", closable: false})
48437 layout.getRegion("center").showPanel("center1");
48442 Roo.BorderLayout.create = function(config, targetEl){
48443 var layout = new Roo.BorderLayout(targetEl || document.body, config);
48444 layout.beginUpdate();
48445 var regions = Roo.BorderLayout.RegionFactory.validRegions;
48446 for(var j = 0, jlen = regions.length; j < jlen; j++){
48447 var lr = regions[j];
48448 if(layout.regions[lr] && config[lr].panels){
48449 var r = layout.regions[lr];
48450 var ps = config[lr].panels;
48451 layout.addTypedPanels(r, ps);
48454 layout.endUpdate();
48459 Roo.BorderLayout.RegionFactory = {
48461 validRegions : ["north","south","east","west","center"],
48464 create : function(target, mgr, config){
48465 target = target.toLowerCase();
48466 if(config.lightweight || config.basic){
48467 return new Roo.BasicLayoutRegion(mgr, config, target);
48471 return new Roo.NorthLayoutRegion(mgr, config);
48473 return new Roo.SouthLayoutRegion(mgr, config);
48475 return new Roo.EastLayoutRegion(mgr, config);
48477 return new Roo.WestLayoutRegion(mgr, config);
48479 return new Roo.CenterLayoutRegion(mgr, config);
48481 throw 'Layout region "'+target+'" not supported.';
48485 * Ext JS Library 1.1.1
48486 * Copyright(c) 2006-2007, Ext JS, LLC.
48488 * Originally Released Under LGPL - original licence link has changed is not relivant.
48491 * <script type="text/javascript">
48495 * @class Roo.BasicLayoutRegion
48496 * @extends Roo.util.Observable
48497 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
48498 * and does not have a titlebar, tabs or any other features. All it does is size and position
48499 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
48501 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
48503 this.position = pos;
48506 * @scope Roo.BasicLayoutRegion
48510 * @event beforeremove
48511 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
48512 * @param {Roo.LayoutRegion} this
48513 * @param {Roo.ContentPanel} panel The panel
48514 * @param {Object} e The cancel event object
48516 "beforeremove" : true,
48518 * @event invalidated
48519 * Fires when the layout for this region is changed.
48520 * @param {Roo.LayoutRegion} this
48522 "invalidated" : true,
48524 * @event visibilitychange
48525 * Fires when this region is shown or hidden
48526 * @param {Roo.LayoutRegion} this
48527 * @param {Boolean} visibility true or false
48529 "visibilitychange" : true,
48531 * @event paneladded
48532 * Fires when a panel is added.
48533 * @param {Roo.LayoutRegion} this
48534 * @param {Roo.ContentPanel} panel The panel
48536 "paneladded" : true,
48538 * @event panelremoved
48539 * Fires when a panel is removed.
48540 * @param {Roo.LayoutRegion} this
48541 * @param {Roo.ContentPanel} panel The panel
48543 "panelremoved" : true,
48546 * Fires when this region is collapsed.
48547 * @param {Roo.LayoutRegion} this
48549 "collapsed" : true,
48552 * Fires when this region is expanded.
48553 * @param {Roo.LayoutRegion} this
48558 * Fires when this region is slid into view.
48559 * @param {Roo.LayoutRegion} this
48561 "slideshow" : true,
48564 * Fires when this region slides out of view.
48565 * @param {Roo.LayoutRegion} this
48567 "slidehide" : true,
48569 * @event panelactivated
48570 * Fires when a panel is activated.
48571 * @param {Roo.LayoutRegion} this
48572 * @param {Roo.ContentPanel} panel The activated panel
48574 "panelactivated" : true,
48577 * Fires when the user resizes this region.
48578 * @param {Roo.LayoutRegion} this
48579 * @param {Number} newSize The new size (width for east/west, height for north/south)
48583 /** A collection of panels in this region. @type Roo.util.MixedCollection */
48584 this.panels = new Roo.util.MixedCollection();
48585 this.panels.getKey = this.getPanelId.createDelegate(this);
48587 this.activePanel = null;
48588 // ensure listeners are added...
48590 if (config.listeners || config.events) {
48591 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
48592 listeners : config.listeners || {},
48593 events : config.events || {}
48597 if(skipConfig !== true){
48598 this.applyConfig(config);
48602 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
48603 getPanelId : function(p){
48607 applyConfig : function(config){
48608 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48609 this.config = config;
48614 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
48615 * the width, for horizontal (north, south) the height.
48616 * @param {Number} newSize The new width or height
48618 resizeTo : function(newSize){
48619 var el = this.el ? this.el :
48620 (this.activePanel ? this.activePanel.getEl() : null);
48622 switch(this.position){
48625 el.setWidth(newSize);
48626 this.fireEvent("resized", this, newSize);
48630 el.setHeight(newSize);
48631 this.fireEvent("resized", this, newSize);
48637 getBox : function(){
48638 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
48641 getMargins : function(){
48642 return this.margins;
48645 updateBox : function(box){
48647 var el = this.activePanel.getEl();
48648 el.dom.style.left = box.x + "px";
48649 el.dom.style.top = box.y + "px";
48650 this.activePanel.setSize(box.width, box.height);
48654 * Returns the container element for this region.
48655 * @return {Roo.Element}
48657 getEl : function(){
48658 return this.activePanel;
48662 * Returns true if this region is currently visible.
48663 * @return {Boolean}
48665 isVisible : function(){
48666 return this.activePanel ? true : false;
48669 setActivePanel : function(panel){
48670 panel = this.getPanel(panel);
48671 if(this.activePanel && this.activePanel != panel){
48672 this.activePanel.setActiveState(false);
48673 this.activePanel.getEl().setLeftTop(-10000,-10000);
48675 this.activePanel = panel;
48676 panel.setActiveState(true);
48678 panel.setSize(this.box.width, this.box.height);
48680 this.fireEvent("panelactivated", this, panel);
48681 this.fireEvent("invalidated");
48685 * Show the specified panel.
48686 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
48687 * @return {Roo.ContentPanel} The shown panel or null
48689 showPanel : function(panel){
48690 if(panel = this.getPanel(panel)){
48691 this.setActivePanel(panel);
48697 * Get the active panel for this region.
48698 * @return {Roo.ContentPanel} The active panel or null
48700 getActivePanel : function(){
48701 return this.activePanel;
48705 * Add the passed ContentPanel(s)
48706 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48707 * @return {Roo.ContentPanel} The panel added (if only one was added)
48709 add : function(panel){
48710 if(arguments.length > 1){
48711 for(var i = 0, len = arguments.length; i < len; i++) {
48712 this.add(arguments[i]);
48716 if(this.hasPanel(panel)){
48717 this.showPanel(panel);
48720 var el = panel.getEl();
48721 if(el.dom.parentNode != this.mgr.el.dom){
48722 this.mgr.el.dom.appendChild(el.dom);
48724 if(panel.setRegion){
48725 panel.setRegion(this);
48727 this.panels.add(panel);
48728 el.setStyle("position", "absolute");
48729 if(!panel.background){
48730 this.setActivePanel(panel);
48731 if(this.config.initialSize && this.panels.getCount()==1){
48732 this.resizeTo(this.config.initialSize);
48735 this.fireEvent("paneladded", this, panel);
48740 * Returns true if the panel is in this region.
48741 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48742 * @return {Boolean}
48744 hasPanel : function(panel){
48745 if(typeof panel == "object"){ // must be panel obj
48746 panel = panel.getId();
48748 return this.getPanel(panel) ? true : false;
48752 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48753 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48754 * @param {Boolean} preservePanel Overrides the config preservePanel option
48755 * @return {Roo.ContentPanel} The panel that was removed
48757 remove : function(panel, preservePanel){
48758 panel = this.getPanel(panel);
48763 this.fireEvent("beforeremove", this, panel, e);
48764 if(e.cancel === true){
48767 var panelId = panel.getId();
48768 this.panels.removeKey(panelId);
48773 * Returns the panel specified or null if it's not in this region.
48774 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48775 * @return {Roo.ContentPanel}
48777 getPanel : function(id){
48778 if(typeof id == "object"){ // must be panel obj
48781 return this.panels.get(id);
48785 * Returns this regions position (north/south/east/west/center).
48788 getPosition: function(){
48789 return this.position;
48793 * Ext JS Library 1.1.1
48794 * Copyright(c) 2006-2007, Ext JS, LLC.
48796 * Originally Released Under LGPL - original licence link has changed is not relivant.
48799 * <script type="text/javascript">
48803 * @class Roo.LayoutRegion
48804 * @extends Roo.BasicLayoutRegion
48805 * This class represents a region in a layout manager.
48806 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
48807 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
48808 * @cfg {Boolean} floatable False to disable floating (defaults to true)
48809 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
48810 * @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})
48811 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
48812 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
48813 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
48814 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
48815 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
48816 * @cfg {String} title The title for the region (overrides panel titles)
48817 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
48818 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
48819 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
48820 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
48821 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
48822 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
48823 * the space available, similar to FireFox 1.5 tabs (defaults to false)
48824 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
48825 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
48826 * @cfg {Boolean} showPin True to show a pin button
48827 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
48828 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
48829 * @cfg {Boolean} disableTabTips True to disable tab tooltips
48830 * @cfg {Number} width For East/West panels
48831 * @cfg {Number} height For North/South panels
48832 * @cfg {Boolean} split To show the splitter
48833 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
48835 Roo.LayoutRegion = function(mgr, config, pos){
48836 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
48837 var dh = Roo.DomHelper;
48838 /** This region's container element
48839 * @type Roo.Element */
48840 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
48841 /** This region's title element
48842 * @type Roo.Element */
48844 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
48845 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
48846 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
48848 this.titleEl.enableDisplayMode();
48849 /** This region's title text element
48850 * @type HTMLElement */
48851 this.titleTextEl = this.titleEl.dom.firstChild;
48852 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
48853 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
48854 this.closeBtn.enableDisplayMode();
48855 this.closeBtn.on("click", this.closeClicked, this);
48856 this.closeBtn.hide();
48858 this.createBody(config);
48859 this.visible = true;
48860 this.collapsed = false;
48862 if(config.hideWhenEmpty){
48864 this.on("paneladded", this.validateVisibility, this);
48865 this.on("panelremoved", this.validateVisibility, this);
48867 this.applyConfig(config);
48870 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
48872 createBody : function(){
48873 /** This region's body element
48874 * @type Roo.Element */
48875 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
48878 applyConfig : function(c){
48879 if(c.collapsible && this.position != "center" && !this.collapsedEl){
48880 var dh = Roo.DomHelper;
48881 if(c.titlebar !== false){
48882 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
48883 this.collapseBtn.on("click", this.collapse, this);
48884 this.collapseBtn.enableDisplayMode();
48886 if(c.showPin === true || this.showPin){
48887 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
48888 this.stickBtn.enableDisplayMode();
48889 this.stickBtn.on("click", this.expand, this);
48890 this.stickBtn.hide();
48893 /** This region's collapsed element
48894 * @type Roo.Element */
48895 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
48896 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
48898 if(c.floatable !== false){
48899 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
48900 this.collapsedEl.on("click", this.collapseClick, this);
48903 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
48904 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
48905 id: "message", unselectable: "on", style:{"float":"left"}});
48906 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
48908 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
48909 this.expandBtn.on("click", this.expand, this);
48911 if(this.collapseBtn){
48912 this.collapseBtn.setVisible(c.collapsible == true);
48914 this.cmargins = c.cmargins || this.cmargins ||
48915 (this.position == "west" || this.position == "east" ?
48916 {top: 0, left: 2, right:2, bottom: 0} :
48917 {top: 2, left: 0, right:0, bottom: 2});
48918 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48919 this.bottomTabs = c.tabPosition != "top";
48920 this.autoScroll = c.autoScroll || false;
48921 if(this.autoScroll){
48922 this.bodyEl.setStyle("overflow", "auto");
48924 this.bodyEl.setStyle("overflow", "hidden");
48926 //if(c.titlebar !== false){
48927 if((!c.titlebar && !c.title) || c.titlebar === false){
48928 this.titleEl.hide();
48930 this.titleEl.show();
48932 this.titleTextEl.innerHTML = c.title;
48936 this.duration = c.duration || .30;
48937 this.slideDuration = c.slideDuration || .45;
48940 this.collapse(true);
48947 * Returns true if this region is currently visible.
48948 * @return {Boolean}
48950 isVisible : function(){
48951 return this.visible;
48955 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
48956 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
48958 setCollapsedTitle : function(title){
48959 title = title || " ";
48960 if(this.collapsedTitleTextEl){
48961 this.collapsedTitleTextEl.innerHTML = title;
48965 getBox : function(){
48967 if(!this.collapsed){
48968 b = this.el.getBox(false, true);
48970 b = this.collapsedEl.getBox(false, true);
48975 getMargins : function(){
48976 return this.collapsed ? this.cmargins : this.margins;
48979 highlight : function(){
48980 this.el.addClass("x-layout-panel-dragover");
48983 unhighlight : function(){
48984 this.el.removeClass("x-layout-panel-dragover");
48987 updateBox : function(box){
48989 if(!this.collapsed){
48990 this.el.dom.style.left = box.x + "px";
48991 this.el.dom.style.top = box.y + "px";
48992 this.updateBody(box.width, box.height);
48994 this.collapsedEl.dom.style.left = box.x + "px";
48995 this.collapsedEl.dom.style.top = box.y + "px";
48996 this.collapsedEl.setSize(box.width, box.height);
48999 this.tabs.autoSizeTabs();
49003 updateBody : function(w, h){
49005 this.el.setWidth(w);
49006 w -= this.el.getBorderWidth("rl");
49007 if(this.config.adjustments){
49008 w += this.config.adjustments[0];
49012 this.el.setHeight(h);
49013 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49014 h -= this.el.getBorderWidth("tb");
49015 if(this.config.adjustments){
49016 h += this.config.adjustments[1];
49018 this.bodyEl.setHeight(h);
49020 h = this.tabs.syncHeight(h);
49023 if(this.panelSize){
49024 w = w !== null ? w : this.panelSize.width;
49025 h = h !== null ? h : this.panelSize.height;
49027 if(this.activePanel){
49028 var el = this.activePanel.getEl();
49029 w = w !== null ? w : el.getWidth();
49030 h = h !== null ? h : el.getHeight();
49031 this.panelSize = {width: w, height: h};
49032 this.activePanel.setSize(w, h);
49034 if(Roo.isIE && this.tabs){
49035 this.tabs.el.repaint();
49040 * Returns the container element for this region.
49041 * @return {Roo.Element}
49043 getEl : function(){
49048 * Hides this region.
49051 if(!this.collapsed){
49052 this.el.dom.style.left = "-2000px";
49055 this.collapsedEl.dom.style.left = "-2000px";
49056 this.collapsedEl.hide();
49058 this.visible = false;
49059 this.fireEvent("visibilitychange", this, false);
49063 * Shows this region if it was previously hidden.
49066 if(!this.collapsed){
49069 this.collapsedEl.show();
49071 this.visible = true;
49072 this.fireEvent("visibilitychange", this, true);
49075 closeClicked : function(){
49076 if(this.activePanel){
49077 this.remove(this.activePanel);
49081 collapseClick : function(e){
49083 e.stopPropagation();
49086 e.stopPropagation();
49092 * Collapses this region.
49093 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49095 collapse : function(skipAnim){
49096 if(this.collapsed) return;
49097 this.collapsed = true;
49099 this.split.el.hide();
49101 if(this.config.animate && skipAnim !== true){
49102 this.fireEvent("invalidated", this);
49103 this.animateCollapse();
49105 this.el.setLocation(-20000,-20000);
49107 this.collapsedEl.show();
49108 this.fireEvent("collapsed", this);
49109 this.fireEvent("invalidated", this);
49113 animateCollapse : function(){
49118 * Expands this region if it was previously collapsed.
49119 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49120 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49122 expand : function(e, skipAnim){
49123 if(e) e.stopPropagation();
49124 if(!this.collapsed || this.el.hasActiveFx()) return;
49126 this.afterSlideIn();
49129 this.collapsed = false;
49130 if(this.config.animate && skipAnim !== true){
49131 this.animateExpand();
49135 this.split.el.show();
49137 this.collapsedEl.setLocation(-2000,-2000);
49138 this.collapsedEl.hide();
49139 this.fireEvent("invalidated", this);
49140 this.fireEvent("expanded", this);
49144 animateExpand : function(){
49148 initTabs : function()
49150 this.bodyEl.setStyle("overflow", "hidden");
49151 var ts = new Roo.TabPanel(
49154 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49155 disableTooltips: this.config.disableTabTips,
49156 toolbar : this.config.toolbar
49159 if(this.config.hideTabs){
49160 ts.stripWrap.setDisplayed(false);
49163 ts.resizeTabs = this.config.resizeTabs === true;
49164 ts.minTabWidth = this.config.minTabWidth || 40;
49165 ts.maxTabWidth = this.config.maxTabWidth || 250;
49166 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49167 ts.monitorResize = false;
49168 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49169 ts.bodyEl.addClass('x-layout-tabs-body');
49170 this.panels.each(this.initPanelAsTab, this);
49173 initPanelAsTab : function(panel){
49174 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49175 this.config.closeOnTab && panel.isClosable());
49176 if(panel.tabTip !== undefined){
49177 ti.setTooltip(panel.tabTip);
49179 ti.on("activate", function(){
49180 this.setActivePanel(panel);
49182 if(this.config.closeOnTab){
49183 ti.on("beforeclose", function(t, e){
49185 this.remove(panel);
49191 updatePanelTitle : function(panel, title){
49192 if(this.activePanel == panel){
49193 this.updateTitle(title);
49196 var ti = this.tabs.getTab(panel.getEl().id);
49198 if(panel.tabTip !== undefined){
49199 ti.setTooltip(panel.tabTip);
49204 updateTitle : function(title){
49205 if(this.titleTextEl && !this.config.title){
49206 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
49210 setActivePanel : function(panel){
49211 panel = this.getPanel(panel);
49212 if(this.activePanel && this.activePanel != panel){
49213 this.activePanel.setActiveState(false);
49215 this.activePanel = panel;
49216 panel.setActiveState(true);
49217 if(this.panelSize){
49218 panel.setSize(this.panelSize.width, this.panelSize.height);
49221 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
49223 this.updateTitle(panel.getTitle());
49225 this.fireEvent("invalidated", this);
49227 this.fireEvent("panelactivated", this, panel);
49231 * Shows the specified panel.
49232 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
49233 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
49235 showPanel : function(panel){
49236 if(panel = this.getPanel(panel)){
49238 var tab = this.tabs.getTab(panel.getEl().id);
49239 if(tab.isHidden()){
49240 this.tabs.unhideTab(tab.id);
49244 this.setActivePanel(panel);
49251 * Get the active panel for this region.
49252 * @return {Roo.ContentPanel} The active panel or null
49254 getActivePanel : function(){
49255 return this.activePanel;
49258 validateVisibility : function(){
49259 if(this.panels.getCount() < 1){
49260 this.updateTitle(" ");
49261 this.closeBtn.hide();
49264 if(!this.isVisible()){
49271 * Adds the passed ContentPanel(s) to this region.
49272 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49273 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
49275 add : function(panel){
49276 if(arguments.length > 1){
49277 for(var i = 0, len = arguments.length; i < len; i++) {
49278 this.add(arguments[i]);
49282 if(this.hasPanel(panel)){
49283 this.showPanel(panel);
49286 panel.setRegion(this);
49287 this.panels.add(panel);
49288 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
49289 this.bodyEl.dom.appendChild(panel.getEl().dom);
49290 if(panel.background !== true){
49291 this.setActivePanel(panel);
49293 this.fireEvent("paneladded", this, panel);
49299 this.initPanelAsTab(panel);
49301 if(panel.background !== true){
49302 this.tabs.activate(panel.getEl().id);
49304 this.fireEvent("paneladded", this, panel);
49309 * Hides the tab for the specified panel.
49310 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49312 hidePanel : function(panel){
49313 if(this.tabs && (panel = this.getPanel(panel))){
49314 this.tabs.hideTab(panel.getEl().id);
49319 * Unhides the tab for a previously hidden panel.
49320 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49322 unhidePanel : function(panel){
49323 if(this.tabs && (panel = this.getPanel(panel))){
49324 this.tabs.unhideTab(panel.getEl().id);
49328 clearPanels : function(){
49329 while(this.panels.getCount() > 0){
49330 this.remove(this.panels.first());
49335 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49336 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49337 * @param {Boolean} preservePanel Overrides the config preservePanel option
49338 * @return {Roo.ContentPanel} The panel that was removed
49340 remove : function(panel, preservePanel){
49341 panel = this.getPanel(panel);
49346 this.fireEvent("beforeremove", this, panel, e);
49347 if(e.cancel === true){
49350 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
49351 var panelId = panel.getId();
49352 this.panels.removeKey(panelId);
49354 document.body.appendChild(panel.getEl().dom);
49357 this.tabs.removeTab(panel.getEl().id);
49358 }else if (!preservePanel){
49359 this.bodyEl.dom.removeChild(panel.getEl().dom);
49361 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
49362 var p = this.panels.first();
49363 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
49364 tempEl.appendChild(p.getEl().dom);
49365 this.bodyEl.update("");
49366 this.bodyEl.dom.appendChild(p.getEl().dom);
49368 this.updateTitle(p.getTitle());
49370 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49371 this.setActivePanel(p);
49373 panel.setRegion(null);
49374 if(this.activePanel == panel){
49375 this.activePanel = null;
49377 if(this.config.autoDestroy !== false && preservePanel !== true){
49378 try{panel.destroy();}catch(e){}
49380 this.fireEvent("panelremoved", this, panel);
49385 * Returns the TabPanel component used by this region
49386 * @return {Roo.TabPanel}
49388 getTabs : function(){
49392 createTool : function(parentEl, className){
49393 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
49394 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
49395 btn.addClassOnOver("x-layout-tools-button-over");
49400 * Ext JS Library 1.1.1
49401 * Copyright(c) 2006-2007, Ext JS, LLC.
49403 * Originally Released Under LGPL - original licence link has changed is not relivant.
49406 * <script type="text/javascript">
49412 * @class Roo.SplitLayoutRegion
49413 * @extends Roo.LayoutRegion
49414 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
49416 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
49417 this.cursor = cursor;
49418 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
49421 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
49422 splitTip : "Drag to resize.",
49423 collapsibleSplitTip : "Drag to resize. Double click to hide.",
49424 useSplitTips : false,
49426 applyConfig : function(config){
49427 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
49430 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
49431 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
49432 /** The SplitBar for this region
49433 * @type Roo.SplitBar */
49434 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
49435 this.split.on("moved", this.onSplitMove, this);
49436 this.split.useShim = config.useShim === true;
49437 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
49438 if(this.useSplitTips){
49439 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
49441 if(config.collapsible){
49442 this.split.el.on("dblclick", this.collapse, this);
49445 if(typeof config.minSize != "undefined"){
49446 this.split.minSize = config.minSize;
49448 if(typeof config.maxSize != "undefined"){
49449 this.split.maxSize = config.maxSize;
49451 if(config.hideWhenEmpty || config.hidden || config.collapsed){
49452 this.hideSplitter();
49457 getHMaxSize : function(){
49458 var cmax = this.config.maxSize || 10000;
49459 var center = this.mgr.getRegion("center");
49460 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
49463 getVMaxSize : function(){
49464 var cmax = this.config.maxSize || 10000;
49465 var center = this.mgr.getRegion("center");
49466 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
49469 onSplitMove : function(split, newSize){
49470 this.fireEvent("resized", this, newSize);
49474 * Returns the {@link Roo.SplitBar} for this region.
49475 * @return {Roo.SplitBar}
49477 getSplitBar : function(){
49482 this.hideSplitter();
49483 Roo.SplitLayoutRegion.superclass.hide.call(this);
49486 hideSplitter : function(){
49488 this.split.el.setLocation(-2000,-2000);
49489 this.split.el.hide();
49495 this.split.el.show();
49497 Roo.SplitLayoutRegion.superclass.show.call(this);
49500 beforeSlide: function(){
49501 if(Roo.isGecko){// firefox overflow auto bug workaround
49502 this.bodyEl.clip();
49503 if(this.tabs) this.tabs.bodyEl.clip();
49504 if(this.activePanel){
49505 this.activePanel.getEl().clip();
49507 if(this.activePanel.beforeSlide){
49508 this.activePanel.beforeSlide();
49514 afterSlide : function(){
49515 if(Roo.isGecko){// firefox overflow auto bug workaround
49516 this.bodyEl.unclip();
49517 if(this.tabs) this.tabs.bodyEl.unclip();
49518 if(this.activePanel){
49519 this.activePanel.getEl().unclip();
49520 if(this.activePanel.afterSlide){
49521 this.activePanel.afterSlide();
49527 initAutoHide : function(){
49528 if(this.autoHide !== false){
49529 if(!this.autoHideHd){
49530 var st = new Roo.util.DelayedTask(this.slideIn, this);
49531 this.autoHideHd = {
49532 "mouseout": function(e){
49533 if(!e.within(this.el, true)){
49537 "mouseover" : function(e){
49543 this.el.on(this.autoHideHd);
49547 clearAutoHide : function(){
49548 if(this.autoHide !== false){
49549 this.el.un("mouseout", this.autoHideHd.mouseout);
49550 this.el.un("mouseover", this.autoHideHd.mouseover);
49554 clearMonitor : function(){
49555 Roo.get(document).un("click", this.slideInIf, this);
49558 // these names are backwards but not changed for compat
49559 slideOut : function(){
49560 if(this.isSlid || this.el.hasActiveFx()){
49563 this.isSlid = true;
49564 if(this.collapseBtn){
49565 this.collapseBtn.hide();
49567 this.closeBtnState = this.closeBtn.getStyle('display');
49568 this.closeBtn.hide();
49570 this.stickBtn.show();
49573 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
49574 this.beforeSlide();
49575 this.el.setStyle("z-index", 10001);
49576 this.el.slideIn(this.getSlideAnchor(), {
49577 callback: function(){
49579 this.initAutoHide();
49580 Roo.get(document).on("click", this.slideInIf, this);
49581 this.fireEvent("slideshow", this);
49588 afterSlideIn : function(){
49589 this.clearAutoHide();
49590 this.isSlid = false;
49591 this.clearMonitor();
49592 this.el.setStyle("z-index", "");
49593 if(this.collapseBtn){
49594 this.collapseBtn.show();
49596 this.closeBtn.setStyle('display', this.closeBtnState);
49598 this.stickBtn.hide();
49600 this.fireEvent("slidehide", this);
49603 slideIn : function(cb){
49604 if(!this.isSlid || this.el.hasActiveFx()){
49608 this.isSlid = false;
49609 this.beforeSlide();
49610 this.el.slideOut(this.getSlideAnchor(), {
49611 callback: function(){
49612 this.el.setLeftTop(-10000, -10000);
49614 this.afterSlideIn();
49622 slideInIf : function(e){
49623 if(!e.within(this.el)){
49628 animateCollapse : function(){
49629 this.beforeSlide();
49630 this.el.setStyle("z-index", 20000);
49631 var anchor = this.getSlideAnchor();
49632 this.el.slideOut(anchor, {
49633 callback : function(){
49634 this.el.setStyle("z-index", "");
49635 this.collapsedEl.slideIn(anchor, {duration:.3});
49637 this.el.setLocation(-10000,-10000);
49639 this.fireEvent("collapsed", this);
49646 animateExpand : function(){
49647 this.beforeSlide();
49648 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
49649 this.el.setStyle("z-index", 20000);
49650 this.collapsedEl.hide({
49653 this.el.slideIn(this.getSlideAnchor(), {
49654 callback : function(){
49655 this.el.setStyle("z-index", "");
49658 this.split.el.show();
49660 this.fireEvent("invalidated", this);
49661 this.fireEvent("expanded", this);
49689 getAnchor : function(){
49690 return this.anchors[this.position];
49693 getCollapseAnchor : function(){
49694 return this.canchors[this.position];
49697 getSlideAnchor : function(){
49698 return this.sanchors[this.position];
49701 getAlignAdj : function(){
49702 var cm = this.cmargins;
49703 switch(this.position){
49719 getExpandAdj : function(){
49720 var c = this.collapsedEl, cm = this.cmargins;
49721 switch(this.position){
49723 return [-(cm.right+c.getWidth()+cm.left), 0];
49726 return [cm.right+c.getWidth()+cm.left, 0];
49729 return [0, -(cm.top+cm.bottom+c.getHeight())];
49732 return [0, cm.top+cm.bottom+c.getHeight()];
49738 * Ext JS Library 1.1.1
49739 * Copyright(c) 2006-2007, Ext JS, LLC.
49741 * Originally Released Under LGPL - original licence link has changed is not relivant.
49744 * <script type="text/javascript">
49747 * These classes are private internal classes
49749 Roo.CenterLayoutRegion = function(mgr, config){
49750 Roo.LayoutRegion.call(this, mgr, config, "center");
49751 this.visible = true;
49752 this.minWidth = config.minWidth || 20;
49753 this.minHeight = config.minHeight || 20;
49756 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
49758 // center panel can't be hidden
49762 // center panel can't be hidden
49765 getMinWidth: function(){
49766 return this.minWidth;
49769 getMinHeight: function(){
49770 return this.minHeight;
49775 Roo.NorthLayoutRegion = function(mgr, config){
49776 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
49778 this.split.placement = Roo.SplitBar.TOP;
49779 this.split.orientation = Roo.SplitBar.VERTICAL;
49780 this.split.el.addClass("x-layout-split-v");
49782 var size = config.initialSize || config.height;
49783 if(typeof size != "undefined"){
49784 this.el.setHeight(size);
49787 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
49788 orientation: Roo.SplitBar.VERTICAL,
49789 getBox : function(){
49790 if(this.collapsed){
49791 return this.collapsedEl.getBox();
49793 var box = this.el.getBox();
49795 box.height += this.split.el.getHeight();
49800 updateBox : function(box){
49801 if(this.split && !this.collapsed){
49802 box.height -= this.split.el.getHeight();
49803 this.split.el.setLeft(box.x);
49804 this.split.el.setTop(box.y+box.height);
49805 this.split.el.setWidth(box.width);
49807 if(this.collapsed){
49808 this.updateBody(box.width, null);
49810 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49814 Roo.SouthLayoutRegion = function(mgr, config){
49815 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
49817 this.split.placement = Roo.SplitBar.BOTTOM;
49818 this.split.orientation = Roo.SplitBar.VERTICAL;
49819 this.split.el.addClass("x-layout-split-v");
49821 var size = config.initialSize || config.height;
49822 if(typeof size != "undefined"){
49823 this.el.setHeight(size);
49826 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
49827 orientation: Roo.SplitBar.VERTICAL,
49828 getBox : function(){
49829 if(this.collapsed){
49830 return this.collapsedEl.getBox();
49832 var box = this.el.getBox();
49834 var sh = this.split.el.getHeight();
49841 updateBox : function(box){
49842 if(this.split && !this.collapsed){
49843 var sh = this.split.el.getHeight();
49846 this.split.el.setLeft(box.x);
49847 this.split.el.setTop(box.y-sh);
49848 this.split.el.setWidth(box.width);
49850 if(this.collapsed){
49851 this.updateBody(box.width, null);
49853 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49857 Roo.EastLayoutRegion = function(mgr, config){
49858 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
49860 this.split.placement = Roo.SplitBar.RIGHT;
49861 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49862 this.split.el.addClass("x-layout-split-h");
49864 var size = config.initialSize || config.width;
49865 if(typeof size != "undefined"){
49866 this.el.setWidth(size);
49869 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
49870 orientation: Roo.SplitBar.HORIZONTAL,
49871 getBox : function(){
49872 if(this.collapsed){
49873 return this.collapsedEl.getBox();
49875 var box = this.el.getBox();
49877 var sw = this.split.el.getWidth();
49884 updateBox : function(box){
49885 if(this.split && !this.collapsed){
49886 var sw = this.split.el.getWidth();
49888 this.split.el.setLeft(box.x);
49889 this.split.el.setTop(box.y);
49890 this.split.el.setHeight(box.height);
49893 if(this.collapsed){
49894 this.updateBody(null, box.height);
49896 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49900 Roo.WestLayoutRegion = function(mgr, config){
49901 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
49903 this.split.placement = Roo.SplitBar.LEFT;
49904 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49905 this.split.el.addClass("x-layout-split-h");
49907 var size = config.initialSize || config.width;
49908 if(typeof size != "undefined"){
49909 this.el.setWidth(size);
49912 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
49913 orientation: Roo.SplitBar.HORIZONTAL,
49914 getBox : function(){
49915 if(this.collapsed){
49916 return this.collapsedEl.getBox();
49918 var box = this.el.getBox();
49920 box.width += this.split.el.getWidth();
49925 updateBox : function(box){
49926 if(this.split && !this.collapsed){
49927 var sw = this.split.el.getWidth();
49929 this.split.el.setLeft(box.x+box.width);
49930 this.split.el.setTop(box.y);
49931 this.split.el.setHeight(box.height);
49933 if(this.collapsed){
49934 this.updateBody(null, box.height);
49936 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49941 * Ext JS Library 1.1.1
49942 * Copyright(c) 2006-2007, Ext JS, LLC.
49944 * Originally Released Under LGPL - original licence link has changed is not relivant.
49947 * <script type="text/javascript">
49952 * Private internal class for reading and applying state
49954 Roo.LayoutStateManager = function(layout){
49955 // default empty state
49964 Roo.LayoutStateManager.prototype = {
49965 init : function(layout, provider){
49966 this.provider = provider;
49967 var state = provider.get(layout.id+"-layout-state");
49969 var wasUpdating = layout.isUpdating();
49971 layout.beginUpdate();
49973 for(var key in state){
49974 if(typeof state[key] != "function"){
49975 var rstate = state[key];
49976 var r = layout.getRegion(key);
49979 r.resizeTo(rstate.size);
49981 if(rstate.collapsed == true){
49984 r.expand(null, true);
49990 layout.endUpdate();
49992 this.state = state;
49994 this.layout = layout;
49995 layout.on("regionresized", this.onRegionResized, this);
49996 layout.on("regioncollapsed", this.onRegionCollapsed, this);
49997 layout.on("regionexpanded", this.onRegionExpanded, this);
50000 storeState : function(){
50001 this.provider.set(this.layout.id+"-layout-state", this.state);
50004 onRegionResized : function(region, newSize){
50005 this.state[region.getPosition()].size = newSize;
50009 onRegionCollapsed : function(region){
50010 this.state[region.getPosition()].collapsed = true;
50014 onRegionExpanded : function(region){
50015 this.state[region.getPosition()].collapsed = false;
50020 * Ext JS Library 1.1.1
50021 * Copyright(c) 2006-2007, Ext JS, LLC.
50023 * Originally Released Under LGPL - original licence link has changed is not relivant.
50026 * <script type="text/javascript">
50029 * @class Roo.ContentPanel
50030 * @extends Roo.util.Observable
50031 * A basic ContentPanel element.
50032 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50033 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50034 * @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
50035 * @cfg {Boolean} closable True if the panel can be closed/removed
50036 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50037 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50038 * @cfg {Toolbar} toolbar A toolbar for this panel
50039 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50040 * @cfg {String} title The title for this panel
50041 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50042 * @cfg {String} url Calls {@link #setUrl} with this value
50043 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50044 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50045 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50046 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50049 * Create a new ContentPanel.
50050 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50051 * @param {String/Object} config A string to set only the title or a config object
50052 * @param {String} content (optional) Set the HTML content for this panel
50053 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50055 Roo.ContentPanel = function(el, config, content){
50059 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50063 if (config && config.parentLayout) {
50064 el = config.parentLayout.el.createChild();
50067 if(el.autoCreate){ // xtype is available if this is called from factory
50071 this.el = Roo.get(el);
50072 if(!this.el && config && config.autoCreate){
50073 if(typeof config.autoCreate == "object"){
50074 if(!config.autoCreate.id){
50075 config.autoCreate.id = config.id||el;
50077 this.el = Roo.DomHelper.append(document.body,
50078 config.autoCreate, true);
50080 this.el = Roo.DomHelper.append(document.body,
50081 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50084 this.closable = false;
50085 this.loaded = false;
50086 this.active = false;
50087 if(typeof config == "string"){
50088 this.title = config;
50090 Roo.apply(this, config);
50093 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50094 this.wrapEl = this.el.wrap();
50095 this.toolbar.container = this.el.insertSibling(false, 'before');
50096 this.toolbar = new Roo.Toolbar(this.toolbar);
50099 // xtype created footer. - not sure if will work as we normally have to render first..
50100 if (this.footer && !this.footer.el && this.footer.xtype) {
50101 if (!this.wrapEl) {
50102 this.wrapEl = this.el.wrap();
50105 this.footer.container = this.wrapEl.createChild();
50107 this.footer = Roo.factory(this.footer, Roo);
50112 this.resizeEl = Roo.get(this.resizeEl, true);
50114 this.resizeEl = this.el;
50116 // handle view.xtype
50124 * Fires when this panel is activated.
50125 * @param {Roo.ContentPanel} this
50129 * @event deactivate
50130 * Fires when this panel is activated.
50131 * @param {Roo.ContentPanel} this
50133 "deactivate" : true,
50137 * Fires when this panel is resized if fitToFrame is true.
50138 * @param {Roo.ContentPanel} this
50139 * @param {Number} width The width after any component adjustments
50140 * @param {Number} height The height after any component adjustments
50146 * Fires when this tab is created
50147 * @param {Roo.ContentPanel} this
50158 if(this.autoScroll){
50159 this.resizeEl.setStyle("overflow", "auto");
50161 // fix randome scrolling
50162 this.el.on('scroll', function() {
50163 Roo.log('fix random scolling');
50164 this.scrollTo('top',0);
50167 content = content || this.content;
50169 this.setContent(content);
50171 if(config && config.url){
50172 this.setUrl(this.url, this.params, this.loadOnce);
50177 Roo.ContentPanel.superclass.constructor.call(this);
50179 if (this.view && typeof(this.view.xtype) != 'undefined') {
50180 this.view.el = this.el.appendChild(document.createElement("div"));
50181 this.view = Roo.factory(this.view);
50182 this.view.render && this.view.render(false, '');
50186 this.fireEvent('render', this);
50189 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50191 setRegion : function(region){
50192 this.region = region;
50194 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50196 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50201 * Returns the toolbar for this Panel if one was configured.
50202 * @return {Roo.Toolbar}
50204 getToolbar : function(){
50205 return this.toolbar;
50208 setActiveState : function(active){
50209 this.active = active;
50211 this.fireEvent("deactivate", this);
50213 this.fireEvent("activate", this);
50217 * Updates this panel's element
50218 * @param {String} content The new content
50219 * @param {Boolean} loadScripts (optional) true to look for and process scripts
50221 setContent : function(content, loadScripts){
50222 this.el.update(content, loadScripts);
50225 ignoreResize : function(w, h){
50226 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
50229 this.lastSize = {width: w, height: h};
50234 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
50235 * @return {Roo.UpdateManager} The UpdateManager
50237 getUpdateManager : function(){
50238 return this.el.getUpdateManager();
50241 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
50242 * @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:
50245 url: "your-url.php",
50246 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
50247 callback: yourFunction,
50248 scope: yourObject, //(optional scope)
50251 text: "Loading...",
50256 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
50257 * 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.
50258 * @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}
50259 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
50260 * @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.
50261 * @return {Roo.ContentPanel} this
50264 var um = this.el.getUpdateManager();
50265 um.update.apply(um, arguments);
50271 * 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.
50272 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
50273 * @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)
50274 * @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)
50275 * @return {Roo.UpdateManager} The UpdateManager
50277 setUrl : function(url, params, loadOnce){
50278 if(this.refreshDelegate){
50279 this.removeListener("activate", this.refreshDelegate);
50281 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
50282 this.on("activate", this.refreshDelegate);
50283 return this.el.getUpdateManager();
50286 _handleRefresh : function(url, params, loadOnce){
50287 if(!loadOnce || !this.loaded){
50288 var updater = this.el.getUpdateManager();
50289 updater.update(url, params, this._setLoaded.createDelegate(this));
50293 _setLoaded : function(){
50294 this.loaded = true;
50298 * Returns this panel's id
50301 getId : function(){
50306 * Returns this panel's element - used by regiosn to add.
50307 * @return {Roo.Element}
50309 getEl : function(){
50310 return this.wrapEl || this.el;
50313 adjustForComponents : function(width, height)
50315 //Roo.log('adjustForComponents ');
50316 if(this.resizeEl != this.el){
50317 width -= this.el.getFrameWidth('lr');
50318 height -= this.el.getFrameWidth('tb');
50321 var te = this.toolbar.getEl();
50322 height -= te.getHeight();
50323 te.setWidth(width);
50326 var te = this.footer.getEl();
50327 Roo.log("footer:" + te.getHeight());
50329 height -= te.getHeight();
50330 te.setWidth(width);
50334 if(this.adjustments){
50335 width += this.adjustments[0];
50336 height += this.adjustments[1];
50338 return {"width": width, "height": height};
50341 setSize : function(width, height){
50342 if(this.fitToFrame && !this.ignoreResize(width, height)){
50343 if(this.fitContainer && this.resizeEl != this.el){
50344 this.el.setSize(width, height);
50346 var size = this.adjustForComponents(width, height);
50347 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
50348 this.fireEvent('resize', this, size.width, size.height);
50353 * Returns this panel's title
50356 getTitle : function(){
50361 * Set this panel's title
50362 * @param {String} title
50364 setTitle : function(title){
50365 this.title = title;
50367 this.region.updatePanelTitle(this, title);
50372 * Returns true is this panel was configured to be closable
50373 * @return {Boolean}
50375 isClosable : function(){
50376 return this.closable;
50379 beforeSlide : function(){
50381 this.resizeEl.clip();
50384 afterSlide : function(){
50386 this.resizeEl.unclip();
50390 * Force a content refresh from the URL specified in the {@link #setUrl} method.
50391 * Will fail silently if the {@link #setUrl} method has not been called.
50392 * This does not activate the panel, just updates its content.
50394 refresh : function(){
50395 if(this.refreshDelegate){
50396 this.loaded = false;
50397 this.refreshDelegate();
50402 * Destroys this panel
50404 destroy : function(){
50405 this.el.removeAllListeners();
50406 var tempEl = document.createElement("span");
50407 tempEl.appendChild(this.el.dom);
50408 tempEl.innerHTML = "";
50414 * form - if the content panel contains a form - this is a reference to it.
50415 * @type {Roo.form.Form}
50419 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
50420 * This contains a reference to it.
50426 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
50436 * @param {Object} cfg Xtype definition of item to add.
50439 addxtype : function(cfg) {
50441 if (cfg.xtype.match(/^Form$/)) {
50444 //if (this.footer) {
50445 // el = this.footer.container.insertSibling(false, 'before');
50447 el = this.el.createChild();
50450 this.form = new Roo.form.Form(cfg);
50453 if ( this.form.allItems.length) this.form.render(el.dom);
50456 // should only have one of theses..
50457 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
50458 // views.. should not be just added - used named prop 'view''
50460 cfg.el = this.el.appendChild(document.createElement("div"));
50463 var ret = new Roo.factory(cfg);
50465 ret.render && ret.render(false, ''); // render blank..
50474 * @class Roo.GridPanel
50475 * @extends Roo.ContentPanel
50477 * Create a new GridPanel.
50478 * @param {Roo.grid.Grid} grid The grid for this panel
50479 * @param {String/Object} config A string to set only the panel's title, or a config object
50481 Roo.GridPanel = function(grid, config){
50484 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
50485 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
50487 this.wrapper.dom.appendChild(grid.getGridEl().dom);
50489 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
50492 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
50494 // xtype created footer. - not sure if will work as we normally have to render first..
50495 if (this.footer && !this.footer.el && this.footer.xtype) {
50497 this.footer.container = this.grid.getView().getFooterPanel(true);
50498 this.footer.dataSource = this.grid.dataSource;
50499 this.footer = Roo.factory(this.footer, Roo);
50503 grid.monitorWindowResize = false; // turn off autosizing
50504 grid.autoHeight = false;
50505 grid.autoWidth = false;
50507 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
50510 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
50511 getId : function(){
50512 return this.grid.id;
50516 * Returns the grid for this panel
50517 * @return {Roo.grid.Grid}
50519 getGrid : function(){
50523 setSize : function(width, height){
50524 if(!this.ignoreResize(width, height)){
50525 var grid = this.grid;
50526 var size = this.adjustForComponents(width, height);
50527 grid.getGridEl().setSize(size.width, size.height);
50532 beforeSlide : function(){
50533 this.grid.getView().scroller.clip();
50536 afterSlide : function(){
50537 this.grid.getView().scroller.unclip();
50540 destroy : function(){
50541 this.grid.destroy();
50543 Roo.GridPanel.superclass.destroy.call(this);
50549 * @class Roo.NestedLayoutPanel
50550 * @extends Roo.ContentPanel
50552 * Create a new NestedLayoutPanel.
50555 * @param {Roo.BorderLayout} layout The layout for this panel
50556 * @param {String/Object} config A string to set only the title or a config object
50558 Roo.NestedLayoutPanel = function(layout, config)
50560 // construct with only one argument..
50561 /* FIXME - implement nicer consturctors
50562 if (layout.layout) {
50564 layout = config.layout;
50565 delete config.layout;
50567 if (layout.xtype && !layout.getEl) {
50568 // then layout needs constructing..
50569 layout = Roo.factory(layout, Roo);
50574 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
50576 layout.monitorWindowResize = false; // turn off autosizing
50577 this.layout = layout;
50578 this.layout.getEl().addClass("x-layout-nested-layout");
50585 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
50587 setSize : function(width, height){
50588 if(!this.ignoreResize(width, height)){
50589 var size = this.adjustForComponents(width, height);
50590 var el = this.layout.getEl();
50591 el.setSize(size.width, size.height);
50592 var touch = el.dom.offsetWidth;
50593 this.layout.layout();
50594 // ie requires a double layout on the first pass
50595 if(Roo.isIE && !this.initialized){
50596 this.initialized = true;
50597 this.layout.layout();
50602 // activate all subpanels if not currently active..
50604 setActiveState : function(active){
50605 this.active = active;
50607 this.fireEvent("deactivate", this);
50611 this.fireEvent("activate", this);
50612 // not sure if this should happen before or after..
50613 if (!this.layout) {
50614 return; // should not happen..
50617 for (var r in this.layout.regions) {
50618 reg = this.layout.getRegion(r);
50619 if (reg.getActivePanel()) {
50620 //reg.showPanel(reg.getActivePanel()); // force it to activate..
50621 reg.setActivePanel(reg.getActivePanel());
50624 if (!reg.panels.length) {
50627 reg.showPanel(reg.getPanel(0));
50636 * Returns the nested BorderLayout for this panel
50637 * @return {Roo.BorderLayout}
50639 getLayout : function(){
50640 return this.layout;
50644 * Adds a xtype elements to the layout of the nested panel
50648 xtype : 'ContentPanel',
50655 xtype : 'NestedLayoutPanel',
50661 items : [ ... list of content panels or nested layout panels.. ]
50665 * @param {Object} cfg Xtype definition of item to add.
50667 addxtype : function(cfg) {
50668 return this.layout.addxtype(cfg);
50673 Roo.ScrollPanel = function(el, config, content){
50674 config = config || {};
50675 config.fitToFrame = true;
50676 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
50678 this.el.dom.style.overflow = "hidden";
50679 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
50680 this.el.removeClass("x-layout-inactive-content");
50681 this.el.on("mousewheel", this.onWheel, this);
50683 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
50684 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
50685 up.unselectable(); down.unselectable();
50686 up.on("click", this.scrollUp, this);
50687 down.on("click", this.scrollDown, this);
50688 up.addClassOnOver("x-scroller-btn-over");
50689 down.addClassOnOver("x-scroller-btn-over");
50690 up.addClassOnClick("x-scroller-btn-click");
50691 down.addClassOnClick("x-scroller-btn-click");
50692 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
50694 this.resizeEl = this.el;
50695 this.el = wrap; this.up = up; this.down = down;
50698 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
50700 wheelIncrement : 5,
50701 scrollUp : function(){
50702 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
50705 scrollDown : function(){
50706 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
50709 afterScroll : function(){
50710 var el = this.resizeEl;
50711 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
50712 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50713 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50716 setSize : function(){
50717 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
50718 this.afterScroll();
50721 onWheel : function(e){
50722 var d = e.getWheelDelta();
50723 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
50724 this.afterScroll();
50728 setContent : function(content, loadScripts){
50729 this.resizeEl.update(content, loadScripts);
50743 * @class Roo.TreePanel
50744 * @extends Roo.ContentPanel
50746 * Create a new TreePanel. - defaults to fit/scoll contents.
50747 * @param {String/Object} config A string to set only the panel's title, or a config object
50748 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
50750 Roo.TreePanel = function(config){
50751 var el = config.el;
50752 var tree = config.tree;
50753 delete config.tree;
50754 delete config.el; // hopefull!
50756 // wrapper for IE7 strict & safari scroll issue
50758 var treeEl = el.createChild();
50759 config.resizeEl = treeEl;
50763 Roo.TreePanel.superclass.constructor.call(this, el, config);
50766 this.tree = new Roo.tree.TreePanel(treeEl , tree);
50767 //console.log(tree);
50768 this.on('activate', function()
50770 if (this.tree.rendered) {
50773 //console.log('render tree');
50774 this.tree.render();
50776 // this should not be needed.. - it's actually the 'el' that resizes?
50777 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
50779 //this.on('resize', function (cp, w, h) {
50780 // this.tree.innerCt.setWidth(w);
50781 // this.tree.innerCt.setHeight(h);
50782 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
50789 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
50806 * Ext JS Library 1.1.1
50807 * Copyright(c) 2006-2007, Ext JS, LLC.
50809 * Originally Released Under LGPL - original licence link has changed is not relivant.
50812 * <script type="text/javascript">
50817 * @class Roo.ReaderLayout
50818 * @extends Roo.BorderLayout
50819 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
50820 * center region containing two nested regions (a top one for a list view and one for item preview below),
50821 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
50822 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
50823 * expedites the setup of the overall layout and regions for this common application style.
50826 var reader = new Roo.ReaderLayout();
50827 var CP = Roo.ContentPanel; // shortcut for adding
50829 reader.beginUpdate();
50830 reader.add("north", new CP("north", "North"));
50831 reader.add("west", new CP("west", {title: "West"}));
50832 reader.add("east", new CP("east", {title: "East"}));
50834 reader.regions.listView.add(new CP("listView", "List"));
50835 reader.regions.preview.add(new CP("preview", "Preview"));
50836 reader.endUpdate();
50839 * Create a new ReaderLayout
50840 * @param {Object} config Configuration options
50841 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
50842 * document.body if omitted)
50844 Roo.ReaderLayout = function(config, renderTo){
50845 var c = config || {size:{}};
50846 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
50847 north: c.north !== false ? Roo.apply({
50851 }, c.north) : false,
50852 west: c.west !== false ? Roo.apply({
50860 margins:{left:5,right:0,bottom:5,top:5},
50861 cmargins:{left:5,right:5,bottom:5,top:5}
50862 }, c.west) : false,
50863 east: c.east !== false ? Roo.apply({
50871 margins:{left:0,right:5,bottom:5,top:5},
50872 cmargins:{left:5,right:5,bottom:5,top:5}
50873 }, c.east) : false,
50874 center: Roo.apply({
50875 tabPosition: 'top',
50879 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
50883 this.el.addClass('x-reader');
50885 this.beginUpdate();
50887 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
50888 south: c.preview !== false ? Roo.apply({
50895 cmargins:{top:5,left:0, right:0, bottom:0}
50896 }, c.preview) : false,
50897 center: Roo.apply({
50903 this.add('center', new Roo.NestedLayoutPanel(inner,
50904 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
50908 this.regions.preview = inner.getRegion('south');
50909 this.regions.listView = inner.getRegion('center');
50912 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
50914 * Ext JS Library 1.1.1
50915 * Copyright(c) 2006-2007, Ext JS, LLC.
50917 * Originally Released Under LGPL - original licence link has changed is not relivant.
50920 * <script type="text/javascript">
50924 * @class Roo.grid.Grid
50925 * @extends Roo.util.Observable
50926 * This class represents the primary interface of a component based grid control.
50927 * <br><br>Usage:<pre><code>
50928 var grid = new Roo.grid.Grid("my-container-id", {
50931 selModel: mySelectionModel,
50932 autoSizeColumns: true,
50933 monitorWindowResize: false,
50934 trackMouseOver: true
50939 * <b>Common Problems:</b><br/>
50940 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
50941 * element will correct this<br/>
50942 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
50943 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
50944 * are unpredictable.<br/>
50945 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
50946 * grid to calculate dimensions/offsets.<br/>
50948 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
50949 * The container MUST have some type of size defined for the grid to fill. The container will be
50950 * automatically set to position relative if it isn't already.
50951 * @param {Object} config A config object that sets properties on this grid.
50953 Roo.grid.Grid = function(container, config){
50954 // initialize the container
50955 this.container = Roo.get(container);
50956 this.container.update("");
50957 this.container.setStyle("overflow", "hidden");
50958 this.container.addClass('x-grid-container');
50960 this.id = this.container.id;
50962 Roo.apply(this, config);
50963 // check and correct shorthanded configs
50965 this.dataSource = this.ds;
50969 this.colModel = this.cm;
50973 this.selModel = this.sm;
50977 if (this.selModel) {
50978 this.selModel = Roo.factory(this.selModel, Roo.grid);
50979 this.sm = this.selModel;
50980 this.sm.xmodule = this.xmodule || false;
50982 if (typeof(this.colModel.config) == 'undefined') {
50983 this.colModel = new Roo.grid.ColumnModel(this.colModel);
50984 this.cm = this.colModel;
50985 this.cm.xmodule = this.xmodule || false;
50987 if (this.dataSource) {
50988 this.dataSource= Roo.factory(this.dataSource, Roo.data);
50989 this.ds = this.dataSource;
50990 this.ds.xmodule = this.xmodule || false;
50997 this.container.setWidth(this.width);
51001 this.container.setHeight(this.height);
51008 * The raw click event for the entire grid.
51009 * @param {Roo.EventObject} e
51014 * The raw dblclick event for the entire grid.
51015 * @param {Roo.EventObject} e
51019 * @event contextmenu
51020 * The raw contextmenu event for the entire grid.
51021 * @param {Roo.EventObject} e
51023 "contextmenu" : true,
51026 * The raw mousedown event for the entire grid.
51027 * @param {Roo.EventObject} e
51029 "mousedown" : true,
51032 * The raw mouseup event for the entire grid.
51033 * @param {Roo.EventObject} e
51038 * The raw mouseover event for the entire grid.
51039 * @param {Roo.EventObject} e
51041 "mouseover" : true,
51044 * The raw mouseout event for the entire grid.
51045 * @param {Roo.EventObject} e
51050 * The raw keypress event for the entire grid.
51051 * @param {Roo.EventObject} e
51056 * The raw keydown event for the entire grid.
51057 * @param {Roo.EventObject} e
51065 * Fires when a cell is clicked
51066 * @param {Grid} this
51067 * @param {Number} rowIndex
51068 * @param {Number} columnIndex
51069 * @param {Roo.EventObject} e
51071 "cellclick" : true,
51073 * @event celldblclick
51074 * Fires when a cell is double clicked
51075 * @param {Grid} this
51076 * @param {Number} rowIndex
51077 * @param {Number} columnIndex
51078 * @param {Roo.EventObject} e
51080 "celldblclick" : true,
51083 * Fires when a row is clicked
51084 * @param {Grid} this
51085 * @param {Number} rowIndex
51086 * @param {Roo.EventObject} e
51090 * @event rowdblclick
51091 * Fires when a row is double clicked
51092 * @param {Grid} this
51093 * @param {Number} rowIndex
51094 * @param {Roo.EventObject} e
51096 "rowdblclick" : true,
51098 * @event headerclick
51099 * Fires when a header is clicked
51100 * @param {Grid} this
51101 * @param {Number} columnIndex
51102 * @param {Roo.EventObject} e
51104 "headerclick" : true,
51106 * @event headerdblclick
51107 * Fires when a header cell is double clicked
51108 * @param {Grid} this
51109 * @param {Number} columnIndex
51110 * @param {Roo.EventObject} e
51112 "headerdblclick" : true,
51114 * @event rowcontextmenu
51115 * Fires when a row is right clicked
51116 * @param {Grid} this
51117 * @param {Number} rowIndex
51118 * @param {Roo.EventObject} e
51120 "rowcontextmenu" : true,
51122 * @event cellcontextmenu
51123 * Fires when a cell is right clicked
51124 * @param {Grid} this
51125 * @param {Number} rowIndex
51126 * @param {Number} cellIndex
51127 * @param {Roo.EventObject} e
51129 "cellcontextmenu" : true,
51131 * @event headercontextmenu
51132 * Fires when a header is right clicked
51133 * @param {Grid} this
51134 * @param {Number} columnIndex
51135 * @param {Roo.EventObject} e
51137 "headercontextmenu" : true,
51139 * @event bodyscroll
51140 * Fires when the body element is scrolled
51141 * @param {Number} scrollLeft
51142 * @param {Number} scrollTop
51144 "bodyscroll" : true,
51146 * @event columnresize
51147 * Fires when the user resizes a column
51148 * @param {Number} columnIndex
51149 * @param {Number} newSize
51151 "columnresize" : true,
51153 * @event columnmove
51154 * Fires when the user moves a column
51155 * @param {Number} oldIndex
51156 * @param {Number} newIndex
51158 "columnmove" : true,
51161 * Fires when row(s) start being dragged
51162 * @param {Grid} this
51163 * @param {Roo.GridDD} dd The drag drop object
51164 * @param {event} e The raw browser event
51166 "startdrag" : true,
51169 * Fires when a drag operation is complete
51170 * @param {Grid} this
51171 * @param {Roo.GridDD} dd The drag drop object
51172 * @param {event} e The raw browser event
51177 * Fires when dragged row(s) are dropped on a valid DD target
51178 * @param {Grid} this
51179 * @param {Roo.GridDD} dd The drag drop object
51180 * @param {String} targetId The target drag drop object
51181 * @param {event} e The raw browser event
51186 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51187 * @param {Grid} this
51188 * @param {Roo.GridDD} dd The drag drop object
51189 * @param {String} targetId The target drag drop object
51190 * @param {event} e The raw browser event
51195 * Fires when the dragged row(s) first cross another DD target while being dragged
51196 * @param {Grid} this
51197 * @param {Roo.GridDD} dd The drag drop object
51198 * @param {String} targetId The target drag drop object
51199 * @param {event} e The raw browser event
51201 "dragenter" : true,
51204 * Fires when the dragged row(s) leave another DD target while being dragged
51205 * @param {Grid} this
51206 * @param {Roo.GridDD} dd The drag drop object
51207 * @param {String} targetId The target drag drop object
51208 * @param {event} e The raw browser event
51213 * Fires when a row is rendered, so you can change add a style to it.
51214 * @param {GridView} gridview The grid view
51215 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
51221 * Fires when the grid is rendered
51222 * @param {Grid} grid
51227 Roo.grid.Grid.superclass.constructor.call(this);
51229 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
51232 * @cfg {String} ddGroup - drag drop group.
51236 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
51238 minColumnWidth : 25,
51241 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
51242 * <b>on initial render.</b> It is more efficient to explicitly size the columns
51243 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
51245 autoSizeColumns : false,
51248 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
51250 autoSizeHeaders : true,
51253 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
51255 monitorWindowResize : true,
51258 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
51259 * rows measured to get a columns size. Default is 0 (all rows).
51261 maxRowsToMeasure : 0,
51264 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
51266 trackMouseOver : true,
51269 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
51273 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
51275 enableDragDrop : false,
51278 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
51280 enableColumnMove : true,
51283 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
51285 enableColumnHide : true,
51288 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
51290 enableRowHeightSync : false,
51293 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
51298 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
51300 autoHeight : false,
51303 * @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.
51305 autoExpandColumn : false,
51308 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
51311 autoExpandMin : 50,
51314 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
51316 autoExpandMax : 1000,
51319 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
51324 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
51328 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
51338 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
51339 * of a fixed width. Default is false.
51342 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
51345 * Called once after all setup has been completed and the grid is ready to be rendered.
51346 * @return {Roo.grid.Grid} this
51348 render : function()
51350 var c = this.container;
51351 // try to detect autoHeight/width mode
51352 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
51353 this.autoHeight = true;
51355 var view = this.getView();
51358 c.on("click", this.onClick, this);
51359 c.on("dblclick", this.onDblClick, this);
51360 c.on("contextmenu", this.onContextMenu, this);
51361 c.on("keydown", this.onKeyDown, this);
51363 c.on("touchstart", this.onTouchStart, this);
51366 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
51368 this.getSelectionModel().init(this);
51373 this.loadMask = new Roo.LoadMask(this.container,
51374 Roo.apply({store:this.dataSource}, this.loadMask));
51378 if (this.toolbar && this.toolbar.xtype) {
51379 this.toolbar.container = this.getView().getHeaderPanel(true);
51380 this.toolbar = new Roo.Toolbar(this.toolbar);
51382 if (this.footer && this.footer.xtype) {
51383 this.footer.dataSource = this.getDataSource();
51384 this.footer.container = this.getView().getFooterPanel(true);
51385 this.footer = Roo.factory(this.footer, Roo);
51387 if (this.dropTarget && this.dropTarget.xtype) {
51388 delete this.dropTarget.xtype;
51389 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
51393 this.rendered = true;
51394 this.fireEvent('render', this);
51399 * Reconfigures the grid to use a different Store and Column Model.
51400 * The View will be bound to the new objects and refreshed.
51401 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
51402 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
51404 reconfigure : function(dataSource, colModel){
51406 this.loadMask.destroy();
51407 this.loadMask = new Roo.LoadMask(this.container,
51408 Roo.apply({store:dataSource}, this.loadMask));
51410 this.view.bind(dataSource, colModel);
51411 this.dataSource = dataSource;
51412 this.colModel = colModel;
51413 this.view.refresh(true);
51417 onKeyDown : function(e){
51418 this.fireEvent("keydown", e);
51422 * Destroy this grid.
51423 * @param {Boolean} removeEl True to remove the element
51425 destroy : function(removeEl, keepListeners){
51427 this.loadMask.destroy();
51429 var c = this.container;
51430 c.removeAllListeners();
51431 this.view.destroy();
51432 this.colModel.purgeListeners();
51433 if(!keepListeners){
51434 this.purgeListeners();
51437 if(removeEl === true){
51443 processEvent : function(name, e){
51444 // does this fire select???
51445 Roo.log('grid:processEvent ' + name);
51447 if (name != 'touchstart' ) {
51448 this.fireEvent(name, e);
51451 var t = e.getTarget();
51453 var header = v.findHeaderIndex(t);
51454 if(header !== false){
51455 this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
51457 var row = v.findRowIndex(t);
51458 var cell = v.findCellIndex(t);
51459 if (name == 'touchstart') {
51460 // first touch is always a click.
51461 // hopefull this happens after selection is updated.?
51464 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
51465 var cs = this.selModel.getSelectedCell();
51466 if (row == cs[0] && cell == cs[1]){
51470 if (typeof(this.selModel.getSelections) != 'undefined') {
51471 var cs = this.selModel.getSelections();
51472 var ds = this.dataSource;
51473 if (cs.length == 1 && ds.getAt(row) == cs[0]){
51484 this.fireEvent("row" + name, this, row, e);
51485 if(cell !== false){
51486 this.fireEvent("cell" + name, this, row, cell, e);
51493 onClick : function(e){
51494 this.processEvent("click", e);
51497 onTouchStart : function(e){
51498 this.processEvent("touchstart", e);
51502 onContextMenu : function(e, t){
51503 this.processEvent("contextmenu", e);
51507 onDblClick : function(e){
51508 this.processEvent("dblclick", e);
51512 walkCells : function(row, col, step, fn, scope){
51513 var cm = this.colModel, clen = cm.getColumnCount();
51514 var ds = this.dataSource, rlen = ds.getCount(), first = true;
51526 if(fn.call(scope || this, row, col, cm) === true){
51544 if(fn.call(scope || this, row, col, cm) === true){
51556 getSelections : function(){
51557 return this.selModel.getSelections();
51561 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
51562 * but if manual update is required this method will initiate it.
51564 autoSize : function(){
51566 this.view.layout();
51567 if(this.view.adjustForScroll){
51568 this.view.adjustForScroll();
51574 * Returns the grid's underlying element.
51575 * @return {Element} The element
51577 getGridEl : function(){
51578 return this.container;
51581 // private for compatibility, overridden by editor grid
51582 stopEditing : function(){},
51585 * Returns the grid's SelectionModel.
51586 * @return {SelectionModel}
51588 getSelectionModel : function(){
51589 if(!this.selModel){
51590 this.selModel = new Roo.grid.RowSelectionModel();
51592 return this.selModel;
51596 * Returns the grid's DataSource.
51597 * @return {DataSource}
51599 getDataSource : function(){
51600 return this.dataSource;
51604 * Returns the grid's ColumnModel.
51605 * @return {ColumnModel}
51607 getColumnModel : function(){
51608 return this.colModel;
51612 * Returns the grid's GridView object.
51613 * @return {GridView}
51615 getView : function(){
51617 this.view = new Roo.grid.GridView(this.viewConfig);
51622 * Called to get grid's drag proxy text, by default returns this.ddText.
51625 getDragDropText : function(){
51626 var count = this.selModel.getCount();
51627 return String.format(this.ddText, count, count == 1 ? '' : 's');
51631 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
51632 * %0 is replaced with the number of selected rows.
51635 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
51637 * Ext JS Library 1.1.1
51638 * Copyright(c) 2006-2007, Ext JS, LLC.
51640 * Originally Released Under LGPL - original licence link has changed is not relivant.
51643 * <script type="text/javascript">
51646 Roo.grid.AbstractGridView = function(){
51650 "beforerowremoved" : true,
51651 "beforerowsinserted" : true,
51652 "beforerefresh" : true,
51653 "rowremoved" : true,
51654 "rowsinserted" : true,
51655 "rowupdated" : true,
51658 Roo.grid.AbstractGridView.superclass.constructor.call(this);
51661 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
51662 rowClass : "x-grid-row",
51663 cellClass : "x-grid-cell",
51664 tdClass : "x-grid-td",
51665 hdClass : "x-grid-hd",
51666 splitClass : "x-grid-hd-split",
51668 init: function(grid){
51670 var cid = this.grid.getGridEl().id;
51671 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
51672 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
51673 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
51674 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
51677 getColumnRenderers : function(){
51678 var renderers = [];
51679 var cm = this.grid.colModel;
51680 var colCount = cm.getColumnCount();
51681 for(var i = 0; i < colCount; i++){
51682 renderers[i] = cm.getRenderer(i);
51687 getColumnIds : function(){
51689 var cm = this.grid.colModel;
51690 var colCount = cm.getColumnCount();
51691 for(var i = 0; i < colCount; i++){
51692 ids[i] = cm.getColumnId(i);
51697 getDataIndexes : function(){
51698 if(!this.indexMap){
51699 this.indexMap = this.buildIndexMap();
51701 return this.indexMap.colToData;
51704 getColumnIndexByDataIndex : function(dataIndex){
51705 if(!this.indexMap){
51706 this.indexMap = this.buildIndexMap();
51708 return this.indexMap.dataToCol[dataIndex];
51712 * Set a css style for a column dynamically.
51713 * @param {Number} colIndex The index of the column
51714 * @param {String} name The css property name
51715 * @param {String} value The css value
51717 setCSSStyle : function(colIndex, name, value){
51718 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
51719 Roo.util.CSS.updateRule(selector, name, value);
51722 generateRules : function(cm){
51723 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
51724 Roo.util.CSS.removeStyleSheet(rulesId);
51725 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51726 var cid = cm.getColumnId(i);
51727 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
51728 this.tdSelector, cid, " {\n}\n",
51729 this.hdSelector, cid, " {\n}\n",
51730 this.splitSelector, cid, " {\n}\n");
51732 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
51736 * Ext JS Library 1.1.1
51737 * Copyright(c) 2006-2007, Ext JS, LLC.
51739 * Originally Released Under LGPL - original licence link has changed is not relivant.
51742 * <script type="text/javascript">
51746 // This is a support class used internally by the Grid components
51747 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
51749 this.view = grid.getView();
51750 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51751 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
51753 this.setHandleElId(Roo.id(hd));
51754 this.setOuterHandleElId(Roo.id(hd2));
51756 this.scroll = false;
51758 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
51760 getDragData : function(e){
51761 var t = Roo.lib.Event.getTarget(e);
51762 var h = this.view.findHeaderCell(t);
51764 return {ddel: h.firstChild, header:h};
51769 onInitDrag : function(e){
51770 this.view.headersDisabled = true;
51771 var clone = this.dragData.ddel.cloneNode(true);
51772 clone.id = Roo.id();
51773 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
51774 this.proxy.update(clone);
51778 afterValidDrop : function(){
51780 setTimeout(function(){
51781 v.headersDisabled = false;
51785 afterInvalidDrop : function(){
51787 setTimeout(function(){
51788 v.headersDisabled = false;
51794 * Ext JS Library 1.1.1
51795 * Copyright(c) 2006-2007, Ext JS, LLC.
51797 * Originally Released Under LGPL - original licence link has changed is not relivant.
51800 * <script type="text/javascript">
51803 // This is a support class used internally by the Grid components
51804 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
51806 this.view = grid.getView();
51807 // split the proxies so they don't interfere with mouse events
51808 this.proxyTop = Roo.DomHelper.append(document.body, {
51809 cls:"col-move-top", html:" "
51811 this.proxyBottom = Roo.DomHelper.append(document.body, {
51812 cls:"col-move-bottom", html:" "
51814 this.proxyTop.hide = this.proxyBottom.hide = function(){
51815 this.setLeftTop(-100,-100);
51816 this.setStyle("visibility", "hidden");
51818 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51819 // temporarily disabled
51820 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
51821 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
51823 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
51824 proxyOffsets : [-4, -9],
51825 fly: Roo.Element.fly,
51827 getTargetFromEvent : function(e){
51828 var t = Roo.lib.Event.getTarget(e);
51829 var cindex = this.view.findCellIndex(t);
51830 if(cindex !== false){
51831 return this.view.getHeaderCell(cindex);
51836 nextVisible : function(h){
51837 var v = this.view, cm = this.grid.colModel;
51840 if(!cm.isHidden(v.getCellIndex(h))){
51848 prevVisible : function(h){
51849 var v = this.view, cm = this.grid.colModel;
51852 if(!cm.isHidden(v.getCellIndex(h))){
51860 positionIndicator : function(h, n, e){
51861 var x = Roo.lib.Event.getPageX(e);
51862 var r = Roo.lib.Dom.getRegion(n.firstChild);
51863 var px, pt, py = r.top + this.proxyOffsets[1];
51864 if((r.right - x) <= (r.right-r.left)/2){
51865 px = r.right+this.view.borderWidth;
51871 var oldIndex = this.view.getCellIndex(h);
51872 var newIndex = this.view.getCellIndex(n);
51874 if(this.grid.colModel.isFixed(newIndex)){
51878 var locked = this.grid.colModel.isLocked(newIndex);
51883 if(oldIndex < newIndex){
51886 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
51889 px += this.proxyOffsets[0];
51890 this.proxyTop.setLeftTop(px, py);
51891 this.proxyTop.show();
51892 if(!this.bottomOffset){
51893 this.bottomOffset = this.view.mainHd.getHeight();
51895 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
51896 this.proxyBottom.show();
51900 onNodeEnter : function(n, dd, e, data){
51901 if(data.header != n){
51902 this.positionIndicator(data.header, n, e);
51906 onNodeOver : function(n, dd, e, data){
51907 var result = false;
51908 if(data.header != n){
51909 result = this.positionIndicator(data.header, n, e);
51912 this.proxyTop.hide();
51913 this.proxyBottom.hide();
51915 return result ? this.dropAllowed : this.dropNotAllowed;
51918 onNodeOut : function(n, dd, e, data){
51919 this.proxyTop.hide();
51920 this.proxyBottom.hide();
51923 onNodeDrop : function(n, dd, e, data){
51924 var h = data.header;
51926 var cm = this.grid.colModel;
51927 var x = Roo.lib.Event.getPageX(e);
51928 var r = Roo.lib.Dom.getRegion(n.firstChild);
51929 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
51930 var oldIndex = this.view.getCellIndex(h);
51931 var newIndex = this.view.getCellIndex(n);
51932 var locked = cm.isLocked(newIndex);
51936 if(oldIndex < newIndex){
51939 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
51942 cm.setLocked(oldIndex, locked, true);
51943 cm.moveColumn(oldIndex, newIndex);
51944 this.grid.fireEvent("columnmove", oldIndex, newIndex);
51952 * Ext JS Library 1.1.1
51953 * Copyright(c) 2006-2007, Ext JS, LLC.
51955 * Originally Released Under LGPL - original licence link has changed is not relivant.
51958 * <script type="text/javascript">
51962 * @class Roo.grid.GridView
51963 * @extends Roo.util.Observable
51966 * @param {Object} config
51968 Roo.grid.GridView = function(config){
51969 Roo.grid.GridView.superclass.constructor.call(this);
51972 Roo.apply(this, config);
51975 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
51977 unselectable : 'unselectable="on"',
51978 unselectableCls : 'x-unselectable',
51981 rowClass : "x-grid-row",
51983 cellClass : "x-grid-col",
51985 tdClass : "x-grid-td",
51987 hdClass : "x-grid-hd",
51989 splitClass : "x-grid-split",
51991 sortClasses : ["sort-asc", "sort-desc"],
51993 enableMoveAnim : false,
51997 dh : Roo.DomHelper,
51999 fly : Roo.Element.fly,
52001 css : Roo.util.CSS,
52007 scrollIncrement : 22,
52009 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52011 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52013 bind : function(ds, cm){
52015 this.ds.un("load", this.onLoad, this);
52016 this.ds.un("datachanged", this.onDataChange, this);
52017 this.ds.un("add", this.onAdd, this);
52018 this.ds.un("remove", this.onRemove, this);
52019 this.ds.un("update", this.onUpdate, this);
52020 this.ds.un("clear", this.onClear, this);
52023 ds.on("load", this.onLoad, this);
52024 ds.on("datachanged", this.onDataChange, this);
52025 ds.on("add", this.onAdd, this);
52026 ds.on("remove", this.onRemove, this);
52027 ds.on("update", this.onUpdate, this);
52028 ds.on("clear", this.onClear, this);
52033 this.cm.un("widthchange", this.onColWidthChange, this);
52034 this.cm.un("headerchange", this.onHeaderChange, this);
52035 this.cm.un("hiddenchange", this.onHiddenChange, this);
52036 this.cm.un("columnmoved", this.onColumnMove, this);
52037 this.cm.un("columnlockchange", this.onColumnLock, this);
52040 this.generateRules(cm);
52041 cm.on("widthchange", this.onColWidthChange, this);
52042 cm.on("headerchange", this.onHeaderChange, this);
52043 cm.on("hiddenchange", this.onHiddenChange, this);
52044 cm.on("columnmoved", this.onColumnMove, this);
52045 cm.on("columnlockchange", this.onColumnLock, this);
52050 init: function(grid){
52051 Roo.grid.GridView.superclass.init.call(this, grid);
52053 this.bind(grid.dataSource, grid.colModel);
52055 grid.on("headerclick", this.handleHeaderClick, this);
52057 if(grid.trackMouseOver){
52058 grid.on("mouseover", this.onRowOver, this);
52059 grid.on("mouseout", this.onRowOut, this);
52061 grid.cancelTextSelection = function(){};
52062 this.gridId = grid.id;
52064 var tpls = this.templates || {};
52067 tpls.master = new Roo.Template(
52068 '<div class="x-grid" hidefocus="true">',
52069 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52070 '<div class="x-grid-topbar"></div>',
52071 '<div class="x-grid-scroller"><div></div></div>',
52072 '<div class="x-grid-locked">',
52073 '<div class="x-grid-header">{lockedHeader}</div>',
52074 '<div class="x-grid-body">{lockedBody}</div>',
52076 '<div class="x-grid-viewport">',
52077 '<div class="x-grid-header">{header}</div>',
52078 '<div class="x-grid-body">{body}</div>',
52080 '<div class="x-grid-bottombar"></div>',
52082 '<div class="x-grid-resize-proxy"> </div>',
52085 tpls.master.disableformats = true;
52089 tpls.header = new Roo.Template(
52090 '<table border="0" cellspacing="0" cellpadding="0">',
52091 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52094 tpls.header.disableformats = true;
52096 tpls.header.compile();
52099 tpls.hcell = new Roo.Template(
52100 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52101 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52104 tpls.hcell.disableFormats = true;
52106 tpls.hcell.compile();
52109 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52110 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52111 tpls.hsplit.disableFormats = true;
52113 tpls.hsplit.compile();
52116 tpls.body = new Roo.Template(
52117 '<table border="0" cellspacing="0" cellpadding="0">',
52118 "<tbody>{rows}</tbody>",
52121 tpls.body.disableFormats = true;
52123 tpls.body.compile();
52126 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52127 tpls.row.disableFormats = true;
52129 tpls.row.compile();
52132 tpls.cell = new Roo.Template(
52133 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52134 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52135 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52138 tpls.cell.disableFormats = true;
52140 tpls.cell.compile();
52142 this.templates = tpls;
52145 // remap these for backwards compat
52146 onColWidthChange : function(){
52147 this.updateColumns.apply(this, arguments);
52149 onHeaderChange : function(){
52150 this.updateHeaders.apply(this, arguments);
52152 onHiddenChange : function(){
52153 this.handleHiddenChange.apply(this, arguments);
52155 onColumnMove : function(){
52156 this.handleColumnMove.apply(this, arguments);
52158 onColumnLock : function(){
52159 this.handleLockChange.apply(this, arguments);
52162 onDataChange : function(){
52164 this.updateHeaderSortState();
52167 onClear : function(){
52171 onUpdate : function(ds, record){
52172 this.refreshRow(record);
52175 refreshRow : function(record){
52176 var ds = this.ds, index;
52177 if(typeof record == 'number'){
52179 record = ds.getAt(index);
52181 index = ds.indexOf(record);
52183 this.insertRows(ds, index, index, true);
52184 this.onRemove(ds, record, index+1, true);
52185 this.syncRowHeights(index, index);
52187 this.fireEvent("rowupdated", this, index, record);
52190 onAdd : function(ds, records, index){
52191 this.insertRows(ds, index, index + (records.length-1));
52194 onRemove : function(ds, record, index, isUpdate){
52195 if(isUpdate !== true){
52196 this.fireEvent("beforerowremoved", this, index, record);
52198 var bt = this.getBodyTable(), lt = this.getLockedTable();
52199 if(bt.rows[index]){
52200 bt.firstChild.removeChild(bt.rows[index]);
52202 if(lt.rows[index]){
52203 lt.firstChild.removeChild(lt.rows[index]);
52205 if(isUpdate !== true){
52206 this.stripeRows(index);
52207 this.syncRowHeights(index, index);
52209 this.fireEvent("rowremoved", this, index, record);
52213 onLoad : function(){
52214 this.scrollToTop();
52218 * Scrolls the grid to the top
52220 scrollToTop : function(){
52222 this.scroller.dom.scrollTop = 0;
52228 * Gets a panel in the header of the grid that can be used for toolbars etc.
52229 * After modifying the contents of this panel a call to grid.autoSize() may be
52230 * required to register any changes in size.
52231 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
52232 * @return Roo.Element
52234 getHeaderPanel : function(doShow){
52236 this.headerPanel.show();
52238 return this.headerPanel;
52242 * Gets a panel in the footer of the grid that can be used for toolbars etc.
52243 * After modifying the contents of this panel a call to grid.autoSize() may be
52244 * required to register any changes in size.
52245 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
52246 * @return Roo.Element
52248 getFooterPanel : function(doShow){
52250 this.footerPanel.show();
52252 return this.footerPanel;
52255 initElements : function(){
52256 var E = Roo.Element;
52257 var el = this.grid.getGridEl().dom.firstChild;
52258 var cs = el.childNodes;
52260 this.el = new E(el);
52262 this.focusEl = new E(el.firstChild);
52263 this.focusEl.swallowEvent("click", true);
52265 this.headerPanel = new E(cs[1]);
52266 this.headerPanel.enableDisplayMode("block");
52268 this.scroller = new E(cs[2]);
52269 this.scrollSizer = new E(this.scroller.dom.firstChild);
52271 this.lockedWrap = new E(cs[3]);
52272 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
52273 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
52275 this.mainWrap = new E(cs[4]);
52276 this.mainHd = new E(this.mainWrap.dom.firstChild);
52277 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
52279 this.footerPanel = new E(cs[5]);
52280 this.footerPanel.enableDisplayMode("block");
52282 this.resizeProxy = new E(cs[6]);
52284 this.headerSelector = String.format(
52285 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
52286 this.lockedHd.id, this.mainHd.id
52289 this.splitterSelector = String.format(
52290 '#{0} div.x-grid-split, #{1} div.x-grid-split',
52291 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
52294 idToCssName : function(s)
52296 return s.replace(/[^a-z0-9]+/ig, '-');
52299 getHeaderCell : function(index){
52300 return Roo.DomQuery.select(this.headerSelector)[index];
52303 getHeaderCellMeasure : function(index){
52304 return this.getHeaderCell(index).firstChild;
52307 getHeaderCellText : function(index){
52308 return this.getHeaderCell(index).firstChild.firstChild;
52311 getLockedTable : function(){
52312 return this.lockedBody.dom.firstChild;
52315 getBodyTable : function(){
52316 return this.mainBody.dom.firstChild;
52319 getLockedRow : function(index){
52320 return this.getLockedTable().rows[index];
52323 getRow : function(index){
52324 return this.getBodyTable().rows[index];
52327 getRowComposite : function(index){
52329 this.rowEl = new Roo.CompositeElementLite();
52331 var els = [], lrow, mrow;
52332 if(lrow = this.getLockedRow(index)){
52335 if(mrow = this.getRow(index)){
52338 this.rowEl.elements = els;
52342 * Gets the 'td' of the cell
52344 * @param {Integer} rowIndex row to select
52345 * @param {Integer} colIndex column to select
52349 getCell : function(rowIndex, colIndex){
52350 var locked = this.cm.getLockedCount();
52352 if(colIndex < locked){
52353 source = this.lockedBody.dom.firstChild;
52355 source = this.mainBody.dom.firstChild;
52356 colIndex -= locked;
52358 return source.rows[rowIndex].childNodes[colIndex];
52361 getCellText : function(rowIndex, colIndex){
52362 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
52365 getCellBox : function(cell){
52366 var b = this.fly(cell).getBox();
52367 if(Roo.isOpera){ // opera fails to report the Y
52368 b.y = cell.offsetTop + this.mainBody.getY();
52373 getCellIndex : function(cell){
52374 var id = String(cell.className).match(this.cellRE);
52376 return parseInt(id[1], 10);
52381 findHeaderIndex : function(n){
52382 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52383 return r ? this.getCellIndex(r) : false;
52386 findHeaderCell : function(n){
52387 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52388 return r ? r : false;
52391 findRowIndex : function(n){
52395 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
52396 return r ? r.rowIndex : false;
52399 findCellIndex : function(node){
52400 var stop = this.el.dom;
52401 while(node && node != stop){
52402 if(this.findRE.test(node.className)){
52403 return this.getCellIndex(node);
52405 node = node.parentNode;
52410 getColumnId : function(index){
52411 return this.cm.getColumnId(index);
52414 getSplitters : function()
52416 if(this.splitterSelector){
52417 return Roo.DomQuery.select(this.splitterSelector);
52423 getSplitter : function(index){
52424 return this.getSplitters()[index];
52427 onRowOver : function(e, t){
52429 if((row = this.findRowIndex(t)) !== false){
52430 this.getRowComposite(row).addClass("x-grid-row-over");
52434 onRowOut : function(e, t){
52436 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
52437 this.getRowComposite(row).removeClass("x-grid-row-over");
52441 renderHeaders : function(){
52443 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
52444 var cb = [], lb = [], sb = [], lsb = [], p = {};
52445 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52446 p.cellId = "x-grid-hd-0-" + i;
52447 p.splitId = "x-grid-csplit-0-" + i;
52448 p.id = cm.getColumnId(i);
52449 p.title = cm.getColumnTooltip(i) || "";
52450 p.value = cm.getColumnHeader(i) || "";
52451 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
52452 if(!cm.isLocked(i)){
52453 cb[cb.length] = ct.apply(p);
52454 sb[sb.length] = st.apply(p);
52456 lb[lb.length] = ct.apply(p);
52457 lsb[lsb.length] = st.apply(p);
52460 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
52461 ht.apply({cells: cb.join(""), splits:sb.join("")})];
52464 updateHeaders : function(){
52465 var html = this.renderHeaders();
52466 this.lockedHd.update(html[0]);
52467 this.mainHd.update(html[1]);
52471 * Focuses the specified row.
52472 * @param {Number} row The row index
52474 focusRow : function(row)
52476 //Roo.log('GridView.focusRow');
52477 var x = this.scroller.dom.scrollLeft;
52478 this.focusCell(row, 0, false);
52479 this.scroller.dom.scrollLeft = x;
52483 * Focuses the specified cell.
52484 * @param {Number} row The row index
52485 * @param {Number} col The column index
52486 * @param {Boolean} hscroll false to disable horizontal scrolling
52488 focusCell : function(row, col, hscroll)
52490 //Roo.log('GridView.focusCell');
52491 var el = this.ensureVisible(row, col, hscroll);
52492 this.focusEl.alignTo(el, "tl-tl");
52494 this.focusEl.focus();
52496 this.focusEl.focus.defer(1, this.focusEl);
52501 * Scrolls the specified cell into view
52502 * @param {Number} row The row index
52503 * @param {Number} col The column index
52504 * @param {Boolean} hscroll false to disable horizontal scrolling
52506 ensureVisible : function(row, col, hscroll)
52508 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
52509 //return null; //disable for testing.
52510 if(typeof row != "number"){
52511 row = row.rowIndex;
52513 if(row < 0 && row >= this.ds.getCount()){
52516 col = (col !== undefined ? col : 0);
52517 var cm = this.grid.colModel;
52518 while(cm.isHidden(col)){
52522 var el = this.getCell(row, col);
52526 var c = this.scroller.dom;
52528 var ctop = parseInt(el.offsetTop, 10);
52529 var cleft = parseInt(el.offsetLeft, 10);
52530 var cbot = ctop + el.offsetHeight;
52531 var cright = cleft + el.offsetWidth;
52533 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
52534 var stop = parseInt(c.scrollTop, 10);
52535 var sleft = parseInt(c.scrollLeft, 10);
52536 var sbot = stop + ch;
52537 var sright = sleft + c.clientWidth;
52539 Roo.log('GridView.ensureVisible:' +
52541 ' c.clientHeight:' + c.clientHeight +
52542 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
52550 c.scrollTop = ctop;
52551 //Roo.log("set scrolltop to ctop DISABLE?");
52552 }else if(cbot > sbot){
52553 //Roo.log("set scrolltop to cbot-ch");
52554 c.scrollTop = cbot-ch;
52557 if(hscroll !== false){
52559 c.scrollLeft = cleft;
52560 }else if(cright > sright){
52561 c.scrollLeft = cright-c.clientWidth;
52568 updateColumns : function(){
52569 this.grid.stopEditing();
52570 var cm = this.grid.colModel, colIds = this.getColumnIds();
52571 //var totalWidth = cm.getTotalWidth();
52573 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52574 //if(cm.isHidden(i)) continue;
52575 var w = cm.getColumnWidth(i);
52576 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52577 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52579 this.updateSplitters();
52582 generateRules : function(cm){
52583 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
52584 Roo.util.CSS.removeStyleSheet(rulesId);
52585 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52586 var cid = cm.getColumnId(i);
52588 if(cm.config[i].align){
52589 align = 'text-align:'+cm.config[i].align+';';
52592 if(cm.isHidden(i)){
52593 hidden = 'display:none;';
52595 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
52597 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
52598 this.hdSelector, cid, " {\n", align, width, "}\n",
52599 this.tdSelector, cid, " {\n",hidden,"\n}\n",
52600 this.splitSelector, cid, " {\n", hidden , "\n}\n");
52602 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52605 updateSplitters : function(){
52606 var cm = this.cm, s = this.getSplitters();
52607 if(s){ // splitters not created yet
52608 var pos = 0, locked = true;
52609 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52610 if(cm.isHidden(i)) continue;
52611 var w = cm.getColumnWidth(i); // make sure it's a number
52612 if(!cm.isLocked(i) && locked){
52617 s[i].style.left = (pos-this.splitOffset) + "px";
52622 handleHiddenChange : function(colModel, colIndex, hidden){
52624 this.hideColumn(colIndex);
52626 this.unhideColumn(colIndex);
52630 hideColumn : function(colIndex){
52631 var cid = this.getColumnId(colIndex);
52632 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
52633 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
52635 this.updateHeaders();
52637 this.updateSplitters();
52641 unhideColumn : function(colIndex){
52642 var cid = this.getColumnId(colIndex);
52643 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
52644 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
52647 this.updateHeaders();
52649 this.updateSplitters();
52653 insertRows : function(dm, firstRow, lastRow, isUpdate){
52654 if(firstRow == 0 && lastRow == dm.getCount()-1){
52658 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
52660 var s = this.getScrollState();
52661 var markup = this.renderRows(firstRow, lastRow);
52662 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
52663 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
52664 this.restoreScroll(s);
52666 this.fireEvent("rowsinserted", this, firstRow, lastRow);
52667 this.syncRowHeights(firstRow, lastRow);
52668 this.stripeRows(firstRow);
52674 bufferRows : function(markup, target, index){
52675 var before = null, trows = target.rows, tbody = target.tBodies[0];
52676 if(index < trows.length){
52677 before = trows[index];
52679 var b = document.createElement("div");
52680 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
52681 var rows = b.firstChild.rows;
52682 for(var i = 0, len = rows.length; i < len; i++){
52684 tbody.insertBefore(rows[0], before);
52686 tbody.appendChild(rows[0]);
52693 deleteRows : function(dm, firstRow, lastRow){
52694 if(dm.getRowCount()<1){
52695 this.fireEvent("beforerefresh", this);
52696 this.mainBody.update("");
52697 this.lockedBody.update("");
52698 this.fireEvent("refresh", this);
52700 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
52701 var bt = this.getBodyTable();
52702 var tbody = bt.firstChild;
52703 var rows = bt.rows;
52704 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
52705 tbody.removeChild(rows[firstRow]);
52707 this.stripeRows(firstRow);
52708 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
52712 updateRows : function(dataSource, firstRow, lastRow){
52713 var s = this.getScrollState();
52715 this.restoreScroll(s);
52718 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
52722 this.updateHeaderSortState();
52725 getScrollState : function(){
52727 var sb = this.scroller.dom;
52728 return {left: sb.scrollLeft, top: sb.scrollTop};
52731 stripeRows : function(startRow){
52732 if(!this.grid.stripeRows || this.ds.getCount() < 1){
52735 startRow = startRow || 0;
52736 var rows = this.getBodyTable().rows;
52737 var lrows = this.getLockedTable().rows;
52738 var cls = ' x-grid-row-alt ';
52739 for(var i = startRow, len = rows.length; i < len; i++){
52740 var row = rows[i], lrow = lrows[i];
52741 var isAlt = ((i+1) % 2 == 0);
52742 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
52743 if(isAlt == hasAlt){
52747 row.className += " x-grid-row-alt";
52749 row.className = row.className.replace("x-grid-row-alt", "");
52752 lrow.className = row.className;
52757 restoreScroll : function(state){
52758 //Roo.log('GridView.restoreScroll');
52759 var sb = this.scroller.dom;
52760 sb.scrollLeft = state.left;
52761 sb.scrollTop = state.top;
52765 syncScroll : function(){
52766 //Roo.log('GridView.syncScroll');
52767 var sb = this.scroller.dom;
52768 var sh = this.mainHd.dom;
52769 var bs = this.mainBody.dom;
52770 var lv = this.lockedBody.dom;
52771 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
52772 lv.scrollTop = bs.scrollTop = sb.scrollTop;
52775 handleScroll : function(e){
52777 var sb = this.scroller.dom;
52778 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
52782 handleWheel : function(e){
52783 var d = e.getWheelDelta();
52784 this.scroller.dom.scrollTop -= d*22;
52785 // set this here to prevent jumpy scrolling on large tables
52786 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
52790 renderRows : function(startRow, endRow){
52791 // pull in all the crap needed to render rows
52792 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
52793 var colCount = cm.getColumnCount();
52795 if(ds.getCount() < 1){
52799 // build a map for all the columns
52801 for(var i = 0; i < colCount; i++){
52802 var name = cm.getDataIndex(i);
52804 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
52805 renderer : cm.getRenderer(i),
52806 id : cm.getColumnId(i),
52807 locked : cm.isLocked(i)
52811 startRow = startRow || 0;
52812 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
52814 // records to render
52815 var rs = ds.getRange(startRow, endRow);
52817 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
52820 // As much as I hate to duplicate code, this was branched because FireFox really hates
52821 // [].join("") on strings. The performance difference was substantial enough to
52822 // branch this function
52823 doRender : Roo.isGecko ?
52824 function(cs, rs, ds, startRow, colCount, stripe){
52825 var ts = this.templates, ct = ts.cell, rt = ts.row;
52827 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52829 var hasListener = this.grid.hasListener('rowclass');
52831 for(var j = 0, len = rs.length; j < len; j++){
52832 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
52833 for(var i = 0; i < colCount; i++){
52835 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52837 p.css = p.attr = "";
52838 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52839 if(p.value == undefined || p.value === "") p.value = " ";
52840 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52841 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52843 var markup = ct.apply(p);
52851 if(stripe && ((rowIndex+1) % 2 == 0)){
52852 alt.push("x-grid-row-alt")
52855 alt.push( " x-grid-dirty-row");
52858 if(this.getRowClass){
52859 alt.push(this.getRowClass(r, rowIndex));
52865 rowIndex : rowIndex,
52868 this.grid.fireEvent('rowclass', this, rowcfg);
52869 alt.push(rowcfg.rowClass);
52871 rp.alt = alt.join(" ");
52872 lbuf+= rt.apply(rp);
52874 buf+= rt.apply(rp);
52876 return [lbuf, buf];
52878 function(cs, rs, ds, startRow, colCount, stripe){
52879 var ts = this.templates, ct = ts.cell, rt = ts.row;
52881 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52882 var hasListener = this.grid.hasListener('rowclass');
52885 for(var j = 0, len = rs.length; j < len; j++){
52886 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
52887 for(var i = 0; i < colCount; i++){
52889 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52891 p.css = p.attr = "";
52892 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52893 if(p.value == undefined || p.value === "") p.value = " ";
52894 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52895 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52898 var markup = ct.apply(p);
52900 cb[cb.length] = markup;
52902 lcb[lcb.length] = markup;
52906 if(stripe && ((rowIndex+1) % 2 == 0)){
52907 alt.push( "x-grid-row-alt");
52910 alt.push(" x-grid-dirty-row");
52913 if(this.getRowClass){
52914 alt.push( this.getRowClass(r, rowIndex));
52920 rowIndex : rowIndex,
52923 this.grid.fireEvent('rowclass', this, rowcfg);
52924 alt.push(rowcfg.rowClass);
52926 rp.alt = alt.join(" ");
52927 rp.cells = lcb.join("");
52928 lbuf[lbuf.length] = rt.apply(rp);
52929 rp.cells = cb.join("");
52930 buf[buf.length] = rt.apply(rp);
52932 return [lbuf.join(""), buf.join("")];
52935 renderBody : function(){
52936 var markup = this.renderRows();
52937 var bt = this.templates.body;
52938 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
52942 * Refreshes the grid
52943 * @param {Boolean} headersToo
52945 refresh : function(headersToo){
52946 this.fireEvent("beforerefresh", this);
52947 this.grid.stopEditing();
52948 var result = this.renderBody();
52949 this.lockedBody.update(result[0]);
52950 this.mainBody.update(result[1]);
52951 if(headersToo === true){
52952 this.updateHeaders();
52953 this.updateColumns();
52954 this.updateSplitters();
52955 this.updateHeaderSortState();
52957 this.syncRowHeights();
52959 this.fireEvent("refresh", this);
52962 handleColumnMove : function(cm, oldIndex, newIndex){
52963 this.indexMap = null;
52964 var s = this.getScrollState();
52965 this.refresh(true);
52966 this.restoreScroll(s);
52967 this.afterMove(newIndex);
52970 afterMove : function(colIndex){
52971 if(this.enableMoveAnim && Roo.enableFx){
52972 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
52974 // if multisort - fix sortOrder, and reload..
52975 if (this.grid.dataSource.multiSort) {
52976 // the we can call sort again..
52977 var dm = this.grid.dataSource;
52978 var cm = this.grid.colModel;
52980 for(var i = 0; i < cm.config.length; i++ ) {
52982 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
52983 continue; // dont' bother, it's not in sort list or being set.
52986 so.push(cm.config[i].dataIndex);
52989 dm.load(dm.lastOptions);
52996 updateCell : function(dm, rowIndex, dataIndex){
52997 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
52998 if(typeof colIndex == "undefined"){ // not present in grid
53001 var cm = this.grid.colModel;
53002 var cell = this.getCell(rowIndex, colIndex);
53003 var cellText = this.getCellText(rowIndex, colIndex);
53006 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53007 id : cm.getColumnId(colIndex),
53008 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53010 var renderer = cm.getRenderer(colIndex);
53011 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53012 if(typeof val == "undefined" || val === "") val = " ";
53013 cellText.innerHTML = val;
53014 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53015 this.syncRowHeights(rowIndex, rowIndex);
53018 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53020 if(this.grid.autoSizeHeaders){
53021 var h = this.getHeaderCellMeasure(colIndex);
53022 maxWidth = Math.max(maxWidth, h.scrollWidth);
53025 if(this.cm.isLocked(colIndex)){
53026 tb = this.getLockedTable();
53029 tb = this.getBodyTable();
53030 index = colIndex - this.cm.getLockedCount();
53033 var rows = tb.rows;
53034 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53035 for(var i = 0; i < stopIndex; i++){
53036 var cell = rows[i].childNodes[index].firstChild;
53037 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53040 return maxWidth + /*margin for error in IE*/ 5;
53043 * Autofit a column to its content.
53044 * @param {Number} colIndex
53045 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53047 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53048 if(this.cm.isHidden(colIndex)){
53049 return; // can't calc a hidden column
53052 var cid = this.cm.getColumnId(colIndex);
53053 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53054 if(this.grid.autoSizeHeaders){
53055 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53058 var newWidth = this.calcColumnWidth(colIndex);
53059 this.cm.setColumnWidth(colIndex,
53060 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53061 if(!suppressEvent){
53062 this.grid.fireEvent("columnresize", colIndex, newWidth);
53067 * Autofits all columns to their content and then expands to fit any extra space in the grid
53069 autoSizeColumns : function(){
53070 var cm = this.grid.colModel;
53071 var colCount = cm.getColumnCount();
53072 for(var i = 0; i < colCount; i++){
53073 this.autoSizeColumn(i, true, true);
53075 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53078 this.updateColumns();
53084 * Autofits all columns to the grid's width proportionate with their current size
53085 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53087 fitColumns : function(reserveScrollSpace){
53088 var cm = this.grid.colModel;
53089 var colCount = cm.getColumnCount();
53093 for (i = 0; i < colCount; i++){
53094 if(!cm.isHidden(i) && !cm.isFixed(i)){
53095 w = cm.getColumnWidth(i);
53101 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53102 if(reserveScrollSpace){
53105 var frac = (avail - cm.getTotalWidth())/width;
53106 while (cols.length){
53109 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53111 this.updateColumns();
53115 onRowSelect : function(rowIndex){
53116 var row = this.getRowComposite(rowIndex);
53117 row.addClass("x-grid-row-selected");
53120 onRowDeselect : function(rowIndex){
53121 var row = this.getRowComposite(rowIndex);
53122 row.removeClass("x-grid-row-selected");
53125 onCellSelect : function(row, col){
53126 var cell = this.getCell(row, col);
53128 Roo.fly(cell).addClass("x-grid-cell-selected");
53132 onCellDeselect : function(row, col){
53133 var cell = this.getCell(row, col);
53135 Roo.fly(cell).removeClass("x-grid-cell-selected");
53139 updateHeaderSortState : function(){
53141 // sort state can be single { field: xxx, direction : yyy}
53142 // or { xxx=>ASC , yyy : DESC ..... }
53145 if (!this.ds.multiSort) {
53146 var state = this.ds.getSortState();
53150 mstate[state.field] = state.direction;
53151 // FIXME... - this is not used here.. but might be elsewhere..
53152 this.sortState = state;
53155 mstate = this.ds.sortToggle;
53157 //remove existing sort classes..
53159 var sc = this.sortClasses;
53160 var hds = this.el.select(this.headerSelector).removeClass(sc);
53162 for(var f in mstate) {
53164 var sortColumn = this.cm.findColumnIndex(f);
53166 if(sortColumn != -1){
53167 var sortDir = mstate[f];
53168 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53177 handleHeaderClick : function(g, index){
53178 if(this.headersDisabled){
53181 var dm = g.dataSource, cm = g.colModel;
53182 if(!cm.isSortable(index)){
53187 if (dm.multiSort) {
53188 // update the sortOrder
53190 for(var i = 0; i < cm.config.length; i++ ) {
53192 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53193 continue; // dont' bother, it's not in sort list or being set.
53196 so.push(cm.config[i].dataIndex);
53202 dm.sort(cm.getDataIndex(index));
53206 destroy : function(){
53208 this.colMenu.removeAll();
53209 Roo.menu.MenuMgr.unregister(this.colMenu);
53210 this.colMenu.getEl().remove();
53211 delete this.colMenu;
53214 this.hmenu.removeAll();
53215 Roo.menu.MenuMgr.unregister(this.hmenu);
53216 this.hmenu.getEl().remove();
53219 if(this.grid.enableColumnMove){
53220 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53222 for(var dd in dds){
53223 if(!dds[dd].config.isTarget && dds[dd].dragElId){
53224 var elid = dds[dd].dragElId;
53226 Roo.get(elid).remove();
53227 } else if(dds[dd].config.isTarget){
53228 dds[dd].proxyTop.remove();
53229 dds[dd].proxyBottom.remove();
53232 if(Roo.dd.DDM.locationCache[dd]){
53233 delete Roo.dd.DDM.locationCache[dd];
53236 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53239 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
53240 this.bind(null, null);
53241 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
53244 handleLockChange : function(){
53245 this.refresh(true);
53248 onDenyColumnLock : function(){
53252 onDenyColumnHide : function(){
53256 handleHdMenuClick : function(item){
53257 var index = this.hdCtxIndex;
53258 var cm = this.cm, ds = this.ds;
53261 ds.sort(cm.getDataIndex(index), "ASC");
53264 ds.sort(cm.getDataIndex(index), "DESC");
53267 var lc = cm.getLockedCount();
53268 if(cm.getColumnCount(true) <= lc+1){
53269 this.onDenyColumnLock();
53273 cm.setLocked(index, true, true);
53274 cm.moveColumn(index, lc);
53275 this.grid.fireEvent("columnmove", index, lc);
53277 cm.setLocked(index, true);
53281 var lc = cm.getLockedCount();
53282 if((lc-1) != index){
53283 cm.setLocked(index, false, true);
53284 cm.moveColumn(index, lc-1);
53285 this.grid.fireEvent("columnmove", index, lc-1);
53287 cm.setLocked(index, false);
53291 index = cm.getIndexById(item.id.substr(4));
53293 if(item.checked && cm.getColumnCount(true) <= 1){
53294 this.onDenyColumnHide();
53297 cm.setHidden(index, item.checked);
53303 beforeColMenuShow : function(){
53304 var cm = this.cm, colCount = cm.getColumnCount();
53305 this.colMenu.removeAll();
53306 for(var i = 0; i < colCount; i++){
53307 this.colMenu.add(new Roo.menu.CheckItem({
53308 id: "col-"+cm.getColumnId(i),
53309 text: cm.getColumnHeader(i),
53310 checked: !cm.isHidden(i),
53316 handleHdCtx : function(g, index, e){
53318 var hd = this.getHeaderCell(index);
53319 this.hdCtxIndex = index;
53320 var ms = this.hmenu.items, cm = this.cm;
53321 ms.get("asc").setDisabled(!cm.isSortable(index));
53322 ms.get("desc").setDisabled(!cm.isSortable(index));
53323 if(this.grid.enableColLock !== false){
53324 ms.get("lock").setDisabled(cm.isLocked(index));
53325 ms.get("unlock").setDisabled(!cm.isLocked(index));
53327 this.hmenu.show(hd, "tl-bl");
53330 handleHdOver : function(e){
53331 var hd = this.findHeaderCell(e.getTarget());
53332 if(hd && !this.headersDisabled){
53333 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
53334 this.fly(hd).addClass("x-grid-hd-over");
53339 handleHdOut : function(e){
53340 var hd = this.findHeaderCell(e.getTarget());
53342 this.fly(hd).removeClass("x-grid-hd-over");
53346 handleSplitDblClick : function(e, t){
53347 var i = this.getCellIndex(t);
53348 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
53349 this.autoSizeColumn(i, true);
53354 render : function(){
53357 var colCount = cm.getColumnCount();
53359 if(this.grid.monitorWindowResize === true){
53360 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
53362 var header = this.renderHeaders();
53363 var body = this.templates.body.apply({rows:""});
53364 var html = this.templates.master.apply({
53367 lockedHeader: header[0],
53371 //this.updateColumns();
53373 this.grid.getGridEl().dom.innerHTML = html;
53375 this.initElements();
53377 // a kludge to fix the random scolling effect in webkit
53378 this.el.on("scroll", function() {
53379 this.el.dom.scrollTop=0; // hopefully not recursive..
53382 this.scroller.on("scroll", this.handleScroll, this);
53383 this.lockedBody.on("mousewheel", this.handleWheel, this);
53384 this.mainBody.on("mousewheel", this.handleWheel, this);
53386 this.mainHd.on("mouseover", this.handleHdOver, this);
53387 this.mainHd.on("mouseout", this.handleHdOut, this);
53388 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
53389 {delegate: "."+this.splitClass});
53391 this.lockedHd.on("mouseover", this.handleHdOver, this);
53392 this.lockedHd.on("mouseout", this.handleHdOut, this);
53393 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
53394 {delegate: "."+this.splitClass});
53396 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
53397 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53400 this.updateSplitters();
53402 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
53403 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53404 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53407 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
53408 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
53410 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
53411 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
53413 if(this.grid.enableColLock !== false){
53414 this.hmenu.add('-',
53415 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
53416 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
53419 if(this.grid.enableColumnHide !== false){
53421 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
53422 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
53423 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
53425 this.hmenu.add('-',
53426 {id:"columns", text: this.columnsText, menu: this.colMenu}
53429 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
53431 this.grid.on("headercontextmenu", this.handleHdCtx, this);
53434 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
53435 this.dd = new Roo.grid.GridDragZone(this.grid, {
53436 ddGroup : this.grid.ddGroup || 'GridDD'
53442 for(var i = 0; i < colCount; i++){
53443 if(cm.isHidden(i)){
53444 this.hideColumn(i);
53446 if(cm.config[i].align){
53447 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
53448 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
53452 this.updateHeaderSortState();
53454 this.beforeInitialResize();
53457 // two part rendering gives faster view to the user
53458 this.renderPhase2.defer(1, this);
53461 renderPhase2 : function(){
53462 // render the rows now
53464 if(this.grid.autoSizeColumns){
53465 this.autoSizeColumns();
53469 beforeInitialResize : function(){
53473 onColumnSplitterMoved : function(i, w){
53474 this.userResized = true;
53475 var cm = this.grid.colModel;
53476 cm.setColumnWidth(i, w, true);
53477 var cid = cm.getColumnId(i);
53478 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53479 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53480 this.updateSplitters();
53482 this.grid.fireEvent("columnresize", i, w);
53485 syncRowHeights : function(startIndex, endIndex){
53486 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
53487 startIndex = startIndex || 0;
53488 var mrows = this.getBodyTable().rows;
53489 var lrows = this.getLockedTable().rows;
53490 var len = mrows.length-1;
53491 endIndex = Math.min(endIndex || len, len);
53492 for(var i = startIndex; i <= endIndex; i++){
53493 var m = mrows[i], l = lrows[i];
53494 var h = Math.max(m.offsetHeight, l.offsetHeight);
53495 m.style.height = l.style.height = h + "px";
53500 layout : function(initialRender, is2ndPass){
53502 var auto = g.autoHeight;
53503 var scrollOffset = 16;
53504 var c = g.getGridEl(), cm = this.cm,
53505 expandCol = g.autoExpandColumn,
53507 //c.beginMeasure();
53509 if(!c.dom.offsetWidth){ // display:none?
53511 this.lockedWrap.show();
53512 this.mainWrap.show();
53517 var hasLock = this.cm.isLocked(0);
53519 var tbh = this.headerPanel.getHeight();
53520 var bbh = this.footerPanel.getHeight();
53523 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
53524 var newHeight = ch + c.getBorderWidth("tb");
53526 newHeight = Math.min(g.maxHeight, newHeight);
53528 c.setHeight(newHeight);
53532 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
53535 var s = this.scroller;
53537 var csize = c.getSize(true);
53539 this.el.setSize(csize.width, csize.height);
53541 this.headerPanel.setWidth(csize.width);
53542 this.footerPanel.setWidth(csize.width);
53544 var hdHeight = this.mainHd.getHeight();
53545 var vw = csize.width;
53546 var vh = csize.height - (tbh + bbh);
53550 var bt = this.getBodyTable();
53551 var ltWidth = hasLock ?
53552 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
53554 var scrollHeight = bt.offsetHeight;
53555 var scrollWidth = ltWidth + bt.offsetWidth;
53556 var vscroll = false, hscroll = false;
53558 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
53560 var lw = this.lockedWrap, mw = this.mainWrap;
53561 var lb = this.lockedBody, mb = this.mainBody;
53563 setTimeout(function(){
53564 var t = s.dom.offsetTop;
53565 var w = s.dom.clientWidth,
53566 h = s.dom.clientHeight;
53569 lw.setSize(ltWidth, h);
53571 mw.setLeftTop(ltWidth, t);
53572 mw.setSize(w-ltWidth, h);
53574 lb.setHeight(h-hdHeight);
53575 mb.setHeight(h-hdHeight);
53577 if(is2ndPass !== true && !gv.userResized && expandCol){
53578 // high speed resize without full column calculation
53580 var ci = cm.getIndexById(expandCol);
53582 ci = cm.findColumnIndex(expandCol);
53584 ci = Math.max(0, ci); // make sure it's got at least the first col.
53585 var expandId = cm.getColumnId(ci);
53586 var tw = cm.getTotalWidth(false);
53587 var currentWidth = cm.getColumnWidth(ci);
53588 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
53589 if(currentWidth != cw){
53590 cm.setColumnWidth(ci, cw, true);
53591 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53592 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53593 gv.updateSplitters();
53594 gv.layout(false, true);
53606 onWindowResize : function(){
53607 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
53613 appendFooter : function(parentEl){
53617 sortAscText : "Sort Ascending",
53618 sortDescText : "Sort Descending",
53619 lockText : "Lock Column",
53620 unlockText : "Unlock Column",
53621 columnsText : "Columns"
53625 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
53626 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
53627 this.proxy.el.addClass('x-grid3-col-dd');
53630 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
53631 handleMouseDown : function(e){
53635 callHandleMouseDown : function(e){
53636 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
53641 * Ext JS Library 1.1.1
53642 * Copyright(c) 2006-2007, Ext JS, LLC.
53644 * Originally Released Under LGPL - original licence link has changed is not relivant.
53647 * <script type="text/javascript">
53651 // This is a support class used internally by the Grid components
53652 Roo.grid.SplitDragZone = function(grid, hd, hd2){
53654 this.view = grid.getView();
53655 this.proxy = this.view.resizeProxy;
53656 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
53657 "gridSplitters" + this.grid.getGridEl().id, {
53658 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
53660 this.setHandleElId(Roo.id(hd));
53661 this.setOuterHandleElId(Roo.id(hd2));
53662 this.scroll = false;
53664 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
53665 fly: Roo.Element.fly,
53667 b4StartDrag : function(x, y){
53668 this.view.headersDisabled = true;
53669 this.proxy.setHeight(this.view.mainWrap.getHeight());
53670 var w = this.cm.getColumnWidth(this.cellIndex);
53671 var minw = Math.max(w-this.grid.minColumnWidth, 0);
53672 this.resetConstraints();
53673 this.setXConstraint(minw, 1000);
53674 this.setYConstraint(0, 0);
53675 this.minX = x - minw;
53676 this.maxX = x + 1000;
53678 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
53682 handleMouseDown : function(e){
53683 ev = Roo.EventObject.setEvent(e);
53684 var t = this.fly(ev.getTarget());
53685 if(t.hasClass("x-grid-split")){
53686 this.cellIndex = this.view.getCellIndex(t.dom);
53687 this.split = t.dom;
53688 this.cm = this.grid.colModel;
53689 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
53690 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
53695 endDrag : function(e){
53696 this.view.headersDisabled = false;
53697 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
53698 var diff = endX - this.startPos;
53699 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
53702 autoOffset : function(){
53703 this.setDelta(0,0);
53707 * Ext JS Library 1.1.1
53708 * Copyright(c) 2006-2007, Ext JS, LLC.
53710 * Originally Released Under LGPL - original licence link has changed is not relivant.
53713 * <script type="text/javascript">
53717 // This is a support class used internally by the Grid components
53718 Roo.grid.GridDragZone = function(grid, config){
53719 this.view = grid.getView();
53720 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
53721 if(this.view.lockedBody){
53722 this.setHandleElId(Roo.id(this.view.mainBody.dom));
53723 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
53725 this.scroll = false;
53727 this.ddel = document.createElement('div');
53728 this.ddel.className = 'x-grid-dd-wrap';
53731 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
53732 ddGroup : "GridDD",
53734 getDragData : function(e){
53735 var t = Roo.lib.Event.getTarget(e);
53736 var rowIndex = this.view.findRowIndex(t);
53737 var sm = this.grid.selModel;
53739 //Roo.log(rowIndex);
53741 if (sm.getSelectedCell) {
53742 // cell selection..
53743 if (!sm.getSelectedCell()) {
53746 if (rowIndex != sm.getSelectedCell()[0]) {
53752 if(rowIndex !== false){
53757 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
53759 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
53762 if (e.hasModifier()){
53763 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
53766 Roo.log("getDragData");
53771 rowIndex: rowIndex,
53772 selections:sm.getSelections ? sm.getSelections() : (
53773 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
53780 onInitDrag : function(e){
53781 var data = this.dragData;
53782 this.ddel.innerHTML = this.grid.getDragDropText();
53783 this.proxy.update(this.ddel);
53784 // fire start drag?
53787 afterRepair : function(){
53788 this.dragging = false;
53791 getRepairXY : function(e, data){
53795 onEndDrag : function(data, e){
53799 onValidDrop : function(dd, e, id){
53804 beforeInvalidDrop : function(e, id){
53809 * Ext JS Library 1.1.1
53810 * Copyright(c) 2006-2007, Ext JS, LLC.
53812 * Originally Released Under LGPL - original licence link has changed is not relivant.
53815 * <script type="text/javascript">
53820 * @class Roo.grid.ColumnModel
53821 * @extends Roo.util.Observable
53822 * This is the default implementation of a ColumnModel used by the Grid. It defines
53823 * the columns in the grid.
53826 var colModel = new Roo.grid.ColumnModel([
53827 {header: "Ticker", width: 60, sortable: true, locked: true},
53828 {header: "Company Name", width: 150, sortable: true},
53829 {header: "Market Cap.", width: 100, sortable: true},
53830 {header: "$ Sales", width: 100, sortable: true, renderer: money},
53831 {header: "Employees", width: 100, sortable: true, resizable: false}
53836 * The config options listed for this class are options which may appear in each
53837 * individual column definition.
53838 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
53840 * @param {Object} config An Array of column config objects. See this class's
53841 * config objects for details.
53843 Roo.grid.ColumnModel = function(config){
53845 * The config passed into the constructor
53847 this.config = config;
53850 // if no id, create one
53851 // if the column does not have a dataIndex mapping,
53852 // map it to the order it is in the config
53853 for(var i = 0, len = config.length; i < len; i++){
53855 if(typeof c.dataIndex == "undefined"){
53858 if(typeof c.renderer == "string"){
53859 c.renderer = Roo.util.Format[c.renderer];
53861 if(typeof c.id == "undefined"){
53864 if(c.editor && c.editor.xtype){
53865 c.editor = Roo.factory(c.editor, Roo.grid);
53867 if(c.editor && c.editor.isFormField){
53868 c.editor = new Roo.grid.GridEditor(c.editor);
53870 this.lookup[c.id] = c;
53874 * The width of columns which have no width specified (defaults to 100)
53877 this.defaultWidth = 100;
53880 * Default sortable of columns which have no sortable specified (defaults to false)
53883 this.defaultSortable = false;
53887 * @event widthchange
53888 * Fires when the width of a column changes.
53889 * @param {ColumnModel} this
53890 * @param {Number} columnIndex The column index
53891 * @param {Number} newWidth The new width
53893 "widthchange": true,
53895 * @event headerchange
53896 * Fires when the text of a header changes.
53897 * @param {ColumnModel} this
53898 * @param {Number} columnIndex The column index
53899 * @param {Number} newText The new header text
53901 "headerchange": true,
53903 * @event hiddenchange
53904 * Fires when a column is hidden or "unhidden".
53905 * @param {ColumnModel} this
53906 * @param {Number} columnIndex The column index
53907 * @param {Boolean} hidden true if hidden, false otherwise
53909 "hiddenchange": true,
53911 * @event columnmoved
53912 * Fires when a column is moved.
53913 * @param {ColumnModel} this
53914 * @param {Number} oldIndex
53915 * @param {Number} newIndex
53917 "columnmoved" : true,
53919 * @event columlockchange
53920 * Fires when a column's locked state is changed
53921 * @param {ColumnModel} this
53922 * @param {Number} colIndex
53923 * @param {Boolean} locked true if locked
53925 "columnlockchange" : true
53927 Roo.grid.ColumnModel.superclass.constructor.call(this);
53929 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
53931 * @cfg {String} header The header text to display in the Grid view.
53934 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
53935 * {@link Roo.data.Record} definition from which to draw the column's value. If not
53936 * specified, the column's index is used as an index into the Record's data Array.
53939 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
53940 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
53943 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
53944 * Defaults to the value of the {@link #defaultSortable} property.
53945 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
53948 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
53951 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
53954 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
53957 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
53960 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
53961 * given the cell's data value. See {@link #setRenderer}. If not specified, the
53962 * default renderer uses the raw data value.
53965 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
53968 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
53972 * Returns the id of the column at the specified index.
53973 * @param {Number} index The column index
53974 * @return {String} the id
53976 getColumnId : function(index){
53977 return this.config[index].id;
53981 * Returns the column for a specified id.
53982 * @param {String} id The column id
53983 * @return {Object} the column
53985 getColumnById : function(id){
53986 return this.lookup[id];
53991 * Returns the column for a specified dataIndex.
53992 * @param {String} dataIndex The column dataIndex
53993 * @return {Object|Boolean} the column or false if not found
53995 getColumnByDataIndex: function(dataIndex){
53996 var index = this.findColumnIndex(dataIndex);
53997 return index > -1 ? this.config[index] : false;
54001 * Returns the index for a specified column id.
54002 * @param {String} id The column id
54003 * @return {Number} the index, or -1 if not found
54005 getIndexById : function(id){
54006 for(var i = 0, len = this.config.length; i < len; i++){
54007 if(this.config[i].id == id){
54015 * Returns the index for a specified column dataIndex.
54016 * @param {String} dataIndex The column dataIndex
54017 * @return {Number} the index, or -1 if not found
54020 findColumnIndex : function(dataIndex){
54021 for(var i = 0, len = this.config.length; i < len; i++){
54022 if(this.config[i].dataIndex == dataIndex){
54030 moveColumn : function(oldIndex, newIndex){
54031 var c = this.config[oldIndex];
54032 this.config.splice(oldIndex, 1);
54033 this.config.splice(newIndex, 0, c);
54034 this.dataMap = null;
54035 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54038 isLocked : function(colIndex){
54039 return this.config[colIndex].locked === true;
54042 setLocked : function(colIndex, value, suppressEvent){
54043 if(this.isLocked(colIndex) == value){
54046 this.config[colIndex].locked = value;
54047 if(!suppressEvent){
54048 this.fireEvent("columnlockchange", this, colIndex, value);
54052 getTotalLockedWidth : function(){
54053 var totalWidth = 0;
54054 for(var i = 0; i < this.config.length; i++){
54055 if(this.isLocked(i) && !this.isHidden(i)){
54056 this.totalWidth += this.getColumnWidth(i);
54062 getLockedCount : function(){
54063 for(var i = 0, len = this.config.length; i < len; i++){
54064 if(!this.isLocked(i)){
54071 * Returns the number of columns.
54074 getColumnCount : function(visibleOnly){
54075 if(visibleOnly === true){
54077 for(var i = 0, len = this.config.length; i < len; i++){
54078 if(!this.isHidden(i)){
54084 return this.config.length;
54088 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54089 * @param {Function} fn
54090 * @param {Object} scope (optional)
54091 * @return {Array} result
54093 getColumnsBy : function(fn, scope){
54095 for(var i = 0, len = this.config.length; i < len; i++){
54096 var c = this.config[i];
54097 if(fn.call(scope||this, c, i) === true){
54105 * Returns true if the specified column is sortable.
54106 * @param {Number} col The column index
54107 * @return {Boolean}
54109 isSortable : function(col){
54110 if(typeof this.config[col].sortable == "undefined"){
54111 return this.defaultSortable;
54113 return this.config[col].sortable;
54117 * Returns the rendering (formatting) function defined for the column.
54118 * @param {Number} col The column index.
54119 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54121 getRenderer : function(col){
54122 if(!this.config[col].renderer){
54123 return Roo.grid.ColumnModel.defaultRenderer;
54125 return this.config[col].renderer;
54129 * Sets the rendering (formatting) function for a column.
54130 * @param {Number} col The column index
54131 * @param {Function} fn The function to use to process the cell's raw data
54132 * to return HTML markup for the grid view. The render function is called with
54133 * the following parameters:<ul>
54134 * <li>Data value.</li>
54135 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54136 * <li>css A CSS style string to apply to the table cell.</li>
54137 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54138 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54139 * <li>Row index</li>
54140 * <li>Column index</li>
54141 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54143 setRenderer : function(col, fn){
54144 this.config[col].renderer = fn;
54148 * Returns the width for the specified column.
54149 * @param {Number} col The column index
54152 getColumnWidth : function(col){
54153 return this.config[col].width * 1 || this.defaultWidth;
54157 * Sets the width for a column.
54158 * @param {Number} col The column index
54159 * @param {Number} width The new width
54161 setColumnWidth : function(col, width, suppressEvent){
54162 this.config[col].width = width;
54163 this.totalWidth = null;
54164 if(!suppressEvent){
54165 this.fireEvent("widthchange", this, col, width);
54170 * Returns the total width of all columns.
54171 * @param {Boolean} includeHidden True to include hidden column widths
54174 getTotalWidth : function(includeHidden){
54175 if(!this.totalWidth){
54176 this.totalWidth = 0;
54177 for(var i = 0, len = this.config.length; i < len; i++){
54178 if(includeHidden || !this.isHidden(i)){
54179 this.totalWidth += this.getColumnWidth(i);
54183 return this.totalWidth;
54187 * Returns the header for the specified column.
54188 * @param {Number} col The column index
54191 getColumnHeader : function(col){
54192 return this.config[col].header;
54196 * Sets the header for a column.
54197 * @param {Number} col The column index
54198 * @param {String} header The new header
54200 setColumnHeader : function(col, header){
54201 this.config[col].header = header;
54202 this.fireEvent("headerchange", this, col, header);
54206 * Returns the tooltip for the specified column.
54207 * @param {Number} col The column index
54210 getColumnTooltip : function(col){
54211 return this.config[col].tooltip;
54214 * Sets the tooltip for a column.
54215 * @param {Number} col The column index
54216 * @param {String} tooltip The new tooltip
54218 setColumnTooltip : function(col, tooltip){
54219 this.config[col].tooltip = tooltip;
54223 * Returns the dataIndex for the specified column.
54224 * @param {Number} col The column index
54227 getDataIndex : function(col){
54228 return this.config[col].dataIndex;
54232 * Sets the dataIndex for a column.
54233 * @param {Number} col The column index
54234 * @param {Number} dataIndex The new dataIndex
54236 setDataIndex : function(col, dataIndex){
54237 this.config[col].dataIndex = dataIndex;
54243 * Returns true if the cell is editable.
54244 * @param {Number} colIndex The column index
54245 * @param {Number} rowIndex The row index
54246 * @return {Boolean}
54248 isCellEditable : function(colIndex, rowIndex){
54249 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
54253 * Returns the editor defined for the cell/column.
54254 * return false or null to disable editing.
54255 * @param {Number} colIndex The column index
54256 * @param {Number} rowIndex The row index
54259 getCellEditor : function(colIndex, rowIndex){
54260 return this.config[colIndex].editor;
54264 * Sets if a column is editable.
54265 * @param {Number} col The column index
54266 * @param {Boolean} editable True if the column is editable
54268 setEditable : function(col, editable){
54269 this.config[col].editable = editable;
54274 * Returns true if the column is hidden.
54275 * @param {Number} colIndex The column index
54276 * @return {Boolean}
54278 isHidden : function(colIndex){
54279 return this.config[colIndex].hidden;
54284 * Returns true if the column width cannot be changed
54286 isFixed : function(colIndex){
54287 return this.config[colIndex].fixed;
54291 * Returns true if the column can be resized
54292 * @return {Boolean}
54294 isResizable : function(colIndex){
54295 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
54298 * Sets if a column is hidden.
54299 * @param {Number} colIndex The column index
54300 * @param {Boolean} hidden True if the column is hidden
54302 setHidden : function(colIndex, hidden){
54303 this.config[colIndex].hidden = hidden;
54304 this.totalWidth = null;
54305 this.fireEvent("hiddenchange", this, colIndex, hidden);
54309 * Sets the editor for a column.
54310 * @param {Number} col The column index
54311 * @param {Object} editor The editor object
54313 setEditor : function(col, editor){
54314 this.config[col].editor = editor;
54318 Roo.grid.ColumnModel.defaultRenderer = function(value){
54319 if(typeof value == "string" && value.length < 1){
54325 // Alias for backwards compatibility
54326 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
54329 * Ext JS Library 1.1.1
54330 * Copyright(c) 2006-2007, Ext JS, LLC.
54332 * Originally Released Under LGPL - original licence link has changed is not relivant.
54335 * <script type="text/javascript">
54339 * @class Roo.grid.AbstractSelectionModel
54340 * @extends Roo.util.Observable
54341 * Abstract base class for grid SelectionModels. It provides the interface that should be
54342 * implemented by descendant classes. This class should not be directly instantiated.
54345 Roo.grid.AbstractSelectionModel = function(){
54346 this.locked = false;
54347 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
54350 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
54351 /** @ignore Called by the grid automatically. Do not call directly. */
54352 init : function(grid){
54358 * Locks the selections.
54361 this.locked = true;
54365 * Unlocks the selections.
54367 unlock : function(){
54368 this.locked = false;
54372 * Returns true if the selections are locked.
54373 * @return {Boolean}
54375 isLocked : function(){
54376 return this.locked;
54380 * Ext JS Library 1.1.1
54381 * Copyright(c) 2006-2007, Ext JS, LLC.
54383 * Originally Released Under LGPL - original licence link has changed is not relivant.
54386 * <script type="text/javascript">
54389 * @extends Roo.grid.AbstractSelectionModel
54390 * @class Roo.grid.RowSelectionModel
54391 * The default SelectionModel used by {@link Roo.grid.Grid}.
54392 * It supports multiple selections and keyboard selection/navigation.
54394 * @param {Object} config
54396 Roo.grid.RowSelectionModel = function(config){
54397 Roo.apply(this, config);
54398 this.selections = new Roo.util.MixedCollection(false, function(o){
54403 this.lastActive = false;
54407 * @event selectionchange
54408 * Fires when the selection changes
54409 * @param {SelectionModel} this
54411 "selectionchange" : true,
54413 * @event afterselectionchange
54414 * Fires after the selection changes (eg. by key press or clicking)
54415 * @param {SelectionModel} this
54417 "afterselectionchange" : true,
54419 * @event beforerowselect
54420 * Fires when a row is selected being selected, return false to cancel.
54421 * @param {SelectionModel} this
54422 * @param {Number} rowIndex The selected index
54423 * @param {Boolean} keepExisting False if other selections will be cleared
54425 "beforerowselect" : true,
54428 * Fires when a row is selected.
54429 * @param {SelectionModel} this
54430 * @param {Number} rowIndex The selected index
54431 * @param {Roo.data.Record} r The record
54433 "rowselect" : true,
54435 * @event rowdeselect
54436 * Fires when a row is deselected.
54437 * @param {SelectionModel} this
54438 * @param {Number} rowIndex The selected index
54440 "rowdeselect" : true
54442 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
54443 this.locked = false;
54446 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
54448 * @cfg {Boolean} singleSelect
54449 * True to allow selection of only one row at a time (defaults to false)
54451 singleSelect : false,
54454 initEvents : function(){
54456 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
54457 this.grid.on("mousedown", this.handleMouseDown, this);
54458 }else{ // allow click to work like normal
54459 this.grid.on("rowclick", this.handleDragableRowClick, this);
54462 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
54463 "up" : function(e){
54465 this.selectPrevious(e.shiftKey);
54466 }else if(this.last !== false && this.lastActive !== false){
54467 var last = this.last;
54468 this.selectRange(this.last, this.lastActive-1);
54469 this.grid.getView().focusRow(this.lastActive);
54470 if(last !== false){
54474 this.selectFirstRow();
54476 this.fireEvent("afterselectionchange", this);
54478 "down" : function(e){
54480 this.selectNext(e.shiftKey);
54481 }else if(this.last !== false && this.lastActive !== false){
54482 var last = this.last;
54483 this.selectRange(this.last, this.lastActive+1);
54484 this.grid.getView().focusRow(this.lastActive);
54485 if(last !== false){
54489 this.selectFirstRow();
54491 this.fireEvent("afterselectionchange", this);
54496 var view = this.grid.view;
54497 view.on("refresh", this.onRefresh, this);
54498 view.on("rowupdated", this.onRowUpdated, this);
54499 view.on("rowremoved", this.onRemove, this);
54503 onRefresh : function(){
54504 var ds = this.grid.dataSource, i, v = this.grid.view;
54505 var s = this.selections;
54506 s.each(function(r){
54507 if((i = ds.indexOfId(r.id)) != -1){
54516 onRemove : function(v, index, r){
54517 this.selections.remove(r);
54521 onRowUpdated : function(v, index, r){
54522 if(this.isSelected(r)){
54523 v.onRowSelect(index);
54529 * @param {Array} records The records to select
54530 * @param {Boolean} keepExisting (optional) True to keep existing selections
54532 selectRecords : function(records, keepExisting){
54534 this.clearSelections();
54536 var ds = this.grid.dataSource;
54537 for(var i = 0, len = records.length; i < len; i++){
54538 this.selectRow(ds.indexOf(records[i]), true);
54543 * Gets the number of selected rows.
54546 getCount : function(){
54547 return this.selections.length;
54551 * Selects the first row in the grid.
54553 selectFirstRow : function(){
54558 * Select the last row.
54559 * @param {Boolean} keepExisting (optional) True to keep existing selections
54561 selectLastRow : function(keepExisting){
54562 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
54566 * Selects the row immediately following the last selected row.
54567 * @param {Boolean} keepExisting (optional) True to keep existing selections
54569 selectNext : function(keepExisting){
54570 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
54571 this.selectRow(this.last+1, keepExisting);
54572 this.grid.getView().focusRow(this.last);
54577 * Selects the row that precedes the last selected row.
54578 * @param {Boolean} keepExisting (optional) True to keep existing selections
54580 selectPrevious : function(keepExisting){
54582 this.selectRow(this.last-1, keepExisting);
54583 this.grid.getView().focusRow(this.last);
54588 * Returns the selected records
54589 * @return {Array} Array of selected records
54591 getSelections : function(){
54592 return [].concat(this.selections.items);
54596 * Returns the first selected record.
54599 getSelected : function(){
54600 return this.selections.itemAt(0);
54605 * Clears all selections.
54607 clearSelections : function(fast){
54608 if(this.locked) return;
54610 var ds = this.grid.dataSource;
54611 var s = this.selections;
54612 s.each(function(r){
54613 this.deselectRow(ds.indexOfId(r.id));
54617 this.selections.clear();
54624 * Selects all rows.
54626 selectAll : function(){
54627 if(this.locked) return;
54628 this.selections.clear();
54629 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
54630 this.selectRow(i, true);
54635 * Returns True if there is a selection.
54636 * @return {Boolean}
54638 hasSelection : function(){
54639 return this.selections.length > 0;
54643 * Returns True if the specified row is selected.
54644 * @param {Number/Record} record The record or index of the record to check
54645 * @return {Boolean}
54647 isSelected : function(index){
54648 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
54649 return (r && this.selections.key(r.id) ? true : false);
54653 * Returns True if the specified record id is selected.
54654 * @param {String} id The id of record to check
54655 * @return {Boolean}
54657 isIdSelected : function(id){
54658 return (this.selections.key(id) ? true : false);
54662 handleMouseDown : function(e, t){
54663 var view = this.grid.getView(), rowIndex;
54664 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
54667 if(e.shiftKey && this.last !== false){
54668 var last = this.last;
54669 this.selectRange(last, rowIndex, e.ctrlKey);
54670 this.last = last; // reset the last
54671 view.focusRow(rowIndex);
54673 var isSelected = this.isSelected(rowIndex);
54674 if(e.button !== 0 && isSelected){
54675 view.focusRow(rowIndex);
54676 }else if(e.ctrlKey && isSelected){
54677 this.deselectRow(rowIndex);
54678 }else if(!isSelected){
54679 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
54680 view.focusRow(rowIndex);
54683 this.fireEvent("afterselectionchange", this);
54686 handleDragableRowClick : function(grid, rowIndex, e)
54688 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
54689 this.selectRow(rowIndex, false);
54690 grid.view.focusRow(rowIndex);
54691 this.fireEvent("afterselectionchange", this);
54696 * Selects multiple rows.
54697 * @param {Array} rows Array of the indexes of the row to select
54698 * @param {Boolean} keepExisting (optional) True to keep existing selections
54700 selectRows : function(rows, keepExisting){
54702 this.clearSelections();
54704 for(var i = 0, len = rows.length; i < len; i++){
54705 this.selectRow(rows[i], true);
54710 * Selects a range of rows. All rows in between startRow and endRow are also selected.
54711 * @param {Number} startRow The index of the first row in the range
54712 * @param {Number} endRow The index of the last row in the range
54713 * @param {Boolean} keepExisting (optional) True to retain existing selections
54715 selectRange : function(startRow, endRow, keepExisting){
54716 if(this.locked) return;
54718 this.clearSelections();
54720 if(startRow <= endRow){
54721 for(var i = startRow; i <= endRow; i++){
54722 this.selectRow(i, true);
54725 for(var i = startRow; i >= endRow; i--){
54726 this.selectRow(i, true);
54732 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
54733 * @param {Number} startRow The index of the first row in the range
54734 * @param {Number} endRow The index of the last row in the range
54736 deselectRange : function(startRow, endRow, preventViewNotify){
54737 if(this.locked) return;
54738 for(var i = startRow; i <= endRow; i++){
54739 this.deselectRow(i, preventViewNotify);
54745 * @param {Number} row The index of the row to select
54746 * @param {Boolean} keepExisting (optional) True to keep existing selections
54748 selectRow : function(index, keepExisting, preventViewNotify){
54749 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
54750 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
54751 if(!keepExisting || this.singleSelect){
54752 this.clearSelections();
54754 var r = this.grid.dataSource.getAt(index);
54755 this.selections.add(r);
54756 this.last = this.lastActive = index;
54757 if(!preventViewNotify){
54758 this.grid.getView().onRowSelect(index);
54760 this.fireEvent("rowselect", this, index, r);
54761 this.fireEvent("selectionchange", this);
54767 * @param {Number} row The index of the row to deselect
54769 deselectRow : function(index, preventViewNotify){
54770 if(this.locked) return;
54771 if(this.last == index){
54774 if(this.lastActive == index){
54775 this.lastActive = false;
54777 var r = this.grid.dataSource.getAt(index);
54778 this.selections.remove(r);
54779 if(!preventViewNotify){
54780 this.grid.getView().onRowDeselect(index);
54782 this.fireEvent("rowdeselect", this, index);
54783 this.fireEvent("selectionchange", this);
54787 restoreLast : function(){
54789 this.last = this._last;
54794 acceptsNav : function(row, col, cm){
54795 return !cm.isHidden(col) && cm.isCellEditable(col, row);
54799 onEditorKey : function(field, e){
54800 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
54805 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
54807 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54809 }else if(k == e.ENTER && !e.ctrlKey){
54813 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
54815 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
54817 }else if(k == e.ESC){
54821 g.startEditing(newCell[0], newCell[1]);
54826 * Ext JS Library 1.1.1
54827 * Copyright(c) 2006-2007, Ext JS, LLC.
54829 * Originally Released Under LGPL - original licence link has changed is not relivant.
54832 * <script type="text/javascript">
54835 * @class Roo.grid.CellSelectionModel
54836 * @extends Roo.grid.AbstractSelectionModel
54837 * This class provides the basic implementation for cell selection in a grid.
54839 * @param {Object} config The object containing the configuration of this model.
54840 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
54842 Roo.grid.CellSelectionModel = function(config){
54843 Roo.apply(this, config);
54845 this.selection = null;
54849 * @event beforerowselect
54850 * Fires before a cell is selected.
54851 * @param {SelectionModel} this
54852 * @param {Number} rowIndex The selected row index
54853 * @param {Number} colIndex The selected cell index
54855 "beforecellselect" : true,
54857 * @event cellselect
54858 * Fires when a cell is selected.
54859 * @param {SelectionModel} this
54860 * @param {Number} rowIndex The selected row index
54861 * @param {Number} colIndex The selected cell index
54863 "cellselect" : true,
54865 * @event selectionchange
54866 * Fires when the active selection changes.
54867 * @param {SelectionModel} this
54868 * @param {Object} selection null for no selection or an object (o) with two properties
54870 <li>o.record: the record object for the row the selection is in</li>
54871 <li>o.cell: An array of [rowIndex, columnIndex]</li>
54874 "selectionchange" : true,
54877 * Fires when the tab (or enter) was pressed on the last editable cell
54878 * You can use this to trigger add new row.
54879 * @param {SelectionModel} this
54883 * @event beforeeditnext
54884 * Fires before the next editable sell is made active
54885 * You can use this to skip to another cell or fire the tabend
54886 * if you set cell to false
54887 * @param {Object} eventdata object : { cell : [ row, col ] }
54889 "beforeeditnext" : true
54891 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
54894 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
54896 enter_is_tab: false,
54899 initEvents : function(){
54900 this.grid.on("mousedown", this.handleMouseDown, this);
54901 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
54902 var view = this.grid.view;
54903 view.on("refresh", this.onViewChange, this);
54904 view.on("rowupdated", this.onRowUpdated, this);
54905 view.on("beforerowremoved", this.clearSelections, this);
54906 view.on("beforerowsinserted", this.clearSelections, this);
54907 if(this.grid.isEditor){
54908 this.grid.on("beforeedit", this.beforeEdit, this);
54913 beforeEdit : function(e){
54914 this.select(e.row, e.column, false, true, e.record);
54918 onRowUpdated : function(v, index, r){
54919 if(this.selection && this.selection.record == r){
54920 v.onCellSelect(index, this.selection.cell[1]);
54925 onViewChange : function(){
54926 this.clearSelections(true);
54930 * Returns the currently selected cell,.
54931 * @return {Array} The selected cell (row, column) or null if none selected.
54933 getSelectedCell : function(){
54934 return this.selection ? this.selection.cell : null;
54938 * Clears all selections.
54939 * @param {Boolean} true to prevent the gridview from being notified about the change.
54941 clearSelections : function(preventNotify){
54942 var s = this.selection;
54944 if(preventNotify !== true){
54945 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
54947 this.selection = null;
54948 this.fireEvent("selectionchange", this, null);
54953 * Returns true if there is a selection.
54954 * @return {Boolean}
54956 hasSelection : function(){
54957 return this.selection ? true : false;
54961 handleMouseDown : function(e, t){
54962 var v = this.grid.getView();
54963 if(this.isLocked()){
54966 var row = v.findRowIndex(t);
54967 var cell = v.findCellIndex(t);
54968 if(row !== false && cell !== false){
54969 this.select(row, cell);
54975 * @param {Number} rowIndex
54976 * @param {Number} collIndex
54978 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
54979 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
54980 this.clearSelections();
54981 r = r || this.grid.dataSource.getAt(rowIndex);
54984 cell : [rowIndex, colIndex]
54986 if(!preventViewNotify){
54987 var v = this.grid.getView();
54988 v.onCellSelect(rowIndex, colIndex);
54989 if(preventFocus !== true){
54990 v.focusCell(rowIndex, colIndex);
54993 this.fireEvent("cellselect", this, rowIndex, colIndex);
54994 this.fireEvent("selectionchange", this, this.selection);
54999 isSelectable : function(rowIndex, colIndex, cm){
55000 return !cm.isHidden(colIndex);
55004 handleKeyDown : function(e){
55005 //Roo.log('Cell Sel Model handleKeyDown');
55006 if(!e.isNavKeyPress()){
55009 var g = this.grid, s = this.selection;
55012 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55014 this.select(cell[0], cell[1]);
55019 var walk = function(row, col, step){
55020 return g.walkCells(row, col, step, sm.isSelectable, sm);
55022 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55029 // handled by onEditorKey
55030 if (g.isEditor && g.editing) {
55034 newCell = walk(r, c-1, -1);
55036 newCell = walk(r, c+1, 1);
55041 newCell = walk(r+1, c, 1);
55045 newCell = walk(r-1, c, -1);
55049 newCell = walk(r, c+1, 1);
55053 newCell = walk(r, c-1, -1);
55058 if(g.isEditor && !g.editing){
55059 g.startEditing(r, c);
55068 this.select(newCell[0], newCell[1]);
55074 acceptsNav : function(row, col, cm){
55075 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55079 * @param {Number} field (not used) - as it's normally used as a listener
55080 * @param {Number} e - event - fake it by using
55082 * var e = Roo.EventObjectImpl.prototype;
55083 * e.keyCode = e.TAB
55087 onEditorKey : function(field, e){
55089 var k = e.getKey(),
55092 ed = g.activeEditor,
55094 ///Roo.log('onEditorKey' + k);
55097 if (this.enter_is_tab && k == e.ENTER) {
55103 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55105 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55111 } else if(k == e.ENTER && !e.ctrlKey){
55114 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55116 } else if(k == e.ESC){
55121 var ecall = { cell : newCell, forward : forward };
55122 this.fireEvent('beforeeditnext', ecall );
55123 newCell = ecall.cell;
55124 forward = ecall.forward;
55128 //Roo.log('next cell after edit');
55129 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55130 } else if (forward) {
55131 // tabbed past last
55132 this.fireEvent.defer(100, this, ['tabend',this]);
55137 * Ext JS Library 1.1.1
55138 * Copyright(c) 2006-2007, Ext JS, LLC.
55140 * Originally Released Under LGPL - original licence link has changed is not relivant.
55143 * <script type="text/javascript">
55147 * @class Roo.grid.EditorGrid
55148 * @extends Roo.grid.Grid
55149 * Class for creating and editable grid.
55150 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55151 * The container MUST have some type of size defined for the grid to fill. The container will be
55152 * automatically set to position relative if it isn't already.
55153 * @param {Object} dataSource The data model to bind to
55154 * @param {Object} colModel The column model with info about this grid's columns
55156 Roo.grid.EditorGrid = function(container, config){
55157 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55158 this.getGridEl().addClass("xedit-grid");
55160 if(!this.selModel){
55161 this.selModel = new Roo.grid.CellSelectionModel();
55164 this.activeEditor = null;
55168 * @event beforeedit
55169 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55170 * <ul style="padding:5px;padding-left:16px;">
55171 * <li>grid - This grid</li>
55172 * <li>record - The record being edited</li>
55173 * <li>field - The field name being edited</li>
55174 * <li>value - The value for the field being edited.</li>
55175 * <li>row - The grid row index</li>
55176 * <li>column - The grid column index</li>
55177 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55179 * @param {Object} e An edit event (see above for description)
55181 "beforeedit" : true,
55184 * Fires after a cell is edited. <br />
55185 * <ul style="padding:5px;padding-left:16px;">
55186 * <li>grid - This grid</li>
55187 * <li>record - The record being edited</li>
55188 * <li>field - The field name being edited</li>
55189 * <li>value - The value being set</li>
55190 * <li>originalValue - The original value for the field, before the edit.</li>
55191 * <li>row - The grid row index</li>
55192 * <li>column - The grid column index</li>
55194 * @param {Object} e An edit event (see above for description)
55196 "afteredit" : true,
55198 * @event validateedit
55199 * Fires after a cell is edited, but before the value is set in the record.
55200 * You can use this to modify the value being set in the field, Return false
55201 * to cancel the change. The edit event object has the following properties <br />
55202 * <ul style="padding:5px;padding-left:16px;">
55203 * <li>editor - This editor</li>
55204 * <li>grid - This grid</li>
55205 * <li>record - The record being edited</li>
55206 * <li>field - The field name being edited</li>
55207 * <li>value - The value being set</li>
55208 * <li>originalValue - The original value for the field, before the edit.</li>
55209 * <li>row - The grid row index</li>
55210 * <li>column - The grid column index</li>
55211 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55213 * @param {Object} e An edit event (see above for description)
55215 "validateedit" : true
55217 this.on("bodyscroll", this.stopEditing, this);
55218 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
55221 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
55223 * @cfg {Number} clicksToEdit
55224 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
55231 trackMouseOver: false, // causes very odd FF errors
55233 onCellDblClick : function(g, row, col){
55234 this.startEditing(row, col);
55237 onEditComplete : function(ed, value, startValue){
55238 this.editing = false;
55239 this.activeEditor = null;
55240 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
55242 var field = this.colModel.getDataIndex(ed.col);
55247 originalValue: startValue,
55254 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
55257 if(String(value) !== String(startValue)){
55259 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
55260 r.set(field, e.value);
55261 // if we are dealing with a combo box..
55262 // then we also set the 'name' colum to be the displayField
55263 if (ed.field.displayField && ed.field.name) {
55264 r.set(ed.field.name, ed.field.el.dom.value);
55267 delete e.cancel; //?? why!!!
55268 this.fireEvent("afteredit", e);
55271 this.fireEvent("afteredit", e); // always fire it!
55273 this.view.focusCell(ed.row, ed.col);
55277 * Starts editing the specified for the specified row/column
55278 * @param {Number} rowIndex
55279 * @param {Number} colIndex
55281 startEditing : function(row, col){
55282 this.stopEditing();
55283 if(this.colModel.isCellEditable(col, row)){
55284 this.view.ensureVisible(row, col, true);
55286 var r = this.dataSource.getAt(row);
55287 var field = this.colModel.getDataIndex(col);
55288 var cell = Roo.get(this.view.getCell(row,col));
55293 value: r.data[field],
55298 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
55299 this.editing = true;
55300 var ed = this.colModel.getCellEditor(col, row);
55306 ed.render(ed.parentEl || document.body);
55312 (function(){ // complex but required for focus issues in safari, ie and opera
55316 ed.on("complete", this.onEditComplete, this, {single: true});
55317 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
55318 this.activeEditor = ed;
55319 var v = r.data[field];
55320 ed.startEdit(this.view.getCell(row, col), v);
55321 // combo's with 'displayField and name set
55322 if (ed.field.displayField && ed.field.name) {
55323 ed.field.el.dom.value = r.data[ed.field.name];
55327 }).defer(50, this);
55333 * Stops any active editing
55335 stopEditing : function(){
55336 if(this.activeEditor){
55337 this.activeEditor.completeEdit();
55339 this.activeEditor = null;
55343 * Called to get grid's drag proxy text, by default returns this.ddText.
55346 getDragDropText : function(){
55347 var count = this.selModel.getSelectedCell() ? 1 : 0;
55348 return String.format(this.ddText, count, count == 1 ? '' : 's');
55353 * Ext JS Library 1.1.1
55354 * Copyright(c) 2006-2007, Ext JS, LLC.
55356 * Originally Released Under LGPL - original licence link has changed is not relivant.
55359 * <script type="text/javascript">
55362 // private - not really -- you end up using it !
55363 // This is a support class used internally by the Grid components
55366 * @class Roo.grid.GridEditor
55367 * @extends Roo.Editor
55368 * Class for creating and editable grid elements.
55369 * @param {Object} config any settings (must include field)
55371 Roo.grid.GridEditor = function(field, config){
55372 if (!config && field.field) {
55374 field = Roo.factory(config.field, Roo.form);
55376 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
55377 field.monitorTab = false;
55380 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
55383 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
55386 alignment: "tl-tl",
55389 cls: "x-small-editor x-grid-editor",
55394 * Ext JS Library 1.1.1
55395 * Copyright(c) 2006-2007, Ext JS, LLC.
55397 * Originally Released Under LGPL - original licence link has changed is not relivant.
55400 * <script type="text/javascript">
55405 Roo.grid.PropertyRecord = Roo.data.Record.create([
55406 {name:'name',type:'string'}, 'value'
55410 Roo.grid.PropertyStore = function(grid, source){
55412 this.store = new Roo.data.Store({
55413 recordType : Roo.grid.PropertyRecord
55415 this.store.on('update', this.onUpdate, this);
55417 this.setSource(source);
55419 Roo.grid.PropertyStore.superclass.constructor.call(this);
55424 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
55425 setSource : function(o){
55427 this.store.removeAll();
55430 if(this.isEditableValue(o[k])){
55431 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
55434 this.store.loadRecords({records: data}, {}, true);
55437 onUpdate : function(ds, record, type){
55438 if(type == Roo.data.Record.EDIT){
55439 var v = record.data['value'];
55440 var oldValue = record.modified['value'];
55441 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
55442 this.source[record.id] = v;
55444 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
55451 getProperty : function(row){
55452 return this.store.getAt(row);
55455 isEditableValue: function(val){
55456 if(val && val instanceof Date){
55458 }else if(typeof val == 'object' || typeof val == 'function'){
55464 setValue : function(prop, value){
55465 this.source[prop] = value;
55466 this.store.getById(prop).set('value', value);
55469 getSource : function(){
55470 return this.source;
55474 Roo.grid.PropertyColumnModel = function(grid, store){
55477 g.PropertyColumnModel.superclass.constructor.call(this, [
55478 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
55479 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
55481 this.store = store;
55482 this.bselect = Roo.DomHelper.append(document.body, {
55483 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
55484 {tag: 'option', value: 'true', html: 'true'},
55485 {tag: 'option', value: 'false', html: 'false'}
55488 Roo.id(this.bselect);
55491 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
55492 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
55493 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
55494 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
55495 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
55497 this.renderCellDelegate = this.renderCell.createDelegate(this);
55498 this.renderPropDelegate = this.renderProp.createDelegate(this);
55501 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
55505 valueText : 'Value',
55507 dateFormat : 'm/j/Y',
55510 renderDate : function(dateVal){
55511 return dateVal.dateFormat(this.dateFormat);
55514 renderBool : function(bVal){
55515 return bVal ? 'true' : 'false';
55518 isCellEditable : function(colIndex, rowIndex){
55519 return colIndex == 1;
55522 getRenderer : function(col){
55524 this.renderCellDelegate : this.renderPropDelegate;
55527 renderProp : function(v){
55528 return this.getPropertyName(v);
55531 renderCell : function(val){
55533 if(val instanceof Date){
55534 rv = this.renderDate(val);
55535 }else if(typeof val == 'boolean'){
55536 rv = this.renderBool(val);
55538 return Roo.util.Format.htmlEncode(rv);
55541 getPropertyName : function(name){
55542 var pn = this.grid.propertyNames;
55543 return pn && pn[name] ? pn[name] : name;
55546 getCellEditor : function(colIndex, rowIndex){
55547 var p = this.store.getProperty(rowIndex);
55548 var n = p.data['name'], val = p.data['value'];
55550 if(typeof(this.grid.customEditors[n]) == 'string'){
55551 return this.editors[this.grid.customEditors[n]];
55553 if(typeof(this.grid.customEditors[n]) != 'undefined'){
55554 return this.grid.customEditors[n];
55556 if(val instanceof Date){
55557 return this.editors['date'];
55558 }else if(typeof val == 'number'){
55559 return this.editors['number'];
55560 }else if(typeof val == 'boolean'){
55561 return this.editors['boolean'];
55563 return this.editors['string'];
55569 * @class Roo.grid.PropertyGrid
55570 * @extends Roo.grid.EditorGrid
55571 * This class represents the interface of a component based property grid control.
55572 * <br><br>Usage:<pre><code>
55573 var grid = new Roo.grid.PropertyGrid("my-container-id", {
55581 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55582 * The container MUST have some type of size defined for the grid to fill. The container will be
55583 * automatically set to position relative if it isn't already.
55584 * @param {Object} config A config object that sets properties on this grid.
55586 Roo.grid.PropertyGrid = function(container, config){
55587 config = config || {};
55588 var store = new Roo.grid.PropertyStore(this);
55589 this.store = store;
55590 var cm = new Roo.grid.PropertyColumnModel(this, store);
55591 store.store.sort('name', 'ASC');
55592 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
55595 enableColLock:false,
55596 enableColumnMove:false,
55598 trackMouseOver: false,
55601 this.getGridEl().addClass('x-props-grid');
55602 this.lastEditRow = null;
55603 this.on('columnresize', this.onColumnResize, this);
55606 * @event beforepropertychange
55607 * Fires before a property changes (return false to stop?)
55608 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55609 * @param {String} id Record Id
55610 * @param {String} newval New Value
55611 * @param {String} oldval Old Value
55613 "beforepropertychange": true,
55615 * @event propertychange
55616 * Fires after a property changes
55617 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55618 * @param {String} id Record Id
55619 * @param {String} newval New Value
55620 * @param {String} oldval Old Value
55622 "propertychange": true
55624 this.customEditors = this.customEditors || {};
55626 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
55629 * @cfg {Object} customEditors map of colnames=> custom editors.
55630 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
55631 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
55632 * false disables editing of the field.
55636 * @cfg {Object} propertyNames map of property Names to their displayed value
55639 render : function(){
55640 Roo.grid.PropertyGrid.superclass.render.call(this);
55641 this.autoSize.defer(100, this);
55644 autoSize : function(){
55645 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
55647 this.view.fitColumns();
55651 onColumnResize : function(){
55652 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
55656 * Sets the data for the Grid
55657 * accepts a Key => Value object of all the elements avaiable.
55658 * @param {Object} data to appear in grid.
55660 setSource : function(source){
55661 this.store.setSource(source);
55665 * Gets all the data from the grid.
55666 * @return {Object} data data stored in grid
55668 getSource : function(){
55669 return this.store.getSource();
55673 * Ext JS Library 1.1.1
55674 * Copyright(c) 2006-2007, Ext JS, LLC.
55676 * Originally Released Under LGPL - original licence link has changed is not relivant.
55679 * <script type="text/javascript">
55683 * @class Roo.LoadMask
55684 * A simple utility class for generically masking elements while loading data. If the element being masked has
55685 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
55686 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
55687 * element's UpdateManager load indicator and will be destroyed after the initial load.
55689 * Create a new LoadMask
55690 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
55691 * @param {Object} config The config object
55693 Roo.LoadMask = function(el, config){
55694 this.el = Roo.get(el);
55695 Roo.apply(this, config);
55697 this.store.on('beforeload', this.onBeforeLoad, this);
55698 this.store.on('load', this.onLoad, this);
55699 this.store.on('loadexception', this.onLoadException, this);
55700 this.removeMask = false;
55702 var um = this.el.getUpdateManager();
55703 um.showLoadIndicator = false; // disable the default indicator
55704 um.on('beforeupdate', this.onBeforeLoad, this);
55705 um.on('update', this.onLoad, this);
55706 um.on('failure', this.onLoad, this);
55707 this.removeMask = true;
55711 Roo.LoadMask.prototype = {
55713 * @cfg {Boolean} removeMask
55714 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
55715 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
55718 * @cfg {String} msg
55719 * The text to display in a centered loading message box (defaults to 'Loading...')
55721 msg : 'Loading...',
55723 * @cfg {String} msgCls
55724 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
55726 msgCls : 'x-mask-loading',
55729 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
55735 * Disables the mask to prevent it from being displayed
55737 disable : function(){
55738 this.disabled = true;
55742 * Enables the mask so that it can be displayed
55744 enable : function(){
55745 this.disabled = false;
55748 onLoadException : function()
55750 Roo.log(arguments);
55752 if (typeof(arguments[3]) != 'undefined') {
55753 Roo.MessageBox.alert("Error loading",arguments[3]);
55757 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
55758 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
55767 this.el.unmask(this.removeMask);
55770 onLoad : function()
55772 this.el.unmask(this.removeMask);
55776 onBeforeLoad : function(){
55777 if(!this.disabled){
55778 this.el.mask(this.msg, this.msgCls);
55783 destroy : function(){
55785 this.store.un('beforeload', this.onBeforeLoad, this);
55786 this.store.un('load', this.onLoad, this);
55787 this.store.un('loadexception', this.onLoadException, this);
55789 var um = this.el.getUpdateManager();
55790 um.un('beforeupdate', this.onBeforeLoad, this);
55791 um.un('update', this.onLoad, this);
55792 um.un('failure', this.onLoad, this);
55797 * Ext JS Library 1.1.1
55798 * Copyright(c) 2006-2007, Ext JS, LLC.
55800 * Originally Released Under LGPL - original licence link has changed is not relivant.
55803 * <script type="text/javascript">
55808 * @class Roo.XTemplate
55809 * @extends Roo.Template
55810 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
55812 var t = new Roo.XTemplate(
55813 '<select name="{name}">',
55814 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
55818 // then append, applying the master template values
55821 * Supported features:
55826 {a_variable} - output encoded.
55827 {a_variable.format:("Y-m-d")} - call a method on the variable
55828 {a_variable:raw} - unencoded output
55829 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
55830 {a_variable:this.method_on_template(...)} - call a method on the template object.
55835 <tpl for="a_variable or condition.."></tpl>
55836 <tpl if="a_variable or condition"></tpl>
55837 <tpl exec="some javascript"></tpl>
55838 <tpl name="named_template"></tpl> (experimental)
55840 <tpl for="."></tpl> - just iterate the property..
55841 <tpl for=".."></tpl> - iterates with the parent (probably the template)
55845 Roo.XTemplate = function()
55847 Roo.XTemplate.superclass.constructor.apply(this, arguments);
55854 Roo.extend(Roo.XTemplate, Roo.Template, {
55857 * The various sub templates
55862 * basic tag replacing syntax
55865 * // you can fake an object call by doing this
55869 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
55872 * compile the template
55874 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
55877 compile: function()
55881 s = ['<tpl>', s, '</tpl>'].join('');
55883 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
55884 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
55885 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
55886 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
55887 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
55892 while(true == !!(m = s.match(re))){
55893 var forMatch = m[0].match(nameRe),
55894 ifMatch = m[0].match(ifRe),
55895 execMatch = m[0].match(execRe),
55896 namedMatch = m[0].match(namedRe),
55901 name = forMatch && forMatch[1] ? forMatch[1] : '';
55904 // if - puts fn into test..
55905 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
55907 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
55912 // exec - calls a function... returns empty if true is returned.
55913 exp = execMatch && execMatch[1] ? execMatch[1] : null;
55915 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
55923 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
55924 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
55925 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
55928 var uid = namedMatch ? namedMatch[1] : id;
55932 id: namedMatch ? namedMatch[1] : id,
55939 s = s.replace(m[0], '');
55941 s = s.replace(m[0], '{xtpl'+ id + '}');
55946 for(var i = tpls.length-1; i >= 0; --i){
55947 this.compileTpl(tpls[i]);
55948 this.tpls[tpls[i].id] = tpls[i];
55950 this.master = tpls[tpls.length-1];
55954 * same as applyTemplate, except it's done to one of the subTemplates
55955 * when using named templates, you can do:
55957 * var str = pl.applySubTemplate('your-name', values);
55960 * @param {Number} id of the template
55961 * @param {Object} values to apply to template
55962 * @param {Object} parent (normaly the instance of this object)
55964 applySubTemplate : function(id, values, parent)
55968 var t = this.tpls[id];
55972 if(t.test && !t.test.call(this, values, parent)){
55976 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
55977 Roo.log(e.toString());
55983 if(t.exec && t.exec.call(this, values, parent)){
55987 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
55988 Roo.log(e.toString());
55993 var vs = t.target ? t.target.call(this, values, parent) : values;
55994 parent = t.target ? values : parent;
55995 if(t.target && vs instanceof Array){
55997 for(var i = 0, len = vs.length; i < len; i++){
55998 buf[buf.length] = t.compiled.call(this, vs[i], parent);
56000 return buf.join('');
56002 return t.compiled.call(this, vs, parent);
56004 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
56005 Roo.log(e.toString());
56006 Roo.log(t.compiled);
56011 compileTpl : function(tpl)
56013 var fm = Roo.util.Format;
56014 var useF = this.disableFormats !== true;
56015 var sep = Roo.isGecko ? "+" : ",";
56016 var undef = function(str) {
56017 Roo.log("Property not found :" + str);
56021 var fn = function(m, name, format, args)
56023 //Roo.log(arguments);
56024 args = args ? args.replace(/\\'/g,"'") : args;
56025 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
56026 if (typeof(format) == 'undefined') {
56027 format= 'htmlEncode';
56029 if (format == 'raw' ) {
56033 if(name.substr(0, 4) == 'xtpl'){
56034 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
56037 // build an array of options to determine if value is undefined..
56039 // basically get 'xxxx.yyyy' then do
56040 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
56041 // (function () { Roo.log("Property not found"); return ''; })() :
56046 Roo.each(name.split('.'), function(st) {
56047 lookfor += (lookfor.length ? '.': '') + st;
56048 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
56051 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
56054 if(format && useF){
56056 args = args ? ',' + args : "";
56058 if(format.substr(0, 5) != "this."){
56059 format = "fm." + format + '(';
56061 format = 'this.call("'+ format.substr(5) + '", ';
56065 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
56069 // called with xxyx.yuu:(test,test)
56071 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
56073 // raw.. - :raw modifier..
56074 return "'"+ sep + udef_st + name + ")"+sep+"'";
56078 // branched to use + in gecko and [].join() in others
56080 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
56081 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
56084 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
56085 body.push(tpl.body.replace(/(\r\n|\n)/g,
56086 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
56087 body.push("'].join('');};};");
56088 body = body.join('');
56091 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
56093 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
56099 applyTemplate : function(values){
56100 return this.master.compiled.call(this, values, {});
56101 //var s = this.subs;
56104 apply : function(){
56105 return this.applyTemplate.apply(this, arguments);
56110 Roo.XTemplate.from = function(el){
56111 el = Roo.getDom(el);
56112 return new Roo.XTemplate(el.value || el.innerHTML);