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 || Roo.util.Format.defaults.date);
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, "");
13636 Roo.util.Format.defaults = {
13640 * Ext JS Library 1.1.1
13641 * Copyright(c) 2006-2007, Ext JS, LLC.
13643 * Originally Released Under LGPL - original licence link has changed is not relivant.
13646 * <script type="text/javascript">
13653 * @class Roo.MasterTemplate
13654 * @extends Roo.Template
13655 * Provides a template that can have child templates. The syntax is:
13657 var t = new Roo.MasterTemplate(
13658 '<select name="{name}">',
13659 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13662 t.add('options', {value: 'foo', text: 'bar'});
13663 // or you can add multiple child elements in one shot
13664 t.addAll('options', [
13665 {value: 'foo', text: 'bar'},
13666 {value: 'foo2', text: 'bar2'},
13667 {value: 'foo3', text: 'bar3'}
13669 // then append, applying the master template values
13670 t.append('my-form', {name: 'my-select'});
13672 * A name attribute for the child template is not required if you have only one child
13673 * template or you want to refer to them by index.
13675 Roo.MasterTemplate = function(){
13676 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13677 this.originalHtml = this.html;
13679 var m, re = this.subTemplateRe;
13682 while(m = re.exec(this.html)){
13683 var name = m[1], content = m[2];
13688 tpl : new Roo.Template(content)
13691 st[name] = st[subIndex];
13693 st[subIndex].tpl.compile();
13694 st[subIndex].tpl.call = this.call.createDelegate(this);
13697 this.subCount = subIndex;
13700 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13702 * The regular expression used to match sub templates
13706 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13709 * Applies the passed values to a child template.
13710 * @param {String/Number} name (optional) The name or index of the child template
13711 * @param {Array/Object} values The values to be applied to the template
13712 * @return {MasterTemplate} this
13714 add : function(name, values){
13715 if(arguments.length == 1){
13716 values = arguments[0];
13719 var s = this.subs[name];
13720 s.buffer[s.buffer.length] = s.tpl.apply(values);
13725 * Applies all the passed values to a child template.
13726 * @param {String/Number} name (optional) The name or index of the child template
13727 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13728 * @param {Boolean} reset (optional) True to reset the template first
13729 * @return {MasterTemplate} this
13731 fill : function(name, values, reset){
13733 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13741 for(var i = 0, len = values.length; i < len; i++){
13742 this.add(name, values[i]);
13748 * Resets the template for reuse
13749 * @return {MasterTemplate} this
13751 reset : function(){
13753 for(var i = 0; i < this.subCount; i++){
13759 applyTemplate : function(values){
13761 var replaceIndex = -1;
13762 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13763 return s[++replaceIndex].buffer.join("");
13765 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13768 apply : function(){
13769 return this.applyTemplate.apply(this, arguments);
13772 compile : function(){return this;}
13776 * Alias for fill().
13779 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13781 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13782 * var tpl = Roo.MasterTemplate.from('element-id');
13783 * @param {String/HTMLElement} el
13784 * @param {Object} config
13787 Roo.MasterTemplate.from = function(el, config){
13788 el = Roo.getDom(el);
13789 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13792 * Ext JS Library 1.1.1
13793 * Copyright(c) 2006-2007, Ext JS, LLC.
13795 * Originally Released Under LGPL - original licence link has changed is not relivant.
13798 * <script type="text/javascript">
13803 * @class Roo.util.CSS
13804 * Utility class for manipulating CSS rules
13807 Roo.util.CSS = function(){
13809 var doc = document;
13811 var camelRe = /(-[a-z])/gi;
13812 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13816 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13817 * tag and appended to the HEAD of the document.
13818 * @param {String|Object} cssText The text containing the css rules
13819 * @param {String} id An id to add to the stylesheet for later removal
13820 * @return {StyleSheet}
13822 createStyleSheet : function(cssText, id){
13824 var head = doc.getElementsByTagName("head")[0];
13825 var nrules = doc.createElement("style");
13826 nrules.setAttribute("type", "text/css");
13828 nrules.setAttribute("id", id);
13830 if (typeof(cssText) != 'string') {
13831 // support object maps..
13832 // not sure if this a good idea..
13833 // perhaps it should be merged with the general css handling
13834 // and handle js style props.
13835 var cssTextNew = [];
13836 for(var n in cssText) {
13838 for(var k in cssText[n]) {
13839 citems.push( k + ' : ' +cssText[n][k] + ';' );
13841 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13844 cssText = cssTextNew.join("\n");
13850 head.appendChild(nrules);
13851 ss = nrules.styleSheet;
13852 ss.cssText = cssText;
13855 nrules.appendChild(doc.createTextNode(cssText));
13857 nrules.cssText = cssText;
13859 head.appendChild(nrules);
13860 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13862 this.cacheStyleSheet(ss);
13867 * Removes a style or link tag by id
13868 * @param {String} id The id of the tag
13870 removeStyleSheet : function(id){
13871 var existing = doc.getElementById(id);
13873 existing.parentNode.removeChild(existing);
13878 * Dynamically swaps an existing stylesheet reference for a new one
13879 * @param {String} id The id of an existing link tag to remove
13880 * @param {String} url The href of the new stylesheet to include
13882 swapStyleSheet : function(id, url){
13883 this.removeStyleSheet(id);
13884 var ss = doc.createElement("link");
13885 ss.setAttribute("rel", "stylesheet");
13886 ss.setAttribute("type", "text/css");
13887 ss.setAttribute("id", id);
13888 ss.setAttribute("href", url);
13889 doc.getElementsByTagName("head")[0].appendChild(ss);
13893 * Refresh the rule cache if you have dynamically added stylesheets
13894 * @return {Object} An object (hash) of rules indexed by selector
13896 refreshCache : function(){
13897 return this.getRules(true);
13901 cacheStyleSheet : function(stylesheet){
13905 try{// try catch for cross domain access issue
13906 var ssRules = stylesheet.cssRules || stylesheet.rules;
13907 for(var j = ssRules.length-1; j >= 0; --j){
13908 rules[ssRules[j].selectorText] = ssRules[j];
13914 * Gets all css rules for the document
13915 * @param {Boolean} refreshCache true to refresh the internal cache
13916 * @return {Object} An object (hash) of rules indexed by selector
13918 getRules : function(refreshCache){
13919 if(rules == null || refreshCache){
13921 var ds = doc.styleSheets;
13922 for(var i =0, len = ds.length; i < len; i++){
13924 this.cacheStyleSheet(ds[i]);
13932 * Gets an an individual CSS rule by selector(s)
13933 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13934 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13935 * @return {CSSRule} The CSS rule or null if one is not found
13937 getRule : function(selector, refreshCache){
13938 var rs = this.getRules(refreshCache);
13939 if(!(selector instanceof Array)){
13940 return rs[selector];
13942 for(var i = 0; i < selector.length; i++){
13943 if(rs[selector[i]]){
13944 return rs[selector[i]];
13952 * Updates a rule property
13953 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13954 * @param {String} property The css property
13955 * @param {String} value The new value for the property
13956 * @return {Boolean} true If a rule was found and updated
13958 updateRule : function(selector, property, value){
13959 if(!(selector instanceof Array)){
13960 var rule = this.getRule(selector);
13962 rule.style[property.replace(camelRe, camelFn)] = value;
13966 for(var i = 0; i < selector.length; i++){
13967 if(this.updateRule(selector[i], property, value)){
13977 * Ext JS Library 1.1.1
13978 * Copyright(c) 2006-2007, Ext JS, LLC.
13980 * Originally Released Under LGPL - original licence link has changed is not relivant.
13983 * <script type="text/javascript">
13989 * @class Roo.util.ClickRepeater
13990 * @extends Roo.util.Observable
13992 * A wrapper class which can be applied to any element. Fires a "click" event while the
13993 * mouse is pressed. The interval between firings may be specified in the config but
13994 * defaults to 10 milliseconds.
13996 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13998 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13999 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14000 * Similar to an autorepeat key delay.
14001 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14002 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14003 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14004 * "interval" and "delay" are ignored. "immediate" is honored.
14005 * @cfg {Boolean} preventDefault True to prevent the default click event
14006 * @cfg {Boolean} stopDefault True to stop the default click event
14009 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14010 * 2007-02-02 jvs Renamed to ClickRepeater
14011 * 2007-02-03 jvs Modifications for FF Mac and Safari
14014 * @param {String/HTMLElement/Element} el The element to listen on
14015 * @param {Object} config
14017 Roo.util.ClickRepeater = function(el, config)
14019 this.el = Roo.get(el);
14020 this.el.unselectable();
14022 Roo.apply(this, config);
14027 * Fires when the mouse button is depressed.
14028 * @param {Roo.util.ClickRepeater} this
14030 "mousedown" : true,
14033 * Fires on a specified interval during the time the element is pressed.
14034 * @param {Roo.util.ClickRepeater} this
14039 * Fires when the mouse key is released.
14040 * @param {Roo.util.ClickRepeater} this
14045 this.el.on("mousedown", this.handleMouseDown, this);
14046 if(this.preventDefault || this.stopDefault){
14047 this.el.on("click", function(e){
14048 if(this.preventDefault){
14049 e.preventDefault();
14051 if(this.stopDefault){
14057 // allow inline handler
14059 this.on("click", this.handler, this.scope || this);
14062 Roo.util.ClickRepeater.superclass.constructor.call(this);
14065 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14068 preventDefault : true,
14069 stopDefault : false,
14073 handleMouseDown : function(){
14074 clearTimeout(this.timer);
14076 if(this.pressClass){
14077 this.el.addClass(this.pressClass);
14079 this.mousedownTime = new Date();
14081 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14082 this.el.on("mouseout", this.handleMouseOut, this);
14084 this.fireEvent("mousedown", this);
14085 this.fireEvent("click", this);
14087 this.timer = this.click.defer(this.delay || this.interval, this);
14091 click : function(){
14092 this.fireEvent("click", this);
14093 this.timer = this.click.defer(this.getInterval(), this);
14097 getInterval: function(){
14098 if(!this.accelerate){
14099 return this.interval;
14101 var pressTime = this.mousedownTime.getElapsed();
14102 if(pressTime < 500){
14104 }else if(pressTime < 1700){
14106 }else if(pressTime < 2600){
14108 }else if(pressTime < 3500){
14110 }else if(pressTime < 4400){
14112 }else if(pressTime < 5300){
14114 }else if(pressTime < 6200){
14122 handleMouseOut : function(){
14123 clearTimeout(this.timer);
14124 if(this.pressClass){
14125 this.el.removeClass(this.pressClass);
14127 this.el.on("mouseover", this.handleMouseReturn, this);
14131 handleMouseReturn : function(){
14132 this.el.un("mouseover", this.handleMouseReturn);
14133 if(this.pressClass){
14134 this.el.addClass(this.pressClass);
14140 handleMouseUp : function(){
14141 clearTimeout(this.timer);
14142 this.el.un("mouseover", this.handleMouseReturn);
14143 this.el.un("mouseout", this.handleMouseOut);
14144 Roo.get(document).un("mouseup", this.handleMouseUp);
14145 this.el.removeClass(this.pressClass);
14146 this.fireEvent("mouseup", this);
14150 * Ext JS Library 1.1.1
14151 * Copyright(c) 2006-2007, Ext JS, LLC.
14153 * Originally Released Under LGPL - original licence link has changed is not relivant.
14156 * <script type="text/javascript">
14161 * @class Roo.KeyNav
14162 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14163 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14164 * way to implement custom navigation schemes for any UI component.</p>
14165 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14166 * pageUp, pageDown, del, home, end. Usage:</p>
14168 var nav = new Roo.KeyNav("my-element", {
14169 "left" : function(e){
14170 this.moveLeft(e.ctrlKey);
14172 "right" : function(e){
14173 this.moveRight(e.ctrlKey);
14175 "enter" : function(e){
14182 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14183 * @param {Object} config The config
14185 Roo.KeyNav = function(el, config){
14186 this.el = Roo.get(el);
14187 Roo.apply(this, config);
14188 if(!this.disabled){
14189 this.disabled = true;
14194 Roo.KeyNav.prototype = {
14196 * @cfg {Boolean} disabled
14197 * True to disable this KeyNav instance (defaults to false)
14201 * @cfg {String} defaultEventAction
14202 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14203 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14204 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14206 defaultEventAction: "stopEvent",
14208 * @cfg {Boolean} forceKeyDown
14209 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14210 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14211 * handle keydown instead of keypress.
14213 forceKeyDown : false,
14216 prepareEvent : function(e){
14217 var k = e.getKey();
14218 var h = this.keyToHandler[k];
14219 //if(h && this[h]){
14220 // e.stopPropagation();
14222 if(Roo.isSafari && h && k >= 37 && k <= 40){
14228 relay : function(e){
14229 var k = e.getKey();
14230 var h = this.keyToHandler[k];
14232 if(this.doRelay(e, this[h], h) !== true){
14233 e[this.defaultEventAction]();
14239 doRelay : function(e, h, hname){
14240 return h.call(this.scope || this, e);
14243 // possible handlers
14257 // quick lookup hash
14274 * Enable this KeyNav
14276 enable: function(){
14278 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14279 // the EventObject will normalize Safari automatically
14280 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14281 this.el.on("keydown", this.relay, this);
14283 this.el.on("keydown", this.prepareEvent, this);
14284 this.el.on("keypress", this.relay, this);
14286 this.disabled = false;
14291 * Disable this KeyNav
14293 disable: function(){
14294 if(!this.disabled){
14295 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14296 this.el.un("keydown", this.relay);
14298 this.el.un("keydown", this.prepareEvent);
14299 this.el.un("keypress", this.relay);
14301 this.disabled = true;
14306 * Ext JS Library 1.1.1
14307 * Copyright(c) 2006-2007, Ext JS, LLC.
14309 * Originally Released Under LGPL - original licence link has changed is not relivant.
14312 * <script type="text/javascript">
14317 * @class Roo.KeyMap
14318 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14319 * The constructor accepts the same config object as defined by {@link #addBinding}.
14320 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14321 * combination it will call the function with this signature (if the match is a multi-key
14322 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14323 * A KeyMap can also handle a string representation of keys.<br />
14326 // map one key by key code
14327 var map = new Roo.KeyMap("my-element", {
14328 key: 13, // or Roo.EventObject.ENTER
14333 // map multiple keys to one action by string
14334 var map = new Roo.KeyMap("my-element", {
14340 // map multiple keys to multiple actions by strings and array of codes
14341 var map = new Roo.KeyMap("my-element", [
14344 fn: function(){ alert("Return was pressed"); }
14347 fn: function(){ alert('a, b or c was pressed'); }
14352 fn: function(){ alert('Control + shift + tab was pressed.'); }
14356 * <b>Note: A KeyMap starts enabled</b>
14358 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14359 * @param {Object} config The config (see {@link #addBinding})
14360 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14362 Roo.KeyMap = function(el, config, eventName){
14363 this.el = Roo.get(el);
14364 this.eventName = eventName || "keydown";
14365 this.bindings = [];
14367 this.addBinding(config);
14372 Roo.KeyMap.prototype = {
14374 * True to stop the event from bubbling and prevent the default browser action if the
14375 * key was handled by the KeyMap (defaults to false)
14381 * Add a new binding to this KeyMap. The following config object properties are supported:
14383 Property Type Description
14384 ---------- --------------- ----------------------------------------------------------------------
14385 key String/Array A single keycode or an array of keycodes to handle
14386 shift Boolean True to handle key only when shift is pressed (defaults to false)
14387 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14388 alt Boolean True to handle key only when alt is pressed (defaults to false)
14389 fn Function The function to call when KeyMap finds the expected key combination
14390 scope Object The scope of the callback function
14396 var map = new Roo.KeyMap(document, {
14397 key: Roo.EventObject.ENTER,
14402 //Add a new binding to the existing KeyMap later
14410 * @param {Object/Array} config A single KeyMap config or an array of configs
14412 addBinding : function(config){
14413 if(config instanceof Array){
14414 for(var i = 0, len = config.length; i < len; i++){
14415 this.addBinding(config[i]);
14419 var keyCode = config.key,
14420 shift = config.shift,
14421 ctrl = config.ctrl,
14424 scope = config.scope;
14425 if(typeof keyCode == "string"){
14427 var keyString = keyCode.toUpperCase();
14428 for(var j = 0, len = keyString.length; j < len; j++){
14429 ks.push(keyString.charCodeAt(j));
14433 var keyArray = keyCode instanceof Array;
14434 var handler = function(e){
14435 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14436 var k = e.getKey();
14438 for(var i = 0, len = keyCode.length; i < len; i++){
14439 if(keyCode[i] == k){
14440 if(this.stopEvent){
14443 fn.call(scope || window, k, e);
14449 if(this.stopEvent){
14452 fn.call(scope || window, k, e);
14457 this.bindings.push(handler);
14461 * Shorthand for adding a single key listener
14462 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14463 * following options:
14464 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14465 * @param {Function} fn The function to call
14466 * @param {Object} scope (optional) The scope of the function
14468 on : function(key, fn, scope){
14469 var keyCode, shift, ctrl, alt;
14470 if(typeof key == "object" && !(key instanceof Array)){
14489 handleKeyDown : function(e){
14490 if(this.enabled){ //just in case
14491 var b = this.bindings;
14492 for(var i = 0, len = b.length; i < len; i++){
14493 b[i].call(this, e);
14499 * Returns true if this KeyMap is enabled
14500 * @return {Boolean}
14502 isEnabled : function(){
14503 return this.enabled;
14507 * Enables this KeyMap
14509 enable: function(){
14511 this.el.on(this.eventName, this.handleKeyDown, this);
14512 this.enabled = true;
14517 * Disable this KeyMap
14519 disable: function(){
14521 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14522 this.enabled = false;
14527 * Ext JS Library 1.1.1
14528 * Copyright(c) 2006-2007, Ext JS, LLC.
14530 * Originally Released Under LGPL - original licence link has changed is not relivant.
14533 * <script type="text/javascript">
14538 * @class Roo.util.TextMetrics
14539 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14540 * wide, in pixels, a given block of text will be.
14543 Roo.util.TextMetrics = function(){
14547 * Measures the size of the specified text
14548 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14549 * that can affect the size of the rendered text
14550 * @param {String} text The text to measure
14551 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14552 * in order to accurately measure the text height
14553 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14555 measure : function(el, text, fixedWidth){
14557 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14560 shared.setFixedWidth(fixedWidth || 'auto');
14561 return shared.getSize(text);
14565 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14566 * the overhead of multiple calls to initialize the style properties on each measurement.
14567 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14568 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14569 * in order to accurately measure the text height
14570 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14572 createInstance : function(el, fixedWidth){
14573 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14580 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14581 var ml = new Roo.Element(document.createElement('div'));
14582 document.body.appendChild(ml.dom);
14583 ml.position('absolute');
14584 ml.setLeftTop(-1000, -1000);
14588 ml.setWidth(fixedWidth);
14593 * Returns the size of the specified text based on the internal element's style and width properties
14594 * @memberOf Roo.util.TextMetrics.Instance#
14595 * @param {String} text The text to measure
14596 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14598 getSize : function(text){
14600 var s = ml.getSize();
14606 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14607 * that can affect the size of the rendered text
14608 * @memberOf Roo.util.TextMetrics.Instance#
14609 * @param {String/HTMLElement} el The element, dom node or id
14611 bind : function(el){
14613 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14618 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14619 * to set a fixed width in order to accurately measure the text height.
14620 * @memberOf Roo.util.TextMetrics.Instance#
14621 * @param {Number} width The width to set on the element
14623 setFixedWidth : function(width){
14624 ml.setWidth(width);
14628 * Returns the measured width of the specified text
14629 * @memberOf Roo.util.TextMetrics.Instance#
14630 * @param {String} text The text to measure
14631 * @return {Number} width The width in pixels
14633 getWidth : function(text){
14634 ml.dom.style.width = 'auto';
14635 return this.getSize(text).width;
14639 * Returns the measured height of the specified text. For multiline text, be sure to call
14640 * {@link #setFixedWidth} if necessary.
14641 * @memberOf Roo.util.TextMetrics.Instance#
14642 * @param {String} text The text to measure
14643 * @return {Number} height The height in pixels
14645 getHeight : function(text){
14646 return this.getSize(text).height;
14650 instance.bind(bindTo);
14655 // backwards compat
14656 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14658 * Ext JS Library 1.1.1
14659 * Copyright(c) 2006-2007, Ext JS, LLC.
14661 * Originally Released Under LGPL - original licence link has changed is not relivant.
14664 * <script type="text/javascript">
14668 * @class Roo.state.Provider
14669 * Abstract base class for state provider implementations. This class provides methods
14670 * for encoding and decoding <b>typed</b> variables including dates and defines the
14671 * Provider interface.
14673 Roo.state.Provider = function(){
14675 * @event statechange
14676 * Fires when a state change occurs.
14677 * @param {Provider} this This state provider
14678 * @param {String} key The state key which was changed
14679 * @param {String} value The encoded value for the state
14682 "statechange": true
14685 Roo.state.Provider.superclass.constructor.call(this);
14687 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14689 * Returns the current value for a key
14690 * @param {String} name The key name
14691 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14692 * @return {Mixed} The state data
14694 get : function(name, defaultValue){
14695 return typeof this.state[name] == "undefined" ?
14696 defaultValue : this.state[name];
14700 * Clears a value from the state
14701 * @param {String} name The key name
14703 clear : function(name){
14704 delete this.state[name];
14705 this.fireEvent("statechange", this, name, null);
14709 * Sets the value for a key
14710 * @param {String} name The key name
14711 * @param {Mixed} value The value to set
14713 set : function(name, value){
14714 this.state[name] = value;
14715 this.fireEvent("statechange", this, name, value);
14719 * Decodes a string previously encoded with {@link #encodeValue}.
14720 * @param {String} value The value to decode
14721 * @return {Mixed} The decoded value
14723 decodeValue : function(cookie){
14724 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14725 var matches = re.exec(unescape(cookie));
14726 if(!matches || !matches[1]) return; // non state cookie
14727 var type = matches[1];
14728 var v = matches[2];
14731 return parseFloat(v);
14733 return new Date(Date.parse(v));
14738 var values = v.split("^");
14739 for(var i = 0, len = values.length; i < len; i++){
14740 all.push(this.decodeValue(values[i]));
14745 var values = v.split("^");
14746 for(var i = 0, len = values.length; i < len; i++){
14747 var kv = values[i].split("=");
14748 all[kv[0]] = this.decodeValue(kv[1]);
14757 * Encodes a value including type information. Decode with {@link #decodeValue}.
14758 * @param {Mixed} value The value to encode
14759 * @return {String} The encoded value
14761 encodeValue : function(v){
14763 if(typeof v == "number"){
14765 }else if(typeof v == "boolean"){
14766 enc = "b:" + (v ? "1" : "0");
14767 }else if(v instanceof Date){
14768 enc = "d:" + v.toGMTString();
14769 }else if(v instanceof Array){
14771 for(var i = 0, len = v.length; i < len; i++){
14772 flat += this.encodeValue(v[i]);
14773 if(i != len-1) flat += "^";
14776 }else if(typeof v == "object"){
14779 if(typeof v[key] != "function"){
14780 flat += key + "=" + this.encodeValue(v[key]) + "^";
14783 enc = "o:" + flat.substring(0, flat.length-1);
14787 return escape(enc);
14793 * Ext JS Library 1.1.1
14794 * Copyright(c) 2006-2007, Ext JS, LLC.
14796 * Originally Released Under LGPL - original licence link has changed is not relivant.
14799 * <script type="text/javascript">
14802 * @class Roo.state.Manager
14803 * This is the global state manager. By default all components that are "state aware" check this class
14804 * for state information if you don't pass them a custom state provider. In order for this class
14805 * to be useful, it must be initialized with a provider when your application initializes.
14807 // in your initialization function
14809 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14811 // supposed you have a {@link Roo.BorderLayout}
14812 var layout = new Roo.BorderLayout(...);
14813 layout.restoreState();
14814 // or a {Roo.BasicDialog}
14815 var dialog = new Roo.BasicDialog(...);
14816 dialog.restoreState();
14820 Roo.state.Manager = function(){
14821 var provider = new Roo.state.Provider();
14825 * Configures the default state provider for your application
14826 * @param {Provider} stateProvider The state provider to set
14828 setProvider : function(stateProvider){
14829 provider = stateProvider;
14833 * Returns the current value for a key
14834 * @param {String} name The key name
14835 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14836 * @return {Mixed} The state data
14838 get : function(key, defaultValue){
14839 return provider.get(key, defaultValue);
14843 * Sets the value for a key
14844 * @param {String} name The key name
14845 * @param {Mixed} value The state data
14847 set : function(key, value){
14848 provider.set(key, value);
14852 * Clears a value from the state
14853 * @param {String} name The key name
14855 clear : function(key){
14856 provider.clear(key);
14860 * Gets the currently configured state provider
14861 * @return {Provider} The state provider
14863 getProvider : function(){
14870 * Ext JS Library 1.1.1
14871 * Copyright(c) 2006-2007, Ext JS, LLC.
14873 * Originally Released Under LGPL - original licence link has changed is not relivant.
14876 * <script type="text/javascript">
14879 * @class Roo.state.CookieProvider
14880 * @extends Roo.state.Provider
14881 * The default Provider implementation which saves state via cookies.
14884 var cp = new Roo.state.CookieProvider({
14886 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14887 domain: "roojs.com"
14889 Roo.state.Manager.setProvider(cp);
14891 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14892 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14893 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14894 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14895 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14896 * domain the page is running on including the 'www' like 'www.roojs.com')
14897 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14899 * Create a new CookieProvider
14900 * @param {Object} config The configuration object
14902 Roo.state.CookieProvider = function(config){
14903 Roo.state.CookieProvider.superclass.constructor.call(this);
14905 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14906 this.domain = null;
14907 this.secure = false;
14908 Roo.apply(this, config);
14909 this.state = this.readCookies();
14912 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14914 set : function(name, value){
14915 if(typeof value == "undefined" || value === null){
14919 this.setCookie(name, value);
14920 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14924 clear : function(name){
14925 this.clearCookie(name);
14926 Roo.state.CookieProvider.superclass.clear.call(this, name);
14930 readCookies : function(){
14932 var c = document.cookie + ";";
14933 var re = /\s?(.*?)=(.*?);/g;
14935 while((matches = re.exec(c)) != null){
14936 var name = matches[1];
14937 var value = matches[2];
14938 if(name && name.substring(0,3) == "ys-"){
14939 cookies[name.substr(3)] = this.decodeValue(value);
14946 setCookie : function(name, value){
14947 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14948 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14949 ((this.path == null) ? "" : ("; path=" + this.path)) +
14950 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14951 ((this.secure == true) ? "; secure" : "");
14955 clearCookie : function(name){
14956 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14957 ((this.path == null) ? "" : ("; path=" + this.path)) +
14958 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14959 ((this.secure == true) ? "; secure" : "");
14963 * Ext JS Library 1.1.1
14964 * Copyright(c) 2006-2007, Ext JS, LLC.
14966 * Originally Released Under LGPL - original licence link has changed is not relivant.
14969 * <script type="text/javascript">
14974 * @class Roo.ComponentMgr
14975 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14978 Roo.ComponentMgr = function(){
14979 var all = new Roo.util.MixedCollection();
14983 * Registers a component.
14984 * @param {Roo.Component} c The component
14986 register : function(c){
14991 * Unregisters a component.
14992 * @param {Roo.Component} c The component
14994 unregister : function(c){
14999 * Returns a component by id
15000 * @param {String} id The component id
15002 get : function(id){
15003 return all.get(id);
15007 * Registers a function that will be called when a specified component is added to ComponentMgr
15008 * @param {String} id The component id
15009 * @param {Funtction} fn The callback function
15010 * @param {Object} scope The scope of the callback
15012 onAvailable : function(id, fn, scope){
15013 all.on("add", function(index, o){
15015 fn.call(scope || o, o);
15016 all.un("add", fn, scope);
15023 * Ext JS Library 1.1.1
15024 * Copyright(c) 2006-2007, Ext JS, LLC.
15026 * Originally Released Under LGPL - original licence link has changed is not relivant.
15029 * <script type="text/javascript">
15033 * @class Roo.Component
15034 * @extends Roo.util.Observable
15035 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15036 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15037 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15038 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15039 * All visual components (widgets) that require rendering into a layout should subclass Component.
15041 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15042 * 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
15043 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15045 Roo.Component = function(config){
15046 config = config || {};
15047 if(config.tagName || config.dom || typeof config == "string"){ // element object
15048 config = {el: config, id: config.id || config};
15050 this.initialConfig = config;
15052 Roo.apply(this, config);
15056 * Fires after the component is disabled.
15057 * @param {Roo.Component} this
15062 * Fires after the component is enabled.
15063 * @param {Roo.Component} this
15067 * @event beforeshow
15068 * Fires before the component is shown. Return false to stop the show.
15069 * @param {Roo.Component} this
15074 * Fires after the component is shown.
15075 * @param {Roo.Component} this
15079 * @event beforehide
15080 * Fires before the component is hidden. Return false to stop the hide.
15081 * @param {Roo.Component} this
15086 * Fires after the component is hidden.
15087 * @param {Roo.Component} this
15091 * @event beforerender
15092 * Fires before the component is rendered. Return false to stop the render.
15093 * @param {Roo.Component} this
15095 beforerender : true,
15098 * Fires after the component is rendered.
15099 * @param {Roo.Component} this
15103 * @event beforedestroy
15104 * Fires before the component is destroyed. Return false to stop the destroy.
15105 * @param {Roo.Component} this
15107 beforedestroy : true,
15110 * Fires after the component is destroyed.
15111 * @param {Roo.Component} this
15116 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15118 Roo.ComponentMgr.register(this);
15119 Roo.Component.superclass.constructor.call(this);
15120 this.initComponent();
15121 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15122 this.render(this.renderTo);
15123 delete this.renderTo;
15128 Roo.Component.AUTO_ID = 1000;
15130 Roo.extend(Roo.Component, Roo.util.Observable, {
15132 * @scope Roo.Component.prototype
15134 * true if this component is hidden. Read-only.
15139 * true if this component is disabled. Read-only.
15144 * true if this component has been rendered. Read-only.
15148 /** @cfg {String} disableClass
15149 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15151 disabledClass : "x-item-disabled",
15152 /** @cfg {Boolean} allowDomMove
15153 * Whether the component can move the Dom node when rendering (defaults to true).
15155 allowDomMove : true,
15156 /** @cfg {String} hideMode
15157 * How this component should hidden. Supported values are
15158 * "visibility" (css visibility), "offsets" (negative offset position) and
15159 * "display" (css display) - defaults to "display".
15161 hideMode: 'display',
15164 ctype : "Roo.Component",
15167 * @cfg {String} actionMode
15168 * which property holds the element that used for hide() / show() / disable() / enable()
15174 getActionEl : function(){
15175 return this[this.actionMode];
15178 initComponent : Roo.emptyFn,
15180 * If this is a lazy rendering component, render it to its container element.
15181 * @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.
15183 render : function(container, position){
15184 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15185 if(!container && this.el){
15186 this.el = Roo.get(this.el);
15187 container = this.el.dom.parentNode;
15188 this.allowDomMove = false;
15190 this.container = Roo.get(container);
15191 this.rendered = true;
15192 if(position !== undefined){
15193 if(typeof position == 'number'){
15194 position = this.container.dom.childNodes[position];
15196 position = Roo.getDom(position);
15199 this.onRender(this.container, position || null);
15201 this.el.addClass(this.cls);
15205 this.el.applyStyles(this.style);
15208 this.fireEvent("render", this);
15209 this.afterRender(this.container);
15221 // default function is not really useful
15222 onRender : function(ct, position){
15224 this.el = Roo.get(this.el);
15225 if(this.allowDomMove !== false){
15226 ct.dom.insertBefore(this.el.dom, position);
15232 getAutoCreate : function(){
15233 var cfg = typeof this.autoCreate == "object" ?
15234 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15235 if(this.id && !cfg.id){
15242 afterRender : Roo.emptyFn,
15245 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15246 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15248 destroy : function(){
15249 if(this.fireEvent("beforedestroy", this) !== false){
15250 this.purgeListeners();
15251 this.beforeDestroy();
15253 this.el.removeAllListeners();
15255 if(this.actionMode == "container"){
15256 this.container.remove();
15260 Roo.ComponentMgr.unregister(this);
15261 this.fireEvent("destroy", this);
15266 beforeDestroy : function(){
15271 onDestroy : function(){
15276 * Returns the underlying {@link Roo.Element}.
15277 * @return {Roo.Element} The element
15279 getEl : function(){
15284 * Returns the id of this component.
15287 getId : function(){
15292 * Try to focus this component.
15293 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15294 * @return {Roo.Component} this
15296 focus : function(selectText){
15299 if(selectText === true){
15300 this.el.dom.select();
15315 * Disable this component.
15316 * @return {Roo.Component} this
15318 disable : function(){
15322 this.disabled = true;
15323 this.fireEvent("disable", this);
15328 onDisable : function(){
15329 this.getActionEl().addClass(this.disabledClass);
15330 this.el.dom.disabled = true;
15334 * Enable this component.
15335 * @return {Roo.Component} this
15337 enable : function(){
15341 this.disabled = false;
15342 this.fireEvent("enable", this);
15347 onEnable : function(){
15348 this.getActionEl().removeClass(this.disabledClass);
15349 this.el.dom.disabled = false;
15353 * Convenience function for setting disabled/enabled by boolean.
15354 * @param {Boolean} disabled
15356 setDisabled : function(disabled){
15357 this[disabled ? "disable" : "enable"]();
15361 * Show this component.
15362 * @return {Roo.Component} this
15365 if(this.fireEvent("beforeshow", this) !== false){
15366 this.hidden = false;
15370 this.fireEvent("show", this);
15376 onShow : function(){
15377 var ae = this.getActionEl();
15378 if(this.hideMode == 'visibility'){
15379 ae.dom.style.visibility = "visible";
15380 }else if(this.hideMode == 'offsets'){
15381 ae.removeClass('x-hidden');
15383 ae.dom.style.display = "";
15388 * Hide this component.
15389 * @return {Roo.Component} this
15392 if(this.fireEvent("beforehide", this) !== false){
15393 this.hidden = true;
15397 this.fireEvent("hide", this);
15403 onHide : function(){
15404 var ae = this.getActionEl();
15405 if(this.hideMode == 'visibility'){
15406 ae.dom.style.visibility = "hidden";
15407 }else if(this.hideMode == 'offsets'){
15408 ae.addClass('x-hidden');
15410 ae.dom.style.display = "none";
15415 * Convenience function to hide or show this component by boolean.
15416 * @param {Boolean} visible True to show, false to hide
15417 * @return {Roo.Component} this
15419 setVisible: function(visible){
15429 * Returns true if this component is visible.
15431 isVisible : function(){
15432 return this.getActionEl().isVisible();
15435 cloneConfig : function(overrides){
15436 overrides = overrides || {};
15437 var id = overrides.id || Roo.id();
15438 var cfg = Roo.applyIf(overrides, this.initialConfig);
15439 cfg.id = id; // prevent dup id
15440 return new this.constructor(cfg);
15444 * Ext JS Library 1.1.1
15445 * Copyright(c) 2006-2007, Ext JS, LLC.
15447 * Originally Released Under LGPL - original licence link has changed is not relivant.
15450 * <script type="text/javascript">
15454 * @class Roo.BoxComponent
15455 * @extends Roo.Component
15456 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15457 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15458 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15459 * layout containers.
15461 * @param {Roo.Element/String/Object} config The configuration options.
15463 Roo.BoxComponent = function(config){
15464 Roo.Component.call(this, config);
15468 * Fires after the component is resized.
15469 * @param {Roo.Component} this
15470 * @param {Number} adjWidth The box-adjusted width that was set
15471 * @param {Number} adjHeight The box-adjusted height that was set
15472 * @param {Number} rawWidth The width that was originally specified
15473 * @param {Number} rawHeight The height that was originally specified
15478 * Fires after the component is moved.
15479 * @param {Roo.Component} this
15480 * @param {Number} x The new x position
15481 * @param {Number} y The new y position
15487 Roo.extend(Roo.BoxComponent, Roo.Component, {
15488 // private, set in afterRender to signify that the component has been rendered
15490 // private, used to defer height settings to subclasses
15491 deferHeight: false,
15492 /** @cfg {Number} width
15493 * width (optional) size of component
15495 /** @cfg {Number} height
15496 * height (optional) size of component
15500 * Sets the width and height of the component. This method fires the resize event. This method can accept
15501 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15502 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15503 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15504 * @return {Roo.BoxComponent} this
15506 setSize : function(w, h){
15507 // support for standard size objects
15508 if(typeof w == 'object'){
15513 if(!this.boxReady){
15519 // prevent recalcs when not needed
15520 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15523 this.lastSize = {width: w, height: h};
15525 var adj = this.adjustSize(w, h);
15526 var aw = adj.width, ah = adj.height;
15527 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15528 var rz = this.getResizeEl();
15529 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15530 rz.setSize(aw, ah);
15531 }else if(!this.deferHeight && ah !== undefined){
15533 }else if(aw !== undefined){
15536 this.onResize(aw, ah, w, h);
15537 this.fireEvent('resize', this, aw, ah, w, h);
15543 * Gets the current size of the component's underlying element.
15544 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15546 getSize : function(){
15547 return this.el.getSize();
15551 * Gets the current XY position of the component's underlying element.
15552 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15553 * @return {Array} The XY position of the element (e.g., [100, 200])
15555 getPosition : function(local){
15556 if(local === true){
15557 return [this.el.getLeft(true), this.el.getTop(true)];
15559 return this.xy || this.el.getXY();
15563 * Gets the current box measurements of the component's underlying element.
15564 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15565 * @returns {Object} box An object in the format {x, y, width, height}
15567 getBox : function(local){
15568 var s = this.el.getSize();
15570 s.x = this.el.getLeft(true);
15571 s.y = this.el.getTop(true);
15573 var xy = this.xy || this.el.getXY();
15581 * Sets the current box measurements of the component's underlying element.
15582 * @param {Object} box An object in the format {x, y, width, height}
15583 * @returns {Roo.BoxComponent} this
15585 updateBox : function(box){
15586 this.setSize(box.width, box.height);
15587 this.setPagePosition(box.x, box.y);
15592 getResizeEl : function(){
15593 return this.resizeEl || this.el;
15597 getPositionEl : function(){
15598 return this.positionEl || this.el;
15602 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15603 * This method fires the move event.
15604 * @param {Number} left The new left
15605 * @param {Number} top The new top
15606 * @returns {Roo.BoxComponent} this
15608 setPosition : function(x, y){
15611 if(!this.boxReady){
15614 var adj = this.adjustPosition(x, y);
15615 var ax = adj.x, ay = adj.y;
15617 var el = this.getPositionEl();
15618 if(ax !== undefined || ay !== undefined){
15619 if(ax !== undefined && ay !== undefined){
15620 el.setLeftTop(ax, ay);
15621 }else if(ax !== undefined){
15623 }else if(ay !== undefined){
15626 this.onPosition(ax, ay);
15627 this.fireEvent('move', this, ax, ay);
15633 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15634 * This method fires the move event.
15635 * @param {Number} x The new x position
15636 * @param {Number} y The new y position
15637 * @returns {Roo.BoxComponent} this
15639 setPagePosition : function(x, y){
15642 if(!this.boxReady){
15645 if(x === undefined || y === undefined){ // cannot translate undefined points
15648 var p = this.el.translatePoints(x, y);
15649 this.setPosition(p.left, p.top);
15654 onRender : function(ct, position){
15655 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15657 this.resizeEl = Roo.get(this.resizeEl);
15659 if(this.positionEl){
15660 this.positionEl = Roo.get(this.positionEl);
15665 afterRender : function(){
15666 Roo.BoxComponent.superclass.afterRender.call(this);
15667 this.boxReady = true;
15668 this.setSize(this.width, this.height);
15669 if(this.x || this.y){
15670 this.setPosition(this.x, this.y);
15672 if(this.pageX || this.pageY){
15673 this.setPagePosition(this.pageX, this.pageY);
15678 * Force the component's size to recalculate based on the underlying element's current height and width.
15679 * @returns {Roo.BoxComponent} this
15681 syncSize : function(){
15682 delete this.lastSize;
15683 this.setSize(this.el.getWidth(), this.el.getHeight());
15688 * Called after the component is resized, this method is empty by default but can be implemented by any
15689 * subclass that needs to perform custom logic after a resize occurs.
15690 * @param {Number} adjWidth The box-adjusted width that was set
15691 * @param {Number} adjHeight The box-adjusted height that was set
15692 * @param {Number} rawWidth The width that was originally specified
15693 * @param {Number} rawHeight The height that was originally specified
15695 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15700 * Called after the component is moved, this method is empty by default but can be implemented by any
15701 * subclass that needs to perform custom logic after a move occurs.
15702 * @param {Number} x The new x position
15703 * @param {Number} y The new y position
15705 onPosition : function(x, y){
15710 adjustSize : function(w, h){
15711 if(this.autoWidth){
15714 if(this.autoHeight){
15717 return {width : w, height: h};
15721 adjustPosition : function(x, y){
15722 return {x : x, y: y};
15725 * Original code for Roojs - LGPL
15726 * <script type="text/javascript">
15730 * @class Roo.XComponent
15731 * A delayed Element creator...
15732 * Or a way to group chunks of interface together.
15734 * Mypart.xyx = new Roo.XComponent({
15736 parent : 'Mypart.xyz', // empty == document.element.!!
15740 disabled : function() {}
15742 tree : function() { // return an tree of xtype declared components
15746 xtype : 'NestedLayoutPanel',
15753 * It can be used to build a big heiracy, with parent etc.
15754 * or you can just use this to render a single compoent to a dom element
15755 * MYPART.render(Roo.Element | String(id) | dom_element )
15757 * @extends Roo.util.Observable
15759 * @param cfg {Object} configuration of component
15762 Roo.XComponent = function(cfg) {
15763 Roo.apply(this, cfg);
15767 * Fires when this the componnt is built
15768 * @param {Roo.XComponent} c the component
15773 this.region = this.region || 'center'; // default..
15774 Roo.XComponent.register(this);
15775 this.modules = false;
15776 this.el = false; // where the layout goes..
15780 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15783 * The created element (with Roo.factory())
15784 * @type {Roo.Layout}
15790 * for BC - use el in new code
15791 * @type {Roo.Layout}
15797 * for BC - use el in new code
15798 * @type {Roo.Layout}
15803 * @cfg {Function|boolean} disabled
15804 * If this module is disabled by some rule, return true from the funtion
15809 * @cfg {String} parent
15810 * Name of parent element which it get xtype added to..
15815 * @cfg {String} order
15816 * Used to set the order in which elements are created (usefull for multiple tabs)
15821 * @cfg {String} name
15822 * String to display while loading.
15826 * @cfg {String} region
15827 * Region to render component to (defaults to center)
15832 * @cfg {Array} items
15833 * A single item array - the first element is the root of the tree..
15834 * It's done this way to stay compatible with the Xtype system...
15840 * The method that retuns the tree of parts that make up this compoennt
15847 * render element to dom or tree
15848 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15851 render : function(el)
15855 var hp = this.parent ? 1 : 0;
15857 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15858 // if parent is a '#.....' string, then let's use that..
15859 var ename = this.parent.substr(1)
15860 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
15861 el = Roo.get(ename);
15862 if (!el && !this.parent) {
15863 Roo.log("Warning - element can not be found :#" + ename );
15869 if (!this.parent) {
15871 el = el ? Roo.get(el) : false;
15873 // it's a top level one..
15875 el : new Roo.BorderLayout(el || document.body, {
15881 tabPosition: 'top',
15882 //resizeTabs: true,
15883 alwaysShowTabs: el && hp? false : true,
15884 hideTabs: el || !hp ? true : false,
15891 if (!this.parent.el) {
15892 // probably an old style ctor, which has been disabled.
15896 // The 'tree' method is '_tree now'
15898 var tree = this._tree ? this._tree() : this.tree();
15899 tree.region = tree.region || this.region;
15901 if (this.parent.el === true) {
15902 // bootstrap... - body..
15903 this.parent.el = Roo.factory(tree);
15906 this.el = this.parent.el.addxtype(tree);
15907 this.fireEvent('built', this);
15909 this.panel = this.el;
15910 this.layout = this.panel.layout;
15911 this.parentLayout = this.parent.layout || false;
15917 Roo.apply(Roo.XComponent, {
15919 * @property hideProgress
15920 * true to disable the building progress bar.. usefull on single page renders.
15923 hideProgress : false,
15925 * @property buildCompleted
15926 * True when the builder has completed building the interface.
15929 buildCompleted : false,
15932 * @property topModule
15933 * the upper most module - uses document.element as it's constructor.
15940 * @property modules
15941 * array of modules to be created by registration system.
15942 * @type {Array} of Roo.XComponent
15947 * @property elmodules
15948 * array of modules to be created by which use #ID
15949 * @type {Array} of Roo.XComponent
15955 * @property build_from_html
15956 * Build elements from html - used by bootstrap HTML stuff
15957 * - this is cleared after build is completed
15958 * @type {boolean} true (default false)
15961 build_from_html : false,
15964 * Register components to be built later.
15966 * This solves the following issues
15967 * - Building is not done on page load, but after an authentication process has occured.
15968 * - Interface elements are registered on page load
15969 * - Parent Interface elements may not be loaded before child, so this handles that..
15976 module : 'Pman.Tab.projectMgr',
15978 parent : 'Pman.layout',
15979 disabled : false, // or use a function..
15982 * * @param {Object} details about module
15984 register : function(obj) {
15986 Roo.XComponent.event.fireEvent('register', obj);
15987 switch(typeof(obj.disabled) ) {
15993 if ( obj.disabled() ) {
15999 if (obj.disabled) {
16005 this.modules.push(obj);
16009 * convert a string to an object..
16010 * eg. 'AAA.BBB' -> finds AAA.BBB
16014 toObject : function(str)
16016 if (!str || typeof(str) == 'object') {
16019 if (str.substring(0,1) == '#') {
16023 var ar = str.split('.');
16028 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16030 throw "Module not found : " + str;
16034 throw "Module not found : " + str;
16036 Roo.each(ar, function(e) {
16037 if (typeof(o[e]) == 'undefined') {
16038 throw "Module not found : " + str;
16049 * move modules into their correct place in the tree..
16052 preBuild : function ()
16055 Roo.each(this.modules , function (obj)
16057 Roo.XComponent.event.fireEvent('beforebuild', obj);
16059 var opar = obj.parent;
16061 obj.parent = this.toObject(opar);
16063 Roo.log("parent:toObject failed: " + e.toString());
16068 Roo.debug && Roo.log("GOT top level module");
16069 Roo.debug && Roo.log(obj);
16070 obj.modules = new Roo.util.MixedCollection(false,
16071 function(o) { return o.order + '' }
16073 this.topModule = obj;
16076 // parent is a string (usually a dom element name..)
16077 if (typeof(obj.parent) == 'string') {
16078 this.elmodules.push(obj);
16081 if (obj.parent.constructor != Roo.XComponent) {
16082 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16084 if (!obj.parent.modules) {
16085 obj.parent.modules = new Roo.util.MixedCollection(false,
16086 function(o) { return o.order + '' }
16089 if (obj.parent.disabled) {
16090 obj.disabled = true;
16092 obj.parent.modules.add(obj);
16097 * make a list of modules to build.
16098 * @return {Array} list of modules.
16101 buildOrder : function()
16104 var cmp = function(a,b) {
16105 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16107 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16108 throw "No top level modules to build";
16111 // make a flat list in order of modules to build.
16112 var mods = this.topModule ? [ this.topModule ] : [];
16115 // elmodules (is a list of DOM based modules )
16116 Roo.each(this.elmodules, function(e) {
16118 if (!this.topModule &&
16119 typeof(e.parent) == 'string' &&
16120 e.parent.substring(0,1) == '#' &&
16121 Roo.get(e.parent.substr(1))
16124 _this.topModule = e;
16130 // add modules to their parents..
16131 var addMod = function(m) {
16132 Roo.debug && Roo.log("build Order: add: " + m.name);
16135 if (m.modules && !m.disabled) {
16136 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16137 m.modules.keySort('ASC', cmp );
16138 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16140 m.modules.each(addMod);
16142 Roo.debug && Roo.log("build Order: no child modules");
16144 // not sure if this is used any more..
16146 m.finalize.name = m.name + " (clean up) ";
16147 mods.push(m.finalize);
16151 if (this.topModule && this.topModule.modules) {
16152 this.topModule.modules.keySort('ASC', cmp );
16153 this.topModule.modules.each(addMod);
16159 * Build the registered modules.
16160 * @param {Object} parent element.
16161 * @param {Function} optional method to call after module has been added.
16165 build : function(opts)
16168 if (typeof(opts) != 'undefined') {
16169 Roo.apply(this,opts);
16173 var mods = this.buildOrder();
16175 //this.allmods = mods;
16176 //Roo.debug && Roo.log(mods);
16178 if (!mods.length) { // should not happen
16179 throw "NO modules!!!";
16183 var msg = "Building Interface...";
16184 // flash it up as modal - so we store the mask!?
16185 if (!this.hideProgress && Roo.MessageBox) {
16186 Roo.MessageBox.show({ title: 'loading' });
16187 Roo.MessageBox.show({
16188 title: "Please wait...",
16197 var total = mods.length;
16200 var progressRun = function() {
16201 if (!mods.length) {
16202 Roo.debug && Roo.log('hide?');
16203 if (!this.hideProgress && Roo.MessageBox) {
16204 Roo.MessageBox.hide();
16206 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16208 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16214 var m = mods.shift();
16217 Roo.debug && Roo.log(m);
16218 // not sure if this is supported any more.. - modules that are are just function
16219 if (typeof(m) == 'function') {
16221 return progressRun.defer(10, _this);
16225 msg = "Building Interface " + (total - mods.length) +
16227 (m.name ? (' - ' + m.name) : '');
16228 Roo.debug && Roo.log(msg);
16229 if (!this.hideProgress && Roo.MessageBox) {
16230 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16234 // is the module disabled?
16235 var disabled = (typeof(m.disabled) == 'function') ?
16236 m.disabled.call(m.module.disabled) : m.disabled;
16240 return progressRun(); // we do not update the display!
16248 // it's 10 on top level, and 1 on others??? why...
16249 return progressRun.defer(10, _this);
16252 progressRun.defer(1, _this);
16266 * wrapper for event.on - aliased later..
16267 * Typically use to register a event handler for register:
16269 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16278 Roo.XComponent.event = new Roo.util.Observable({
16282 * Fires when an Component is registered,
16283 * set the disable property on the Component to stop registration.
16284 * @param {Roo.XComponent} c the component being registerd.
16289 * @event beforebuild
16290 * Fires before each Component is built
16291 * can be used to apply permissions.
16292 * @param {Roo.XComponent} c the component being registerd.
16295 'beforebuild' : true,
16297 * @event buildcomplete
16298 * Fires on the top level element when all elements have been built
16299 * @param {Roo.XComponent} the top level component.
16301 'buildcomplete' : true
16306 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16309 * Ext JS Library 1.1.1
16310 * Copyright(c) 2006-2007, Ext JS, LLC.
16312 * Originally Released Under LGPL - original licence link has changed is not relivant.
16315 * <script type="text/javascript">
16321 * These classes are derivatives of the similarly named classes in the YUI Library.
16322 * The original license:
16323 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16324 * Code licensed under the BSD License:
16325 * http://developer.yahoo.net/yui/license.txt
16330 var Event=Roo.EventManager;
16331 var Dom=Roo.lib.Dom;
16334 * @class Roo.dd.DragDrop
16335 * @extends Roo.util.Observable
16336 * Defines the interface and base operation of items that that can be
16337 * dragged or can be drop targets. It was designed to be extended, overriding
16338 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16339 * Up to three html elements can be associated with a DragDrop instance:
16341 * <li>linked element: the element that is passed into the constructor.
16342 * This is the element which defines the boundaries for interaction with
16343 * other DragDrop objects.</li>
16344 * <li>handle element(s): The drag operation only occurs if the element that
16345 * was clicked matches a handle element. By default this is the linked
16346 * element, but there are times that you will want only a portion of the
16347 * linked element to initiate the drag operation, and the setHandleElId()
16348 * method provides a way to define this.</li>
16349 * <li>drag element: this represents the element that would be moved along
16350 * with the cursor during a drag operation. By default, this is the linked
16351 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16352 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16355 * This class should not be instantiated until the onload event to ensure that
16356 * the associated elements are available.
16357 * The following would define a DragDrop obj that would interact with any
16358 * other DragDrop obj in the "group1" group:
16360 * dd = new Roo.dd.DragDrop("div1", "group1");
16362 * Since none of the event handlers have been implemented, nothing would
16363 * actually happen if you were to run the code above. Normally you would
16364 * override this class or one of the default implementations, but you can
16365 * also override the methods you want on an instance of the class...
16367 * dd.onDragDrop = function(e, id) {
16368 * alert("dd was dropped on " + id);
16372 * @param {String} id of the element that is linked to this instance
16373 * @param {String} sGroup the group of related DragDrop objects
16374 * @param {object} config an object containing configurable attributes
16375 * Valid properties for DragDrop:
16376 * padding, isTarget, maintainOffset, primaryButtonOnly
16378 Roo.dd.DragDrop = function(id, sGroup, config) {
16380 this.init(id, sGroup, config);
16385 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16388 * The id of the element associated with this object. This is what we
16389 * refer to as the "linked element" because the size and position of
16390 * this element is used to determine when the drag and drop objects have
16398 * Configuration attributes passed into the constructor
16405 * The id of the element that will be dragged. By default this is same
16406 * as the linked element , but could be changed to another element. Ex:
16408 * @property dragElId
16415 * the id of the element that initiates the drag operation. By default
16416 * this is the linked element, but could be changed to be a child of this
16417 * element. This lets us do things like only starting the drag when the
16418 * header element within the linked html element is clicked.
16419 * @property handleElId
16426 * An associative array of HTML tags that will be ignored if clicked.
16427 * @property invalidHandleTypes
16428 * @type {string: string}
16430 invalidHandleTypes: null,
16433 * An associative array of ids for elements that will be ignored if clicked
16434 * @property invalidHandleIds
16435 * @type {string: string}
16437 invalidHandleIds: null,
16440 * An indexted array of css class names for elements that will be ignored
16442 * @property invalidHandleClasses
16445 invalidHandleClasses: null,
16448 * The linked element's absolute X position at the time the drag was
16450 * @property startPageX
16457 * The linked element's absolute X position at the time the drag was
16459 * @property startPageY
16466 * The group defines a logical collection of DragDrop objects that are
16467 * related. Instances only get events when interacting with other
16468 * DragDrop object in the same group. This lets us define multiple
16469 * groups using a single DragDrop subclass if we want.
16471 * @type {string: string}
16476 * Individual drag/drop instances can be locked. This will prevent
16477 * onmousedown start drag.
16485 * Lock this instance
16488 lock: function() { this.locked = true; },
16491 * Unlock this instace
16494 unlock: function() { this.locked = false; },
16497 * By default, all insances can be a drop target. This can be disabled by
16498 * setting isTarget to false.
16505 * The padding configured for this drag and drop object for calculating
16506 * the drop zone intersection with this object.
16513 * Cached reference to the linked element
16514 * @property _domRef
16520 * Internal typeof flag
16521 * @property __ygDragDrop
16524 __ygDragDrop: true,
16527 * Set to true when horizontal contraints are applied
16528 * @property constrainX
16535 * Set to true when vertical contraints are applied
16536 * @property constrainY
16543 * The left constraint
16551 * The right constraint
16559 * The up constraint
16568 * The down constraint
16576 * Maintain offsets when we resetconstraints. Set to true when you want
16577 * the position of the element relative to its parent to stay the same
16578 * when the page changes
16580 * @property maintainOffset
16583 maintainOffset: false,
16586 * Array of pixel locations the element will snap to if we specified a
16587 * horizontal graduation/interval. This array is generated automatically
16588 * when you define a tick interval.
16595 * Array of pixel locations the element will snap to if we specified a
16596 * vertical graduation/interval. This array is generated automatically
16597 * when you define a tick interval.
16604 * By default the drag and drop instance will only respond to the primary
16605 * button click (left button for a right-handed mouse). Set to true to
16606 * allow drag and drop to start with any mouse click that is propogated
16608 * @property primaryButtonOnly
16611 primaryButtonOnly: true,
16614 * The availabe property is false until the linked dom element is accessible.
16615 * @property available
16621 * By default, drags can only be initiated if the mousedown occurs in the
16622 * region the linked element is. This is done in part to work around a
16623 * bug in some browsers that mis-report the mousedown if the previous
16624 * mouseup happened outside of the window. This property is set to true
16625 * if outer handles are defined.
16627 * @property hasOuterHandles
16631 hasOuterHandles: false,
16634 * Code that executes immediately before the startDrag event
16635 * @method b4StartDrag
16638 b4StartDrag: function(x, y) { },
16641 * Abstract method called after a drag/drop object is clicked
16642 * and the drag or mousedown time thresholds have beeen met.
16643 * @method startDrag
16644 * @param {int} X click location
16645 * @param {int} Y click location
16647 startDrag: function(x, y) { /* override this */ },
16650 * Code that executes immediately before the onDrag event
16654 b4Drag: function(e) { },
16657 * Abstract method called during the onMouseMove event while dragging an
16660 * @param {Event} e the mousemove event
16662 onDrag: function(e) { /* override this */ },
16665 * Abstract method called when this element fist begins hovering over
16666 * another DragDrop obj
16667 * @method onDragEnter
16668 * @param {Event} e the mousemove event
16669 * @param {String|DragDrop[]} id In POINT mode, the element
16670 * id this is hovering over. In INTERSECT mode, an array of one or more
16671 * dragdrop items being hovered over.
16673 onDragEnter: function(e, id) { /* override this */ },
16676 * Code that executes immediately before the onDragOver event
16677 * @method b4DragOver
16680 b4DragOver: function(e) { },
16683 * Abstract method called when this element is hovering over another
16685 * @method onDragOver
16686 * @param {Event} e the mousemove event
16687 * @param {String|DragDrop[]} id In POINT mode, the element
16688 * id this is hovering over. In INTERSECT mode, an array of dd items
16689 * being hovered over.
16691 onDragOver: function(e, id) { /* override this */ },
16694 * Code that executes immediately before the onDragOut event
16695 * @method b4DragOut
16698 b4DragOut: function(e) { },
16701 * Abstract method called when we are no longer hovering over an element
16702 * @method onDragOut
16703 * @param {Event} e the mousemove event
16704 * @param {String|DragDrop[]} id In POINT mode, the element
16705 * id this was hovering over. In INTERSECT mode, an array of dd items
16706 * that the mouse is no longer over.
16708 onDragOut: function(e, id) { /* override this */ },
16711 * Code that executes immediately before the onDragDrop event
16712 * @method b4DragDrop
16715 b4DragDrop: function(e) { },
16718 * Abstract method called when this item is dropped on another DragDrop
16720 * @method onDragDrop
16721 * @param {Event} e the mouseup event
16722 * @param {String|DragDrop[]} id In POINT mode, the element
16723 * id this was dropped on. In INTERSECT mode, an array of dd items this
16726 onDragDrop: function(e, id) { /* override this */ },
16729 * Abstract method called when this item is dropped on an area with no
16731 * @method onInvalidDrop
16732 * @param {Event} e the mouseup event
16734 onInvalidDrop: function(e) { /* override this */ },
16737 * Code that executes immediately before the endDrag event
16738 * @method b4EndDrag
16741 b4EndDrag: function(e) { },
16744 * Fired when we are done dragging the object
16746 * @param {Event} e the mouseup event
16748 endDrag: function(e) { /* override this */ },
16751 * Code executed immediately before the onMouseDown event
16752 * @method b4MouseDown
16753 * @param {Event} e the mousedown event
16756 b4MouseDown: function(e) { },
16759 * Event handler that fires when a drag/drop obj gets a mousedown
16760 * @method onMouseDown
16761 * @param {Event} e the mousedown event
16763 onMouseDown: function(e) { /* override this */ },
16766 * Event handler that fires when a drag/drop obj gets a mouseup
16767 * @method onMouseUp
16768 * @param {Event} e the mouseup event
16770 onMouseUp: function(e) { /* override this */ },
16773 * Override the onAvailable method to do what is needed after the initial
16774 * position was determined.
16775 * @method onAvailable
16777 onAvailable: function () {
16781 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16784 defaultPadding : {left:0, right:0, top:0, bottom:0},
16787 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16791 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16792 { dragElId: "existingProxyDiv" });
16793 dd.startDrag = function(){
16794 this.constrainTo("parent-id");
16797 * Or you can initalize it using the {@link Roo.Element} object:
16799 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16800 startDrag : function(){
16801 this.constrainTo("parent-id");
16805 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16806 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16807 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16808 * an object containing the sides to pad. For example: {right:10, bottom:10}
16809 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16811 constrainTo : function(constrainTo, pad, inContent){
16812 if(typeof pad == "number"){
16813 pad = {left: pad, right:pad, top:pad, bottom:pad};
16815 pad = pad || this.defaultPadding;
16816 var b = Roo.get(this.getEl()).getBox();
16817 var ce = Roo.get(constrainTo);
16818 var s = ce.getScroll();
16819 var c, cd = ce.dom;
16820 if(cd == document.body){
16821 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16824 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16828 var topSpace = b.y - c.y;
16829 var leftSpace = b.x - c.x;
16831 this.resetConstraints();
16832 this.setXConstraint(leftSpace - (pad.left||0), // left
16833 c.width - leftSpace - b.width - (pad.right||0) //right
16835 this.setYConstraint(topSpace - (pad.top||0), //top
16836 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16841 * Returns a reference to the linked element
16843 * @return {HTMLElement} the html element
16845 getEl: function() {
16846 if (!this._domRef) {
16847 this._domRef = Roo.getDom(this.id);
16850 return this._domRef;
16854 * Returns a reference to the actual element to drag. By default this is
16855 * the same as the html element, but it can be assigned to another
16856 * element. An example of this can be found in Roo.dd.DDProxy
16857 * @method getDragEl
16858 * @return {HTMLElement} the html element
16860 getDragEl: function() {
16861 return Roo.getDom(this.dragElId);
16865 * Sets up the DragDrop object. Must be called in the constructor of any
16866 * Roo.dd.DragDrop subclass
16868 * @param id the id of the linked element
16869 * @param {String} sGroup the group of related items
16870 * @param {object} config configuration attributes
16872 init: function(id, sGroup, config) {
16873 this.initTarget(id, sGroup, config);
16874 if (!Roo.isTouch) {
16875 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16877 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16878 // Event.on(this.id, "selectstart", Event.preventDefault);
16882 * Initializes Targeting functionality only... the object does not
16883 * get a mousedown handler.
16884 * @method initTarget
16885 * @param id the id of the linked element
16886 * @param {String} sGroup the group of related items
16887 * @param {object} config configuration attributes
16889 initTarget: function(id, sGroup, config) {
16891 // configuration attributes
16892 this.config = config || {};
16894 // create a local reference to the drag and drop manager
16895 this.DDM = Roo.dd.DDM;
16896 // initialize the groups array
16899 // assume that we have an element reference instead of an id if the
16900 // parameter is not a string
16901 if (typeof id !== "string") {
16908 // add to an interaction group
16909 this.addToGroup((sGroup) ? sGroup : "default");
16911 // We don't want to register this as the handle with the manager
16912 // so we just set the id rather than calling the setter.
16913 this.handleElId = id;
16915 // the linked element is the element that gets dragged by default
16916 this.setDragElId(id);
16918 // by default, clicked anchors will not start drag operations.
16919 this.invalidHandleTypes = { A: "A" };
16920 this.invalidHandleIds = {};
16921 this.invalidHandleClasses = [];
16923 this.applyConfig();
16925 this.handleOnAvailable();
16929 * Applies the configuration parameters that were passed into the constructor.
16930 * This is supposed to happen at each level through the inheritance chain. So
16931 * a DDProxy implentation will execute apply config on DDProxy, DD, and
16932 * DragDrop in order to get all of the parameters that are available in
16934 * @method applyConfig
16936 applyConfig: function() {
16938 // configurable properties:
16939 // padding, isTarget, maintainOffset, primaryButtonOnly
16940 this.padding = this.config.padding || [0, 0, 0, 0];
16941 this.isTarget = (this.config.isTarget !== false);
16942 this.maintainOffset = (this.config.maintainOffset);
16943 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
16948 * Executed when the linked element is available
16949 * @method handleOnAvailable
16952 handleOnAvailable: function() {
16953 this.available = true;
16954 this.resetConstraints();
16955 this.onAvailable();
16959 * Configures the padding for the target zone in px. Effectively expands
16960 * (or reduces) the virtual object size for targeting calculations.
16961 * Supports css-style shorthand; if only one parameter is passed, all sides
16962 * will have that padding, and if only two are passed, the top and bottom
16963 * will have the first param, the left and right the second.
16964 * @method setPadding
16965 * @param {int} iTop Top pad
16966 * @param {int} iRight Right pad
16967 * @param {int} iBot Bot pad
16968 * @param {int} iLeft Left pad
16970 setPadding: function(iTop, iRight, iBot, iLeft) {
16971 // this.padding = [iLeft, iRight, iTop, iBot];
16972 if (!iRight && 0 !== iRight) {
16973 this.padding = [iTop, iTop, iTop, iTop];
16974 } else if (!iBot && 0 !== iBot) {
16975 this.padding = [iTop, iRight, iTop, iRight];
16977 this.padding = [iTop, iRight, iBot, iLeft];
16982 * Stores the initial placement of the linked element.
16983 * @method setInitialPosition
16984 * @param {int} diffX the X offset, default 0
16985 * @param {int} diffY the Y offset, default 0
16987 setInitPosition: function(diffX, diffY) {
16988 var el = this.getEl();
16990 if (!this.DDM.verifyEl(el)) {
16994 var dx = diffX || 0;
16995 var dy = diffY || 0;
16997 var p = Dom.getXY( el );
16999 this.initPageX = p[0] - dx;
17000 this.initPageY = p[1] - dy;
17002 this.lastPageX = p[0];
17003 this.lastPageY = p[1];
17006 this.setStartPosition(p);
17010 * Sets the start position of the element. This is set when the obj
17011 * is initialized, the reset when a drag is started.
17012 * @method setStartPosition
17013 * @param pos current position (from previous lookup)
17016 setStartPosition: function(pos) {
17017 var p = pos || Dom.getXY( this.getEl() );
17018 this.deltaSetXY = null;
17020 this.startPageX = p[0];
17021 this.startPageY = p[1];
17025 * Add this instance to a group of related drag/drop objects. All
17026 * instances belong to at least one group, and can belong to as many
17027 * groups as needed.
17028 * @method addToGroup
17029 * @param sGroup {string} the name of the group
17031 addToGroup: function(sGroup) {
17032 this.groups[sGroup] = true;
17033 this.DDM.regDragDrop(this, sGroup);
17037 * Remove's this instance from the supplied interaction group
17038 * @method removeFromGroup
17039 * @param {string} sGroup The group to drop
17041 removeFromGroup: function(sGroup) {
17042 if (this.groups[sGroup]) {
17043 delete this.groups[sGroup];
17046 this.DDM.removeDDFromGroup(this, sGroup);
17050 * Allows you to specify that an element other than the linked element
17051 * will be moved with the cursor during a drag
17052 * @method setDragElId
17053 * @param id {string} the id of the element that will be used to initiate the drag
17055 setDragElId: function(id) {
17056 this.dragElId = id;
17060 * Allows you to specify a child of the linked element that should be
17061 * used to initiate the drag operation. An example of this would be if
17062 * you have a content div with text and links. Clicking anywhere in the
17063 * content area would normally start the drag operation. Use this method
17064 * to specify that an element inside of the content div is the element
17065 * that starts the drag operation.
17066 * @method setHandleElId
17067 * @param id {string} the id of the element that will be used to
17068 * initiate the drag.
17070 setHandleElId: function(id) {
17071 if (typeof id !== "string") {
17074 this.handleElId = id;
17075 this.DDM.regHandle(this.id, id);
17079 * Allows you to set an element outside of the linked element as a drag
17081 * @method setOuterHandleElId
17082 * @param id the id of the element that will be used to initiate the drag
17084 setOuterHandleElId: function(id) {
17085 if (typeof id !== "string") {
17088 Event.on(id, "mousedown",
17089 this.handleMouseDown, this);
17090 this.setHandleElId(id);
17092 this.hasOuterHandles = true;
17096 * Remove all drag and drop hooks for this element
17099 unreg: function() {
17100 Event.un(this.id, "mousedown",
17101 this.handleMouseDown);
17102 Event.un(this.id, "touchstart",
17103 this.handleMouseDown);
17104 this._domRef = null;
17105 this.DDM._remove(this);
17108 destroy : function(){
17113 * Returns true if this instance is locked, or the drag drop mgr is locked
17114 * (meaning that all drag/drop is disabled on the page.)
17116 * @return {boolean} true if this obj or all drag/drop is locked, else
17119 isLocked: function() {
17120 return (this.DDM.isLocked() || this.locked);
17124 * Fired when this object is clicked
17125 * @method handleMouseDown
17127 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17130 handleMouseDown: function(e, oDD){
17132 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17133 //Roo.log('not touch/ button !=0');
17136 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17137 return; // double touch..
17141 if (this.isLocked()) {
17142 //Roo.log('locked');
17146 this.DDM.refreshCache(this.groups);
17147 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17148 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17149 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17150 //Roo.log('no outer handes or not over target');
17153 // Roo.log('check validator');
17154 if (this.clickValidator(e)) {
17155 // Roo.log('validate success');
17156 // set the initial element position
17157 this.setStartPosition();
17160 this.b4MouseDown(e);
17161 this.onMouseDown(e);
17163 this.DDM.handleMouseDown(e, this);
17165 this.DDM.stopEvent(e);
17173 clickValidator: function(e) {
17174 var target = e.getTarget();
17175 return ( this.isValidHandleChild(target) &&
17176 (this.id == this.handleElId ||
17177 this.DDM.handleWasClicked(target, this.id)) );
17181 * Allows you to specify a tag name that should not start a drag operation
17182 * when clicked. This is designed to facilitate embedding links within a
17183 * drag handle that do something other than start the drag.
17184 * @method addInvalidHandleType
17185 * @param {string} tagName the type of element to exclude
17187 addInvalidHandleType: function(tagName) {
17188 var type = tagName.toUpperCase();
17189 this.invalidHandleTypes[type] = type;
17193 * Lets you to specify an element id for a child of a drag handle
17194 * that should not initiate a drag
17195 * @method addInvalidHandleId
17196 * @param {string} id the element id of the element you wish to ignore
17198 addInvalidHandleId: function(id) {
17199 if (typeof id !== "string") {
17202 this.invalidHandleIds[id] = id;
17206 * Lets you specify a css class of elements that will not initiate a drag
17207 * @method addInvalidHandleClass
17208 * @param {string} cssClass the class of the elements you wish to ignore
17210 addInvalidHandleClass: function(cssClass) {
17211 this.invalidHandleClasses.push(cssClass);
17215 * Unsets an excluded tag name set by addInvalidHandleType
17216 * @method removeInvalidHandleType
17217 * @param {string} tagName the type of element to unexclude
17219 removeInvalidHandleType: function(tagName) {
17220 var type = tagName.toUpperCase();
17221 // this.invalidHandleTypes[type] = null;
17222 delete this.invalidHandleTypes[type];
17226 * Unsets an invalid handle id
17227 * @method removeInvalidHandleId
17228 * @param {string} id the id of the element to re-enable
17230 removeInvalidHandleId: function(id) {
17231 if (typeof id !== "string") {
17234 delete this.invalidHandleIds[id];
17238 * Unsets an invalid css class
17239 * @method removeInvalidHandleClass
17240 * @param {string} cssClass the class of the element(s) you wish to
17243 removeInvalidHandleClass: function(cssClass) {
17244 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17245 if (this.invalidHandleClasses[i] == cssClass) {
17246 delete this.invalidHandleClasses[i];
17252 * Checks the tag exclusion list to see if this click should be ignored
17253 * @method isValidHandleChild
17254 * @param {HTMLElement} node the HTMLElement to evaluate
17255 * @return {boolean} true if this is a valid tag type, false if not
17257 isValidHandleChild: function(node) {
17260 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17263 nodeName = node.nodeName.toUpperCase();
17265 nodeName = node.nodeName;
17267 valid = valid && !this.invalidHandleTypes[nodeName];
17268 valid = valid && !this.invalidHandleIds[node.id];
17270 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17271 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17280 * Create the array of horizontal tick marks if an interval was specified
17281 * in setXConstraint().
17282 * @method setXTicks
17285 setXTicks: function(iStartX, iTickSize) {
17287 this.xTickSize = iTickSize;
17291 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17293 this.xTicks[this.xTicks.length] = i;
17298 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17300 this.xTicks[this.xTicks.length] = i;
17305 this.xTicks.sort(this.DDM.numericSort) ;
17309 * Create the array of vertical tick marks if an interval was specified in
17310 * setYConstraint().
17311 * @method setYTicks
17314 setYTicks: function(iStartY, iTickSize) {
17316 this.yTickSize = iTickSize;
17320 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17322 this.yTicks[this.yTicks.length] = i;
17327 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17329 this.yTicks[this.yTicks.length] = i;
17334 this.yTicks.sort(this.DDM.numericSort) ;
17338 * By default, the element can be dragged any place on the screen. Use
17339 * this method to limit the horizontal travel of the element. Pass in
17340 * 0,0 for the parameters if you want to lock the drag to the y axis.
17341 * @method setXConstraint
17342 * @param {int} iLeft the number of pixels the element can move to the left
17343 * @param {int} iRight the number of pixels the element can move to the
17345 * @param {int} iTickSize optional parameter for specifying that the
17347 * should move iTickSize pixels at a time.
17349 setXConstraint: function(iLeft, iRight, iTickSize) {
17350 this.leftConstraint = iLeft;
17351 this.rightConstraint = iRight;
17353 this.minX = this.initPageX - iLeft;
17354 this.maxX = this.initPageX + iRight;
17355 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17357 this.constrainX = true;
17361 * Clears any constraints applied to this instance. Also clears ticks
17362 * since they can't exist independent of a constraint at this time.
17363 * @method clearConstraints
17365 clearConstraints: function() {
17366 this.constrainX = false;
17367 this.constrainY = false;
17372 * Clears any tick interval defined for this instance
17373 * @method clearTicks
17375 clearTicks: function() {
17376 this.xTicks = null;
17377 this.yTicks = null;
17378 this.xTickSize = 0;
17379 this.yTickSize = 0;
17383 * By default, the element can be dragged any place on the screen. Set
17384 * this to limit the vertical travel of the element. Pass in 0,0 for the
17385 * parameters if you want to lock the drag to the x axis.
17386 * @method setYConstraint
17387 * @param {int} iUp the number of pixels the element can move up
17388 * @param {int} iDown the number of pixels the element can move down
17389 * @param {int} iTickSize optional parameter for specifying that the
17390 * element should move iTickSize pixels at a time.
17392 setYConstraint: function(iUp, iDown, iTickSize) {
17393 this.topConstraint = iUp;
17394 this.bottomConstraint = iDown;
17396 this.minY = this.initPageY - iUp;
17397 this.maxY = this.initPageY + iDown;
17398 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17400 this.constrainY = true;
17405 * resetConstraints must be called if you manually reposition a dd element.
17406 * @method resetConstraints
17407 * @param {boolean} maintainOffset
17409 resetConstraints: function() {
17412 // Maintain offsets if necessary
17413 if (this.initPageX || this.initPageX === 0) {
17414 // figure out how much this thing has moved
17415 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17416 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17418 this.setInitPosition(dx, dy);
17420 // This is the first time we have detected the element's position
17422 this.setInitPosition();
17425 if (this.constrainX) {
17426 this.setXConstraint( this.leftConstraint,
17427 this.rightConstraint,
17431 if (this.constrainY) {
17432 this.setYConstraint( this.topConstraint,
17433 this.bottomConstraint,
17439 * Normally the drag element is moved pixel by pixel, but we can specify
17440 * that it move a number of pixels at a time. This method resolves the
17441 * location when we have it set up like this.
17443 * @param {int} val where we want to place the object
17444 * @param {int[]} tickArray sorted array of valid points
17445 * @return {int} the closest tick
17448 getTick: function(val, tickArray) {
17451 // If tick interval is not defined, it is effectively 1 pixel,
17452 // so we return the value passed to us.
17454 } else if (tickArray[0] >= val) {
17455 // The value is lower than the first tick, so we return the first
17457 return tickArray[0];
17459 for (var i=0, len=tickArray.length; i<len; ++i) {
17461 if (tickArray[next] && tickArray[next] >= val) {
17462 var diff1 = val - tickArray[i];
17463 var diff2 = tickArray[next] - val;
17464 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17468 // The value is larger than the last tick, so we return the last
17470 return tickArray[tickArray.length - 1];
17477 * @return {string} string representation of the dd obj
17479 toString: function() {
17480 return ("DragDrop " + this.id);
17488 * Ext JS Library 1.1.1
17489 * Copyright(c) 2006-2007, Ext JS, LLC.
17491 * Originally Released Under LGPL - original licence link has changed is not relivant.
17494 * <script type="text/javascript">
17499 * The drag and drop utility provides a framework for building drag and drop
17500 * applications. In addition to enabling drag and drop for specific elements,
17501 * the drag and drop elements are tracked by the manager class, and the
17502 * interactions between the various elements are tracked during the drag and
17503 * the implementing code is notified about these important moments.
17506 // Only load the library once. Rewriting the manager class would orphan
17507 // existing drag and drop instances.
17508 if (!Roo.dd.DragDropMgr) {
17511 * @class Roo.dd.DragDropMgr
17512 * DragDropMgr is a singleton that tracks the element interaction for
17513 * all DragDrop items in the window. Generally, you will not call
17514 * this class directly, but it does have helper methods that could
17515 * be useful in your DragDrop implementations.
17518 Roo.dd.DragDropMgr = function() {
17520 var Event = Roo.EventManager;
17525 * Two dimensional Array of registered DragDrop objects. The first
17526 * dimension is the DragDrop item group, the second the DragDrop
17529 * @type {string: string}
17536 * Array of element ids defined as drag handles. Used to determine
17537 * if the element that generated the mousedown event is actually the
17538 * handle and not the html element itself.
17539 * @property handleIds
17540 * @type {string: string}
17547 * the DragDrop object that is currently being dragged
17548 * @property dragCurrent
17556 * the DragDrop object(s) that are being hovered over
17557 * @property dragOvers
17565 * the X distance between the cursor and the object being dragged
17574 * the Y distance between the cursor and the object being dragged
17583 * Flag to determine if we should prevent the default behavior of the
17584 * events we define. By default this is true, but this can be set to
17585 * false if you need the default behavior (not recommended)
17586 * @property preventDefault
17590 preventDefault: true,
17593 * Flag to determine if we should stop the propagation of the events
17594 * we generate. This is true by default but you may want to set it to
17595 * false if the html element contains other features that require the
17597 * @property stopPropagation
17601 stopPropagation: true,
17604 * Internal flag that is set to true when drag and drop has been
17606 * @property initialized
17613 * All drag and drop can be disabled.
17621 * Called the first time an element is registered.
17627 this.initialized = true;
17631 * In point mode, drag and drop interaction is defined by the
17632 * location of the cursor during the drag/drop
17640 * In intersect mode, drag and drop interactio nis defined by the
17641 * overlap of two or more drag and drop objects.
17642 * @property INTERSECT
17649 * The current drag and drop mode. Default: POINT
17657 * Runs method on all drag and drop objects
17658 * @method _execOnAll
17662 _execOnAll: function(sMethod, args) {
17663 for (var i in this.ids) {
17664 for (var j in this.ids[i]) {
17665 var oDD = this.ids[i][j];
17666 if (! this.isTypeOfDD(oDD)) {
17669 oDD[sMethod].apply(oDD, args);
17675 * Drag and drop initialization. Sets up the global event handlers
17680 _onLoad: function() {
17684 if (!Roo.isTouch) {
17685 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17686 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17688 Event.on(document, "touchend", this.handleMouseUp, this, true);
17689 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17691 Event.on(window, "unload", this._onUnload, this, true);
17692 Event.on(window, "resize", this._onResize, this, true);
17693 // Event.on(window, "mouseout", this._test);
17698 * Reset constraints on all drag and drop objs
17699 * @method _onResize
17703 _onResize: function(e) {
17704 this._execOnAll("resetConstraints", []);
17708 * Lock all drag and drop functionality
17712 lock: function() { this.locked = true; },
17715 * Unlock all drag and drop functionality
17719 unlock: function() { this.locked = false; },
17722 * Is drag and drop locked?
17724 * @return {boolean} True if drag and drop is locked, false otherwise.
17727 isLocked: function() { return this.locked; },
17730 * Location cache that is set for all drag drop objects when a drag is
17731 * initiated, cleared when the drag is finished.
17732 * @property locationCache
17739 * Set useCache to false if you want to force object the lookup of each
17740 * drag and drop linked element constantly during a drag.
17741 * @property useCache
17748 * The number of pixels that the mouse needs to move after the
17749 * mousedown before the drag is initiated. Default=3;
17750 * @property clickPixelThresh
17754 clickPixelThresh: 3,
17757 * The number of milliseconds after the mousedown event to initiate the
17758 * drag if we don't get a mouseup event. Default=1000
17759 * @property clickTimeThresh
17763 clickTimeThresh: 350,
17766 * Flag that indicates that either the drag pixel threshold or the
17767 * mousdown time threshold has been met
17768 * @property dragThreshMet
17773 dragThreshMet: false,
17776 * Timeout used for the click time threshold
17777 * @property clickTimeout
17782 clickTimeout: null,
17785 * The X position of the mousedown event stored for later use when a
17786 * drag threshold is met.
17795 * The Y position of the mousedown event stored for later use when a
17796 * drag threshold is met.
17805 * Each DragDrop instance must be registered with the DragDropMgr.
17806 * This is executed in DragDrop.init()
17807 * @method regDragDrop
17808 * @param {DragDrop} oDD the DragDrop object to register
17809 * @param {String} sGroup the name of the group this element belongs to
17812 regDragDrop: function(oDD, sGroup) {
17813 if (!this.initialized) { this.init(); }
17815 if (!this.ids[sGroup]) {
17816 this.ids[sGroup] = {};
17818 this.ids[sGroup][oDD.id] = oDD;
17822 * Removes the supplied dd instance from the supplied group. Executed
17823 * by DragDrop.removeFromGroup, so don't call this function directly.
17824 * @method removeDDFromGroup
17828 removeDDFromGroup: function(oDD, sGroup) {
17829 if (!this.ids[sGroup]) {
17830 this.ids[sGroup] = {};
17833 var obj = this.ids[sGroup];
17834 if (obj && obj[oDD.id]) {
17835 delete obj[oDD.id];
17840 * Unregisters a drag and drop item. This is executed in
17841 * DragDrop.unreg, use that method instead of calling this directly.
17846 _remove: function(oDD) {
17847 for (var g in oDD.groups) {
17848 if (g && this.ids[g][oDD.id]) {
17849 delete this.ids[g][oDD.id];
17852 delete this.handleIds[oDD.id];
17856 * Each DragDrop handle element must be registered. This is done
17857 * automatically when executing DragDrop.setHandleElId()
17858 * @method regHandle
17859 * @param {String} sDDId the DragDrop id this element is a handle for
17860 * @param {String} sHandleId the id of the element that is the drag
17864 regHandle: function(sDDId, sHandleId) {
17865 if (!this.handleIds[sDDId]) {
17866 this.handleIds[sDDId] = {};
17868 this.handleIds[sDDId][sHandleId] = sHandleId;
17872 * Utility function to determine if a given element has been
17873 * registered as a drag drop item.
17874 * @method isDragDrop
17875 * @param {String} id the element id to check
17876 * @return {boolean} true if this element is a DragDrop item,
17880 isDragDrop: function(id) {
17881 return ( this.getDDById(id) ) ? true : false;
17885 * Returns the drag and drop instances that are in all groups the
17886 * passed in instance belongs to.
17887 * @method getRelated
17888 * @param {DragDrop} p_oDD the obj to get related data for
17889 * @param {boolean} bTargetsOnly if true, only return targetable objs
17890 * @return {DragDrop[]} the related instances
17893 getRelated: function(p_oDD, bTargetsOnly) {
17895 for (var i in p_oDD.groups) {
17896 for (j in this.ids[i]) {
17897 var dd = this.ids[i][j];
17898 if (! this.isTypeOfDD(dd)) {
17901 if (!bTargetsOnly || dd.isTarget) {
17902 oDDs[oDDs.length] = dd;
17911 * Returns true if the specified dd target is a legal target for
17912 * the specifice drag obj
17913 * @method isLegalTarget
17914 * @param {DragDrop} the drag obj
17915 * @param {DragDrop} the target
17916 * @return {boolean} true if the target is a legal target for the
17920 isLegalTarget: function (oDD, oTargetDD) {
17921 var targets = this.getRelated(oDD, true);
17922 for (var i=0, len=targets.length;i<len;++i) {
17923 if (targets[i].id == oTargetDD.id) {
17932 * My goal is to be able to transparently determine if an object is
17933 * typeof DragDrop, and the exact subclass of DragDrop. typeof
17934 * returns "object", oDD.constructor.toString() always returns
17935 * "DragDrop" and not the name of the subclass. So for now it just
17936 * evaluates a well-known variable in DragDrop.
17937 * @method isTypeOfDD
17938 * @param {Object} the object to evaluate
17939 * @return {boolean} true if typeof oDD = DragDrop
17942 isTypeOfDD: function (oDD) {
17943 return (oDD && oDD.__ygDragDrop);
17947 * Utility function to determine if a given element has been
17948 * registered as a drag drop handle for the given Drag Drop object.
17950 * @param {String} id the element id to check
17951 * @return {boolean} true if this element is a DragDrop handle, false
17955 isHandle: function(sDDId, sHandleId) {
17956 return ( this.handleIds[sDDId] &&
17957 this.handleIds[sDDId][sHandleId] );
17961 * Returns the DragDrop instance for a given id
17962 * @method getDDById
17963 * @param {String} id the id of the DragDrop object
17964 * @return {DragDrop} the drag drop object, null if it is not found
17967 getDDById: function(id) {
17968 for (var i in this.ids) {
17969 if (this.ids[i][id]) {
17970 return this.ids[i][id];
17977 * Fired after a registered DragDrop object gets the mousedown event.
17978 * Sets up the events required to track the object being dragged
17979 * @method handleMouseDown
17980 * @param {Event} e the event
17981 * @param oDD the DragDrop object being dragged
17985 handleMouseDown: function(e, oDD) {
17987 Roo.QuickTips.disable();
17989 this.currentTarget = e.getTarget();
17991 this.dragCurrent = oDD;
17993 var el = oDD.getEl();
17995 // track start position
17996 this.startX = e.getPageX();
17997 this.startY = e.getPageY();
17999 this.deltaX = this.startX - el.offsetLeft;
18000 this.deltaY = this.startY - el.offsetTop;
18002 this.dragThreshMet = false;
18004 this.clickTimeout = setTimeout(
18006 var DDM = Roo.dd.DDM;
18007 DDM.startDrag(DDM.startX, DDM.startY);
18009 this.clickTimeThresh );
18013 * Fired when either the drag pixel threshol or the mousedown hold
18014 * time threshold has been met.
18015 * @method startDrag
18016 * @param x {int} the X position of the original mousedown
18017 * @param y {int} the Y position of the original mousedown
18020 startDrag: function(x, y) {
18021 clearTimeout(this.clickTimeout);
18022 if (this.dragCurrent) {
18023 this.dragCurrent.b4StartDrag(x, y);
18024 this.dragCurrent.startDrag(x, y);
18026 this.dragThreshMet = true;
18030 * Internal function to handle the mouseup event. Will be invoked
18031 * from the context of the document.
18032 * @method handleMouseUp
18033 * @param {Event} e the event
18037 handleMouseUp: function(e) {
18040 Roo.QuickTips.enable();
18042 if (! this.dragCurrent) {
18046 clearTimeout(this.clickTimeout);
18048 if (this.dragThreshMet) {
18049 this.fireEvents(e, true);
18059 * Utility to stop event propagation and event default, if these
18060 * features are turned on.
18061 * @method stopEvent
18062 * @param {Event} e the event as returned by this.getEvent()
18065 stopEvent: function(e){
18066 if(this.stopPropagation) {
18067 e.stopPropagation();
18070 if (this.preventDefault) {
18071 e.preventDefault();
18076 * Internal function to clean up event handlers after the drag
18077 * operation is complete
18079 * @param {Event} e the event
18083 stopDrag: function(e) {
18084 // Fire the drag end event for the item that was dragged
18085 if (this.dragCurrent) {
18086 if (this.dragThreshMet) {
18087 this.dragCurrent.b4EndDrag(e);
18088 this.dragCurrent.endDrag(e);
18091 this.dragCurrent.onMouseUp(e);
18094 this.dragCurrent = null;
18095 this.dragOvers = {};
18099 * Internal function to handle the mousemove event. Will be invoked
18100 * from the context of the html element.
18102 * @TODO figure out what we can do about mouse events lost when the
18103 * user drags objects beyond the window boundary. Currently we can
18104 * detect this in internet explorer by verifying that the mouse is
18105 * down during the mousemove event. Firefox doesn't give us the
18106 * button state on the mousemove event.
18107 * @method handleMouseMove
18108 * @param {Event} e the event
18112 handleMouseMove: function(e) {
18113 if (! this.dragCurrent) {
18117 // var button = e.which || e.button;
18119 // check for IE mouseup outside of page boundary
18120 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18122 return this.handleMouseUp(e);
18125 if (!this.dragThreshMet) {
18126 var diffX = Math.abs(this.startX - e.getPageX());
18127 var diffY = Math.abs(this.startY - e.getPageY());
18128 if (diffX > this.clickPixelThresh ||
18129 diffY > this.clickPixelThresh) {
18130 this.startDrag(this.startX, this.startY);
18134 if (this.dragThreshMet) {
18135 this.dragCurrent.b4Drag(e);
18136 this.dragCurrent.onDrag(e);
18137 if(!this.dragCurrent.moveOnly){
18138 this.fireEvents(e, false);
18148 * Iterates over all of the DragDrop elements to find ones we are
18149 * hovering over or dropping on
18150 * @method fireEvents
18151 * @param {Event} e the event
18152 * @param {boolean} isDrop is this a drop op or a mouseover op?
18156 fireEvents: function(e, isDrop) {
18157 var dc = this.dragCurrent;
18159 // If the user did the mouse up outside of the window, we could
18160 // get here even though we have ended the drag.
18161 if (!dc || dc.isLocked()) {
18165 var pt = e.getPoint();
18167 // cache the previous dragOver array
18173 var enterEvts = [];
18175 // Check to see if the object(s) we were hovering over is no longer
18176 // being hovered over so we can fire the onDragOut event
18177 for (var i in this.dragOvers) {
18179 var ddo = this.dragOvers[i];
18181 if (! this.isTypeOfDD(ddo)) {
18185 if (! this.isOverTarget(pt, ddo, this.mode)) {
18186 outEvts.push( ddo );
18189 oldOvers[i] = true;
18190 delete this.dragOvers[i];
18193 for (var sGroup in dc.groups) {
18195 if ("string" != typeof sGroup) {
18199 for (i in this.ids[sGroup]) {
18200 var oDD = this.ids[sGroup][i];
18201 if (! this.isTypeOfDD(oDD)) {
18205 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18206 if (this.isOverTarget(pt, oDD, this.mode)) {
18207 // look for drop interactions
18209 dropEvts.push( oDD );
18210 // look for drag enter and drag over interactions
18213 // initial drag over: dragEnter fires
18214 if (!oldOvers[oDD.id]) {
18215 enterEvts.push( oDD );
18216 // subsequent drag overs: dragOver fires
18218 overEvts.push( oDD );
18221 this.dragOvers[oDD.id] = oDD;
18229 if (outEvts.length) {
18230 dc.b4DragOut(e, outEvts);
18231 dc.onDragOut(e, outEvts);
18234 if (enterEvts.length) {
18235 dc.onDragEnter(e, enterEvts);
18238 if (overEvts.length) {
18239 dc.b4DragOver(e, overEvts);
18240 dc.onDragOver(e, overEvts);
18243 if (dropEvts.length) {
18244 dc.b4DragDrop(e, dropEvts);
18245 dc.onDragDrop(e, dropEvts);
18249 // fire dragout events
18251 for (i=0, len=outEvts.length; i<len; ++i) {
18252 dc.b4DragOut(e, outEvts[i].id);
18253 dc.onDragOut(e, outEvts[i].id);
18256 // fire enter events
18257 for (i=0,len=enterEvts.length; i<len; ++i) {
18258 // dc.b4DragEnter(e, oDD.id);
18259 dc.onDragEnter(e, enterEvts[i].id);
18262 // fire over events
18263 for (i=0,len=overEvts.length; i<len; ++i) {
18264 dc.b4DragOver(e, overEvts[i].id);
18265 dc.onDragOver(e, overEvts[i].id);
18268 // fire drop events
18269 for (i=0, len=dropEvts.length; i<len; ++i) {
18270 dc.b4DragDrop(e, dropEvts[i].id);
18271 dc.onDragDrop(e, dropEvts[i].id);
18276 // notify about a drop that did not find a target
18277 if (isDrop && !dropEvts.length) {
18278 dc.onInvalidDrop(e);
18284 * Helper function for getting the best match from the list of drag
18285 * and drop objects returned by the drag and drop events when we are
18286 * in INTERSECT mode. It returns either the first object that the
18287 * cursor is over, or the object that has the greatest overlap with
18288 * the dragged element.
18289 * @method getBestMatch
18290 * @param {DragDrop[]} dds The array of drag and drop objects
18292 * @return {DragDrop} The best single match
18295 getBestMatch: function(dds) {
18297 // Return null if the input is not what we expect
18298 //if (!dds || !dds.length || dds.length == 0) {
18300 // If there is only one item, it wins
18301 //} else if (dds.length == 1) {
18303 var len = dds.length;
18308 // Loop through the targeted items
18309 for (var i=0; i<len; ++i) {
18311 // If the cursor is over the object, it wins. If the
18312 // cursor is over multiple matches, the first one we come
18314 if (dd.cursorIsOver) {
18317 // Otherwise the object with the most overlap wins
18320 winner.overlap.getArea() < dd.overlap.getArea()) {
18331 * Refreshes the cache of the top-left and bottom-right points of the
18332 * drag and drop objects in the specified group(s). This is in the
18333 * format that is stored in the drag and drop instance, so typical
18336 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18340 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18342 * @TODO this really should be an indexed array. Alternatively this
18343 * method could accept both.
18344 * @method refreshCache
18345 * @param {Object} groups an associative array of groups to refresh
18348 refreshCache: function(groups) {
18349 for (var sGroup in groups) {
18350 if ("string" != typeof sGroup) {
18353 for (var i in this.ids[sGroup]) {
18354 var oDD = this.ids[sGroup][i];
18356 if (this.isTypeOfDD(oDD)) {
18357 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18358 var loc = this.getLocation(oDD);
18360 this.locationCache[oDD.id] = loc;
18362 delete this.locationCache[oDD.id];
18363 // this will unregister the drag and drop object if
18364 // the element is not in a usable state
18373 * This checks to make sure an element exists and is in the DOM. The
18374 * main purpose is to handle cases where innerHTML is used to remove
18375 * drag and drop objects from the DOM. IE provides an 'unspecified
18376 * error' when trying to access the offsetParent of such an element
18378 * @param {HTMLElement} el the element to check
18379 * @return {boolean} true if the element looks usable
18382 verifyEl: function(el) {
18387 parent = el.offsetParent;
18390 parent = el.offsetParent;
18401 * Returns a Region object containing the drag and drop element's position
18402 * and size, including the padding configured for it
18403 * @method getLocation
18404 * @param {DragDrop} oDD the drag and drop object to get the
18406 * @return {Roo.lib.Region} a Region object representing the total area
18407 * the element occupies, including any padding
18408 * the instance is configured for.
18411 getLocation: function(oDD) {
18412 if (! this.isTypeOfDD(oDD)) {
18416 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18419 pos= Roo.lib.Dom.getXY(el);
18427 x2 = x1 + el.offsetWidth;
18429 y2 = y1 + el.offsetHeight;
18431 t = y1 - oDD.padding[0];
18432 r = x2 + oDD.padding[1];
18433 b = y2 + oDD.padding[2];
18434 l = x1 - oDD.padding[3];
18436 return new Roo.lib.Region( t, r, b, l );
18440 * Checks the cursor location to see if it over the target
18441 * @method isOverTarget
18442 * @param {Roo.lib.Point} pt The point to evaluate
18443 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18444 * @return {boolean} true if the mouse is over the target
18448 isOverTarget: function(pt, oTarget, intersect) {
18449 // use cache if available
18450 var loc = this.locationCache[oTarget.id];
18451 if (!loc || !this.useCache) {
18452 loc = this.getLocation(oTarget);
18453 this.locationCache[oTarget.id] = loc;
18461 oTarget.cursorIsOver = loc.contains( pt );
18463 // DragDrop is using this as a sanity check for the initial mousedown
18464 // in this case we are done. In POINT mode, if the drag obj has no
18465 // contraints, we are also done. Otherwise we need to evaluate the
18466 // location of the target as related to the actual location of the
18467 // dragged element.
18468 var dc = this.dragCurrent;
18469 if (!dc || !dc.getTargetCoord ||
18470 (!intersect && !dc.constrainX && !dc.constrainY)) {
18471 return oTarget.cursorIsOver;
18474 oTarget.overlap = null;
18476 // Get the current location of the drag element, this is the
18477 // location of the mouse event less the delta that represents
18478 // where the original mousedown happened on the element. We
18479 // need to consider constraints and ticks as well.
18480 var pos = dc.getTargetCoord(pt.x, pt.y);
18482 var el = dc.getDragEl();
18483 var curRegion = new Roo.lib.Region( pos.y,
18484 pos.x + el.offsetWidth,
18485 pos.y + el.offsetHeight,
18488 var overlap = curRegion.intersect(loc);
18491 oTarget.overlap = overlap;
18492 return (intersect) ? true : oTarget.cursorIsOver;
18499 * unload event handler
18500 * @method _onUnload
18504 _onUnload: function(e, me) {
18505 Roo.dd.DragDropMgr.unregAll();
18509 * Cleans up the drag and drop events and objects.
18514 unregAll: function() {
18516 if (this.dragCurrent) {
18518 this.dragCurrent = null;
18521 this._execOnAll("unreg", []);
18523 for (i in this.elementCache) {
18524 delete this.elementCache[i];
18527 this.elementCache = {};
18532 * A cache of DOM elements
18533 * @property elementCache
18540 * Get the wrapper for the DOM element specified
18541 * @method getElWrapper
18542 * @param {String} id the id of the element to get
18543 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18545 * @deprecated This wrapper isn't that useful
18548 getElWrapper: function(id) {
18549 var oWrapper = this.elementCache[id];
18550 if (!oWrapper || !oWrapper.el) {
18551 oWrapper = this.elementCache[id] =
18552 new this.ElementWrapper(Roo.getDom(id));
18558 * Returns the actual DOM element
18559 * @method getElement
18560 * @param {String} id the id of the elment to get
18561 * @return {Object} The element
18562 * @deprecated use Roo.getDom instead
18565 getElement: function(id) {
18566 return Roo.getDom(id);
18570 * Returns the style property for the DOM element (i.e.,
18571 * document.getElById(id).style)
18573 * @param {String} id the id of the elment to get
18574 * @return {Object} The style property of the element
18575 * @deprecated use Roo.getDom instead
18578 getCss: function(id) {
18579 var el = Roo.getDom(id);
18580 return (el) ? el.style : null;
18584 * Inner class for cached elements
18585 * @class DragDropMgr.ElementWrapper
18590 ElementWrapper: function(el) {
18595 this.el = el || null;
18600 this.id = this.el && el.id;
18602 * A reference to the style property
18605 this.css = this.el && el.style;
18609 * Returns the X position of an html element
18611 * @param el the element for which to get the position
18612 * @return {int} the X coordinate
18614 * @deprecated use Roo.lib.Dom.getX instead
18617 getPosX: function(el) {
18618 return Roo.lib.Dom.getX(el);
18622 * Returns the Y position of an html element
18624 * @param el the element for which to get the position
18625 * @return {int} the Y coordinate
18626 * @deprecated use Roo.lib.Dom.getY instead
18629 getPosY: function(el) {
18630 return Roo.lib.Dom.getY(el);
18634 * Swap two nodes. In IE, we use the native method, for others we
18635 * emulate the IE behavior
18637 * @param n1 the first node to swap
18638 * @param n2 the other node to swap
18641 swapNode: function(n1, n2) {
18645 var p = n2.parentNode;
18646 var s = n2.nextSibling;
18649 p.insertBefore(n1, n2);
18650 } else if (n2 == n1.nextSibling) {
18651 p.insertBefore(n2, n1);
18653 n1.parentNode.replaceChild(n2, n1);
18654 p.insertBefore(n1, s);
18660 * Returns the current scroll position
18661 * @method getScroll
18665 getScroll: function () {
18666 var t, l, dde=document.documentElement, db=document.body;
18667 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18669 l = dde.scrollLeft;
18676 return { top: t, left: l };
18680 * Returns the specified element style property
18682 * @param {HTMLElement} el the element
18683 * @param {string} styleProp the style property
18684 * @return {string} The value of the style property
18685 * @deprecated use Roo.lib.Dom.getStyle
18688 getStyle: function(el, styleProp) {
18689 return Roo.fly(el).getStyle(styleProp);
18693 * Gets the scrollTop
18694 * @method getScrollTop
18695 * @return {int} the document's scrollTop
18698 getScrollTop: function () { return this.getScroll().top; },
18701 * Gets the scrollLeft
18702 * @method getScrollLeft
18703 * @return {int} the document's scrollTop
18706 getScrollLeft: function () { return this.getScroll().left; },
18709 * Sets the x/y position of an element to the location of the
18712 * @param {HTMLElement} moveEl The element to move
18713 * @param {HTMLElement} targetEl The position reference element
18716 moveToEl: function (moveEl, targetEl) {
18717 var aCoord = Roo.lib.Dom.getXY(targetEl);
18718 Roo.lib.Dom.setXY(moveEl, aCoord);
18722 * Numeric array sort function
18723 * @method numericSort
18726 numericSort: function(a, b) { return (a - b); },
18730 * @property _timeoutCount
18737 * Trying to make the load order less important. Without this we get
18738 * an error if this file is loaded before the Event Utility.
18739 * @method _addListeners
18743 _addListeners: function() {
18744 var DDM = Roo.dd.DDM;
18745 if ( Roo.lib.Event && document ) {
18748 if (DDM._timeoutCount > 2000) {
18750 setTimeout(DDM._addListeners, 10);
18751 if (document && document.body) {
18752 DDM._timeoutCount += 1;
18759 * Recursively searches the immediate parent and all child nodes for
18760 * the handle element in order to determine wheter or not it was
18762 * @method handleWasClicked
18763 * @param node the html element to inspect
18766 handleWasClicked: function(node, id) {
18767 if (this.isHandle(id, node.id)) {
18770 // check to see if this is a text node child of the one we want
18771 var p = node.parentNode;
18774 if (this.isHandle(id, p.id)) {
18789 // shorter alias, save a few bytes
18790 Roo.dd.DDM = Roo.dd.DragDropMgr;
18791 Roo.dd.DDM._addListeners();
18795 * Ext JS Library 1.1.1
18796 * Copyright(c) 2006-2007, Ext JS, LLC.
18798 * Originally Released Under LGPL - original licence link has changed is not relivant.
18801 * <script type="text/javascript">
18806 * A DragDrop implementation where the linked element follows the
18807 * mouse cursor during a drag.
18808 * @extends Roo.dd.DragDrop
18810 * @param {String} id the id of the linked element
18811 * @param {String} sGroup the group of related DragDrop items
18812 * @param {object} config an object containing configurable attributes
18813 * Valid properties for DD:
18816 Roo.dd.DD = function(id, sGroup, config) {
18818 this.init(id, sGroup, config);
18822 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18825 * When set to true, the utility automatically tries to scroll the browser
18826 * window wehn a drag and drop element is dragged near the viewport boundary.
18827 * Defaults to true.
18834 * Sets the pointer offset to the distance between the linked element's top
18835 * left corner and the location the element was clicked
18836 * @method autoOffset
18837 * @param {int} iPageX the X coordinate of the click
18838 * @param {int} iPageY the Y coordinate of the click
18840 autoOffset: function(iPageX, iPageY) {
18841 var x = iPageX - this.startPageX;
18842 var y = iPageY - this.startPageY;
18843 this.setDelta(x, y);
18847 * Sets the pointer offset. You can call this directly to force the
18848 * offset to be in a particular location (e.g., pass in 0,0 to set it
18849 * to the center of the object)
18851 * @param {int} iDeltaX the distance from the left
18852 * @param {int} iDeltaY the distance from the top
18854 setDelta: function(iDeltaX, iDeltaY) {
18855 this.deltaX = iDeltaX;
18856 this.deltaY = iDeltaY;
18860 * Sets the drag element to the location of the mousedown or click event,
18861 * maintaining the cursor location relative to the location on the element
18862 * that was clicked. Override this if you want to place the element in a
18863 * location other than where the cursor is.
18864 * @method setDragElPos
18865 * @param {int} iPageX the X coordinate of the mousedown or drag event
18866 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18868 setDragElPos: function(iPageX, iPageY) {
18869 // the first time we do this, we are going to check to make sure
18870 // the element has css positioning
18872 var el = this.getDragEl();
18873 this.alignElWithMouse(el, iPageX, iPageY);
18877 * Sets the element to the location of the mousedown or click event,
18878 * maintaining the cursor location relative to the location on the element
18879 * that was clicked. Override this if you want to place the element in a
18880 * location other than where the cursor is.
18881 * @method alignElWithMouse
18882 * @param {HTMLElement} el the element to move
18883 * @param {int} iPageX the X coordinate of the mousedown or drag event
18884 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18886 alignElWithMouse: function(el, iPageX, iPageY) {
18887 var oCoord = this.getTargetCoord(iPageX, iPageY);
18888 var fly = el.dom ? el : Roo.fly(el);
18889 if (!this.deltaSetXY) {
18890 var aCoord = [oCoord.x, oCoord.y];
18892 var newLeft = fly.getLeft(true);
18893 var newTop = fly.getTop(true);
18894 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18896 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18899 this.cachePosition(oCoord.x, oCoord.y);
18900 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18905 * Saves the most recent position so that we can reset the constraints and
18906 * tick marks on-demand. We need to know this so that we can calculate the
18907 * number of pixels the element is offset from its original position.
18908 * @method cachePosition
18909 * @param iPageX the current x position (optional, this just makes it so we
18910 * don't have to look it up again)
18911 * @param iPageY the current y position (optional, this just makes it so we
18912 * don't have to look it up again)
18914 cachePosition: function(iPageX, iPageY) {
18916 this.lastPageX = iPageX;
18917 this.lastPageY = iPageY;
18919 var aCoord = Roo.lib.Dom.getXY(this.getEl());
18920 this.lastPageX = aCoord[0];
18921 this.lastPageY = aCoord[1];
18926 * Auto-scroll the window if the dragged object has been moved beyond the
18927 * visible window boundary.
18928 * @method autoScroll
18929 * @param {int} x the drag element's x position
18930 * @param {int} y the drag element's y position
18931 * @param {int} h the height of the drag element
18932 * @param {int} w the width of the drag element
18935 autoScroll: function(x, y, h, w) {
18938 // The client height
18939 var clientH = Roo.lib.Dom.getViewWidth();
18941 // The client width
18942 var clientW = Roo.lib.Dom.getViewHeight();
18944 // The amt scrolled down
18945 var st = this.DDM.getScrollTop();
18947 // The amt scrolled right
18948 var sl = this.DDM.getScrollLeft();
18950 // Location of the bottom of the element
18953 // Location of the right of the element
18956 // The distance from the cursor to the bottom of the visible area,
18957 // adjusted so that we don't scroll if the cursor is beyond the
18958 // element drag constraints
18959 var toBot = (clientH + st - y - this.deltaY);
18961 // The distance from the cursor to the right of the visible area
18962 var toRight = (clientW + sl - x - this.deltaX);
18965 // How close to the edge the cursor must be before we scroll
18966 // var thresh = (document.all) ? 100 : 40;
18969 // How many pixels to scroll per autoscroll op. This helps to reduce
18970 // clunky scrolling. IE is more sensitive about this ... it needs this
18971 // value to be higher.
18972 var scrAmt = (document.all) ? 80 : 30;
18974 // Scroll down if we are near the bottom of the visible page and the
18975 // obj extends below the crease
18976 if ( bot > clientH && toBot < thresh ) {
18977 window.scrollTo(sl, st + scrAmt);
18980 // Scroll up if the window is scrolled down and the top of the object
18981 // goes above the top border
18982 if ( y < st && st > 0 && y - st < thresh ) {
18983 window.scrollTo(sl, st - scrAmt);
18986 // Scroll right if the obj is beyond the right border and the cursor is
18987 // near the border.
18988 if ( right > clientW && toRight < thresh ) {
18989 window.scrollTo(sl + scrAmt, st);
18992 // Scroll left if the window has been scrolled to the right and the obj
18993 // extends past the left border
18994 if ( x < sl && sl > 0 && x - sl < thresh ) {
18995 window.scrollTo(sl - scrAmt, st);
19001 * Finds the location the element should be placed if we want to move
19002 * it to where the mouse location less the click offset would place us.
19003 * @method getTargetCoord
19004 * @param {int} iPageX the X coordinate of the click
19005 * @param {int} iPageY the Y coordinate of the click
19006 * @return an object that contains the coordinates (Object.x and Object.y)
19009 getTargetCoord: function(iPageX, iPageY) {
19012 var x = iPageX - this.deltaX;
19013 var y = iPageY - this.deltaY;
19015 if (this.constrainX) {
19016 if (x < this.minX) { x = this.minX; }
19017 if (x > this.maxX) { x = this.maxX; }
19020 if (this.constrainY) {
19021 if (y < this.minY) { y = this.minY; }
19022 if (y > this.maxY) { y = this.maxY; }
19025 x = this.getTick(x, this.xTicks);
19026 y = this.getTick(y, this.yTicks);
19033 * Sets up config options specific to this class. Overrides
19034 * Roo.dd.DragDrop, but all versions of this method through the
19035 * inheritance chain are called
19037 applyConfig: function() {
19038 Roo.dd.DD.superclass.applyConfig.call(this);
19039 this.scroll = (this.config.scroll !== false);
19043 * Event that fires prior to the onMouseDown event. Overrides
19046 b4MouseDown: function(e) {
19047 // this.resetConstraints();
19048 this.autoOffset(e.getPageX(),
19053 * Event that fires prior to the onDrag event. Overrides
19056 b4Drag: function(e) {
19057 this.setDragElPos(e.getPageX(),
19061 toString: function() {
19062 return ("DD " + this.id);
19065 //////////////////////////////////////////////////////////////////////////
19066 // Debugging ygDragDrop events that can be overridden
19067 //////////////////////////////////////////////////////////////////////////
19069 startDrag: function(x, y) {
19072 onDrag: function(e) {
19075 onDragEnter: function(e, id) {
19078 onDragOver: function(e, id) {
19081 onDragOut: function(e, id) {
19084 onDragDrop: function(e, id) {
19087 endDrag: function(e) {
19094 * Ext JS Library 1.1.1
19095 * Copyright(c) 2006-2007, Ext JS, LLC.
19097 * Originally Released Under LGPL - original licence link has changed is not relivant.
19100 * <script type="text/javascript">
19104 * @class Roo.dd.DDProxy
19105 * A DragDrop implementation that inserts an empty, bordered div into
19106 * the document that follows the cursor during drag operations. At the time of
19107 * the click, the frame div is resized to the dimensions of the linked html
19108 * element, and moved to the exact location of the linked element.
19110 * References to the "frame" element refer to the single proxy element that
19111 * was created to be dragged in place of all DDProxy elements on the
19114 * @extends Roo.dd.DD
19116 * @param {String} id the id of the linked html element
19117 * @param {String} sGroup the group of related DragDrop objects
19118 * @param {object} config an object containing configurable attributes
19119 * Valid properties for DDProxy in addition to those in DragDrop:
19120 * resizeFrame, centerFrame, dragElId
19122 Roo.dd.DDProxy = function(id, sGroup, config) {
19124 this.init(id, sGroup, config);
19130 * The default drag frame div id
19131 * @property Roo.dd.DDProxy.dragElId
19135 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19137 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19140 * By default we resize the drag frame to be the same size as the element
19141 * we want to drag (this is to get the frame effect). We can turn it off
19142 * if we want a different behavior.
19143 * @property resizeFrame
19149 * By default the frame is positioned exactly where the drag element is, so
19150 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19151 * you do not have constraints on the obj is to have the drag frame centered
19152 * around the cursor. Set centerFrame to true for this effect.
19153 * @property centerFrame
19156 centerFrame: false,
19159 * Creates the proxy element if it does not yet exist
19160 * @method createFrame
19162 createFrame: function() {
19164 var body = document.body;
19166 if (!body || !body.firstChild) {
19167 setTimeout( function() { self.createFrame(); }, 50 );
19171 var div = this.getDragEl();
19174 div = document.createElement("div");
19175 div.id = this.dragElId;
19178 s.position = "absolute";
19179 s.visibility = "hidden";
19181 s.border = "2px solid #aaa";
19184 // appendChild can blow up IE if invoked prior to the window load event
19185 // while rendering a table. It is possible there are other scenarios
19186 // that would cause this to happen as well.
19187 body.insertBefore(div, body.firstChild);
19192 * Initialization for the drag frame element. Must be called in the
19193 * constructor of all subclasses
19194 * @method initFrame
19196 initFrame: function() {
19197 this.createFrame();
19200 applyConfig: function() {
19201 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19203 this.resizeFrame = (this.config.resizeFrame !== false);
19204 this.centerFrame = (this.config.centerFrame);
19205 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19209 * Resizes the drag frame to the dimensions of the clicked object, positions
19210 * it over the object, and finally displays it
19211 * @method showFrame
19212 * @param {int} iPageX X click position
19213 * @param {int} iPageY Y click position
19216 showFrame: function(iPageX, iPageY) {
19217 var el = this.getEl();
19218 var dragEl = this.getDragEl();
19219 var s = dragEl.style;
19221 this._resizeProxy();
19223 if (this.centerFrame) {
19224 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19225 Math.round(parseInt(s.height, 10)/2) );
19228 this.setDragElPos(iPageX, iPageY);
19230 Roo.fly(dragEl).show();
19234 * The proxy is automatically resized to the dimensions of the linked
19235 * element when a drag is initiated, unless resizeFrame is set to false
19236 * @method _resizeProxy
19239 _resizeProxy: function() {
19240 if (this.resizeFrame) {
19241 var el = this.getEl();
19242 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19246 // overrides Roo.dd.DragDrop
19247 b4MouseDown: function(e) {
19248 var x = e.getPageX();
19249 var y = e.getPageY();
19250 this.autoOffset(x, y);
19251 this.setDragElPos(x, y);
19254 // overrides Roo.dd.DragDrop
19255 b4StartDrag: function(x, y) {
19256 // show the drag frame
19257 this.showFrame(x, y);
19260 // overrides Roo.dd.DragDrop
19261 b4EndDrag: function(e) {
19262 Roo.fly(this.getDragEl()).hide();
19265 // overrides Roo.dd.DragDrop
19266 // By default we try to move the element to the last location of the frame.
19267 // This is so that the default behavior mirrors that of Roo.dd.DD.
19268 endDrag: function(e) {
19270 var lel = this.getEl();
19271 var del = this.getDragEl();
19273 // Show the drag frame briefly so we can get its position
19274 del.style.visibility = "";
19277 // Hide the linked element before the move to get around a Safari
19279 lel.style.visibility = "hidden";
19280 Roo.dd.DDM.moveToEl(lel, del);
19281 del.style.visibility = "hidden";
19282 lel.style.visibility = "";
19287 beforeMove : function(){
19291 afterDrag : function(){
19295 toString: function() {
19296 return ("DDProxy " + this.id);
19302 * Ext JS Library 1.1.1
19303 * Copyright(c) 2006-2007, Ext JS, LLC.
19305 * Originally Released Under LGPL - original licence link has changed is not relivant.
19308 * <script type="text/javascript">
19312 * @class Roo.dd.DDTarget
19313 * A DragDrop implementation that does not move, but can be a drop
19314 * target. You would get the same result by simply omitting implementation
19315 * for the event callbacks, but this way we reduce the processing cost of the
19316 * event listener and the callbacks.
19317 * @extends Roo.dd.DragDrop
19319 * @param {String} id the id of the element that is a drop target
19320 * @param {String} sGroup the group of related DragDrop objects
19321 * @param {object} config an object containing configurable attributes
19322 * Valid properties for DDTarget in addition to those in
19326 Roo.dd.DDTarget = function(id, sGroup, config) {
19328 this.initTarget(id, sGroup, config);
19330 if (config.listeners || config.events) {
19331 Roo.dd.DragDrop.superclass.constructor.call(this, {
19332 listeners : config.listeners || {},
19333 events : config.events || {}
19338 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19339 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19340 toString: function() {
19341 return ("DDTarget " + this.id);
19346 * Ext JS Library 1.1.1
19347 * Copyright(c) 2006-2007, Ext JS, LLC.
19349 * Originally Released Under LGPL - original licence link has changed is not relivant.
19352 * <script type="text/javascript">
19357 * @class Roo.dd.ScrollManager
19358 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19359 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19362 Roo.dd.ScrollManager = function(){
19363 var ddm = Roo.dd.DragDropMgr;
19370 var onStop = function(e){
19375 var triggerRefresh = function(){
19376 if(ddm.dragCurrent){
19377 ddm.refreshCache(ddm.dragCurrent.groups);
19381 var doScroll = function(){
19382 if(ddm.dragCurrent){
19383 var dds = Roo.dd.ScrollManager;
19385 if(proc.el.scroll(proc.dir, dds.increment)){
19389 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19394 var clearProc = function(){
19396 clearInterval(proc.id);
19403 var startProc = function(el, dir){
19404 Roo.log('scroll startproc');
19408 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19411 var onFire = function(e, isDrop){
19413 if(isDrop || !ddm.dragCurrent){ return; }
19414 var dds = Roo.dd.ScrollManager;
19415 if(!dragEl || dragEl != ddm.dragCurrent){
19416 dragEl = ddm.dragCurrent;
19417 // refresh regions on drag start
19418 dds.refreshCache();
19421 var xy = Roo.lib.Event.getXY(e);
19422 var pt = new Roo.lib.Point(xy[0], xy[1]);
19423 for(var id in els){
19424 var el = els[id], r = el._region;
19425 if(r && r.contains(pt) && el.isScrollable()){
19426 if(r.bottom - pt.y <= dds.thresh){
19428 startProc(el, "down");
19431 }else if(r.right - pt.x <= dds.thresh){
19433 startProc(el, "left");
19436 }else if(pt.y - r.top <= dds.thresh){
19438 startProc(el, "up");
19441 }else if(pt.x - r.left <= dds.thresh){
19443 startProc(el, "right");
19452 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19453 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19457 * Registers new overflow element(s) to auto scroll
19458 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19460 register : function(el){
19461 if(el instanceof Array){
19462 for(var i = 0, len = el.length; i < len; i++) {
19463 this.register(el[i]);
19469 Roo.dd.ScrollManager.els = els;
19473 * Unregisters overflow element(s) so they are no longer scrolled
19474 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19476 unregister : function(el){
19477 if(el instanceof Array){
19478 for(var i = 0, len = el.length; i < len; i++) {
19479 this.unregister(el[i]);
19488 * The number of pixels from the edge of a container the pointer needs to be to
19489 * trigger scrolling (defaults to 25)
19495 * The number of pixels to scroll in each scroll increment (defaults to 50)
19501 * The frequency of scrolls in milliseconds (defaults to 500)
19507 * True to animate the scroll (defaults to true)
19513 * The animation duration in seconds -
19514 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19520 * Manually trigger a cache refresh.
19522 refreshCache : function(){
19523 for(var id in els){
19524 if(typeof els[id] == 'object'){ // for people extending the object prototype
19525 els[id]._region = els[id].getRegion();
19532 * Ext JS Library 1.1.1
19533 * Copyright(c) 2006-2007, Ext JS, LLC.
19535 * Originally Released Under LGPL - original licence link has changed is not relivant.
19538 * <script type="text/javascript">
19543 * @class Roo.dd.Registry
19544 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19545 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19548 Roo.dd.Registry = function(){
19551 var autoIdSeed = 0;
19553 var getId = function(el, autogen){
19554 if(typeof el == "string"){
19558 if(!id && autogen !== false){
19559 id = "roodd-" + (++autoIdSeed);
19567 * Register a drag drop element
19568 * @param {String|HTMLElement} element The id or DOM node to register
19569 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19570 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19571 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19572 * populated in the data object (if applicable):
19574 Value Description<br />
19575 --------- ------------------------------------------<br />
19576 handles Array of DOM nodes that trigger dragging<br />
19577 for the element being registered<br />
19578 isHandle True if the element passed in triggers<br />
19579 dragging itself, else false
19582 register : function(el, data){
19584 if(typeof el == "string"){
19585 el = document.getElementById(el);
19588 elements[getId(el)] = data;
19589 if(data.isHandle !== false){
19590 handles[data.ddel.id] = data;
19593 var hs = data.handles;
19594 for(var i = 0, len = hs.length; i < len; i++){
19595 handles[getId(hs[i])] = data;
19601 * Unregister a drag drop element
19602 * @param {String|HTMLElement} element The id or DOM node to unregister
19604 unregister : function(el){
19605 var id = getId(el, false);
19606 var data = elements[id];
19608 delete elements[id];
19610 var hs = data.handles;
19611 for(var i = 0, len = hs.length; i < len; i++){
19612 delete handles[getId(hs[i], false)];
19619 * Returns the handle registered for a DOM Node by id
19620 * @param {String|HTMLElement} id The DOM node or id to look up
19621 * @return {Object} handle The custom handle data
19623 getHandle : function(id){
19624 if(typeof id != "string"){ // must be element?
19627 return handles[id];
19631 * Returns the handle that is registered for the DOM node that is the target of the event
19632 * @param {Event} e The event
19633 * @return {Object} handle The custom handle data
19635 getHandleFromEvent : function(e){
19636 var t = Roo.lib.Event.getTarget(e);
19637 return t ? handles[t.id] : null;
19641 * Returns a custom data object that is registered for a DOM node by id
19642 * @param {String|HTMLElement} id The DOM node or id to look up
19643 * @return {Object} data The custom data
19645 getTarget : function(id){
19646 if(typeof id != "string"){ // must be element?
19649 return elements[id];
19653 * Returns a custom data object that is registered for the DOM node that is the target of the event
19654 * @param {Event} e The event
19655 * @return {Object} data The custom data
19657 getTargetFromEvent : function(e){
19658 var t = Roo.lib.Event.getTarget(e);
19659 return t ? elements[t.id] || handles[t.id] : null;
19664 * Ext JS Library 1.1.1
19665 * Copyright(c) 2006-2007, Ext JS, LLC.
19667 * Originally Released Under LGPL - original licence link has changed is not relivant.
19670 * <script type="text/javascript">
19675 * @class Roo.dd.StatusProxy
19676 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19677 * default drag proxy used by all Roo.dd components.
19679 * @param {Object} config
19681 Roo.dd.StatusProxy = function(config){
19682 Roo.apply(this, config);
19683 this.id = this.id || Roo.id();
19684 this.el = new Roo.Layer({
19686 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19687 {tag: "div", cls: "x-dd-drop-icon"},
19688 {tag: "div", cls: "x-dd-drag-ghost"}
19691 shadow: !config || config.shadow !== false
19693 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19694 this.dropStatus = this.dropNotAllowed;
19697 Roo.dd.StatusProxy.prototype = {
19699 * @cfg {String} dropAllowed
19700 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19702 dropAllowed : "x-dd-drop-ok",
19704 * @cfg {String} dropNotAllowed
19705 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19707 dropNotAllowed : "x-dd-drop-nodrop",
19710 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19711 * over the current target element.
19712 * @param {String} cssClass The css class for the new drop status indicator image
19714 setStatus : function(cssClass){
19715 cssClass = cssClass || this.dropNotAllowed;
19716 if(this.dropStatus != cssClass){
19717 this.el.replaceClass(this.dropStatus, cssClass);
19718 this.dropStatus = cssClass;
19723 * Resets the status indicator to the default dropNotAllowed value
19724 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19726 reset : function(clearGhost){
19727 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19728 this.dropStatus = this.dropNotAllowed;
19730 this.ghost.update("");
19735 * Updates the contents of the ghost element
19736 * @param {String} html The html that will replace the current innerHTML of the ghost element
19738 update : function(html){
19739 if(typeof html == "string"){
19740 this.ghost.update(html);
19742 this.ghost.update("");
19743 html.style.margin = "0";
19744 this.ghost.dom.appendChild(html);
19746 // ensure float = none set?? cant remember why though.
19747 var el = this.ghost.dom.firstChild;
19749 Roo.fly(el).setStyle('float', 'none');
19754 * Returns the underlying proxy {@link Roo.Layer}
19755 * @return {Roo.Layer} el
19757 getEl : function(){
19762 * Returns the ghost element
19763 * @return {Roo.Element} el
19765 getGhost : function(){
19771 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19773 hide : function(clear){
19781 * Stops the repair animation if it's currently running
19784 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19790 * Displays this proxy
19797 * Force the Layer to sync its shadow and shim positions to the element
19804 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19805 * invalid drop operation by the item being dragged.
19806 * @param {Array} xy The XY position of the element ([x, y])
19807 * @param {Function} callback The function to call after the repair is complete
19808 * @param {Object} scope The scope in which to execute the callback
19810 repair : function(xy, callback, scope){
19811 this.callback = callback;
19812 this.scope = scope;
19813 if(xy && this.animRepair !== false){
19814 this.el.addClass("x-dd-drag-repair");
19815 this.el.hideUnders(true);
19816 this.anim = this.el.shift({
19817 duration: this.repairDuration || .5,
19821 callback: this.afterRepair,
19825 this.afterRepair();
19830 afterRepair : function(){
19832 if(typeof this.callback == "function"){
19833 this.callback.call(this.scope || this);
19835 this.callback = null;
19840 * Ext JS Library 1.1.1
19841 * Copyright(c) 2006-2007, Ext JS, LLC.
19843 * Originally Released Under LGPL - original licence link has changed is not relivant.
19846 * <script type="text/javascript">
19850 * @class Roo.dd.DragSource
19851 * @extends Roo.dd.DDProxy
19852 * A simple class that provides the basic implementation needed to make any element draggable.
19854 * @param {String/HTMLElement/Element} el The container element
19855 * @param {Object} config
19857 Roo.dd.DragSource = function(el, config){
19858 this.el = Roo.get(el);
19859 this.dragData = {};
19861 Roo.apply(this, config);
19864 this.proxy = new Roo.dd.StatusProxy();
19867 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19868 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19870 this.dragging = false;
19873 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19875 * @cfg {String} dropAllowed
19876 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19878 dropAllowed : "x-dd-drop-ok",
19880 * @cfg {String} dropNotAllowed
19881 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19883 dropNotAllowed : "x-dd-drop-nodrop",
19886 * Returns the data object associated with this drag source
19887 * @return {Object} data An object containing arbitrary data
19889 getDragData : function(e){
19890 return this.dragData;
19894 onDragEnter : function(e, id){
19895 var target = Roo.dd.DragDropMgr.getDDById(id);
19896 this.cachedTarget = target;
19897 if(this.beforeDragEnter(target, e, id) !== false){
19898 if(target.isNotifyTarget){
19899 var status = target.notifyEnter(this, e, this.dragData);
19900 this.proxy.setStatus(status);
19902 this.proxy.setStatus(this.dropAllowed);
19905 if(this.afterDragEnter){
19907 * An empty function by default, but provided so that you can perform a custom action
19908 * when the dragged item enters the drop target by providing an implementation.
19909 * @param {Roo.dd.DragDrop} target The drop target
19910 * @param {Event} e The event object
19911 * @param {String} id The id of the dragged element
19912 * @method afterDragEnter
19914 this.afterDragEnter(target, e, id);
19920 * An empty function by default, but provided so that you can perform a custom action
19921 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
19922 * @param {Roo.dd.DragDrop} target The drop target
19923 * @param {Event} e The event object
19924 * @param {String} id The id of the dragged element
19925 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19927 beforeDragEnter : function(target, e, id){
19932 alignElWithMouse: function() {
19933 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
19938 onDragOver : function(e, id){
19939 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19940 if(this.beforeDragOver(target, e, id) !== false){
19941 if(target.isNotifyTarget){
19942 var status = target.notifyOver(this, e, this.dragData);
19943 this.proxy.setStatus(status);
19946 if(this.afterDragOver){
19948 * An empty function by default, but provided so that you can perform a custom action
19949 * while the dragged item is over the drop target by providing an implementation.
19950 * @param {Roo.dd.DragDrop} target The drop target
19951 * @param {Event} e The event object
19952 * @param {String} id The id of the dragged element
19953 * @method afterDragOver
19955 this.afterDragOver(target, e, id);
19961 * An empty function by default, but provided so that you can perform a custom action
19962 * while the dragged item is over the drop target and optionally cancel the onDragOver.
19963 * @param {Roo.dd.DragDrop} target The drop target
19964 * @param {Event} e The event object
19965 * @param {String} id The id of the dragged element
19966 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19968 beforeDragOver : function(target, e, id){
19973 onDragOut : function(e, id){
19974 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19975 if(this.beforeDragOut(target, e, id) !== false){
19976 if(target.isNotifyTarget){
19977 target.notifyOut(this, e, this.dragData);
19979 this.proxy.reset();
19980 if(this.afterDragOut){
19982 * An empty function by default, but provided so that you can perform a custom action
19983 * after the dragged item is dragged out of the target without dropping.
19984 * @param {Roo.dd.DragDrop} target The drop target
19985 * @param {Event} e The event object
19986 * @param {String} id The id of the dragged element
19987 * @method afterDragOut
19989 this.afterDragOut(target, e, id);
19992 this.cachedTarget = null;
19996 * An empty function by default, but provided so that you can perform a custom action before the dragged
19997 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
19998 * @param {Roo.dd.DragDrop} target The drop target
19999 * @param {Event} e The event object
20000 * @param {String} id The id of the dragged element
20001 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20003 beforeDragOut : function(target, e, id){
20008 onDragDrop : function(e, id){
20009 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20010 if(this.beforeDragDrop(target, e, id) !== false){
20011 if(target.isNotifyTarget){
20012 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20013 this.onValidDrop(target, e, id);
20015 this.onInvalidDrop(target, e, id);
20018 this.onValidDrop(target, e, id);
20021 if(this.afterDragDrop){
20023 * An empty function by default, but provided so that you can perform a custom action
20024 * after a valid drag drop has occurred by providing an implementation.
20025 * @param {Roo.dd.DragDrop} target The drop target
20026 * @param {Event} e The event object
20027 * @param {String} id The id of the dropped element
20028 * @method afterDragDrop
20030 this.afterDragDrop(target, e, id);
20033 delete this.cachedTarget;
20037 * An empty function by default, but provided so that you can perform a custom action before the dragged
20038 * item is dropped onto the target and optionally cancel the onDragDrop.
20039 * @param {Roo.dd.DragDrop} target The drop target
20040 * @param {Event} e The event object
20041 * @param {String} id The id of the dragged element
20042 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20044 beforeDragDrop : function(target, e, id){
20049 onValidDrop : function(target, e, id){
20051 if(this.afterValidDrop){
20053 * An empty function by default, but provided so that you can perform a custom action
20054 * after a valid drop has occurred by providing an implementation.
20055 * @param {Object} target The target DD
20056 * @param {Event} e The event object
20057 * @param {String} id The id of the dropped element
20058 * @method afterInvalidDrop
20060 this.afterValidDrop(target, e, id);
20065 getRepairXY : function(e, data){
20066 return this.el.getXY();
20070 onInvalidDrop : function(target, e, id){
20071 this.beforeInvalidDrop(target, e, id);
20072 if(this.cachedTarget){
20073 if(this.cachedTarget.isNotifyTarget){
20074 this.cachedTarget.notifyOut(this, e, this.dragData);
20076 this.cacheTarget = null;
20078 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20080 if(this.afterInvalidDrop){
20082 * An empty function by default, but provided so that you can perform a custom action
20083 * after an invalid drop has occurred by providing an implementation.
20084 * @param {Event} e The event object
20085 * @param {String} id The id of the dropped element
20086 * @method afterInvalidDrop
20088 this.afterInvalidDrop(e, id);
20093 afterRepair : function(){
20095 this.el.highlight(this.hlColor || "c3daf9");
20097 this.dragging = false;
20101 * An empty function by default, but provided so that you can perform a custom action after an invalid
20102 * drop has occurred.
20103 * @param {Roo.dd.DragDrop} target The drop target
20104 * @param {Event} e The event object
20105 * @param {String} id The id of the dragged element
20106 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20108 beforeInvalidDrop : function(target, e, id){
20113 handleMouseDown : function(e){
20114 if(this.dragging) {
20117 var data = this.getDragData(e);
20118 if(data && this.onBeforeDrag(data, e) !== false){
20119 this.dragData = data;
20121 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20126 * An empty function by default, but provided so that you can perform a custom action before the initial
20127 * drag event begins and optionally cancel it.
20128 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20129 * @param {Event} e The event object
20130 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20132 onBeforeDrag : function(data, e){
20137 * An empty function by default, but provided so that you can perform a custom action once the initial
20138 * drag event has begun. The drag cannot be canceled from this function.
20139 * @param {Number} x The x position of the click on the dragged object
20140 * @param {Number} y The y position of the click on the dragged object
20142 onStartDrag : Roo.emptyFn,
20144 // private - YUI override
20145 startDrag : function(x, y){
20146 this.proxy.reset();
20147 this.dragging = true;
20148 this.proxy.update("");
20149 this.onInitDrag(x, y);
20154 onInitDrag : function(x, y){
20155 var clone = this.el.dom.cloneNode(true);
20156 clone.id = Roo.id(); // prevent duplicate ids
20157 this.proxy.update(clone);
20158 this.onStartDrag(x, y);
20163 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20164 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20166 getProxy : function(){
20171 * Hides the drag source's {@link Roo.dd.StatusProxy}
20173 hideProxy : function(){
20175 this.proxy.reset(true);
20176 this.dragging = false;
20180 triggerCacheRefresh : function(){
20181 Roo.dd.DDM.refreshCache(this.groups);
20184 // private - override to prevent hiding
20185 b4EndDrag: function(e) {
20188 // private - override to prevent moving
20189 endDrag : function(e){
20190 this.onEndDrag(this.dragData, e);
20194 onEndDrag : function(data, e){
20197 // private - pin to cursor
20198 autoOffset : function(x, y) {
20199 this.setDelta(-12, -20);
20203 * Ext JS Library 1.1.1
20204 * Copyright(c) 2006-2007, Ext JS, LLC.
20206 * Originally Released Under LGPL - original licence link has changed is not relivant.
20209 * <script type="text/javascript">
20214 * @class Roo.dd.DropTarget
20215 * @extends Roo.dd.DDTarget
20216 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20217 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20219 * @param {String/HTMLElement/Element} el The container element
20220 * @param {Object} config
20222 Roo.dd.DropTarget = function(el, config){
20223 this.el = Roo.get(el);
20225 var listeners = false; ;
20226 if (config && config.listeners) {
20227 listeners= config.listeners;
20228 delete config.listeners;
20230 Roo.apply(this, config);
20232 if(this.containerScroll){
20233 Roo.dd.ScrollManager.register(this.el);
20237 * @scope Roo.dd.DropTarget
20242 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20243 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20244 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20246 * IMPORTANT : it should set this.overClass and this.dropAllowed
20248 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20249 * @param {Event} e The event
20250 * @param {Object} data An object containing arbitrary data supplied by the drag source
20256 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20257 * This method will be called on every mouse movement while the drag source is over the drop target.
20258 * This default implementation simply returns the dropAllowed config value.
20260 * IMPORTANT : it should set this.dropAllowed
20262 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20263 * @param {Event} e The event
20264 * @param {Object} data An object containing arbitrary data supplied by the drag source
20270 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20271 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20272 * overClass (if any) from the drop element.
20274 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20275 * @param {Event} e The event
20276 * @param {Object} data An object containing arbitrary data supplied by the drag source
20282 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20283 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20284 * implementation that does something to process the drop event and returns true so that the drag source's
20285 * repair action does not run.
20287 * IMPORTANT : it should set this.success
20289 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20290 * @param {Event} e The event
20291 * @param {Object} data An object containing arbitrary data supplied by the drag source
20297 Roo.dd.DropTarget.superclass.constructor.call( this,
20299 this.ddGroup || this.group,
20302 listeners : listeners || {}
20310 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20312 * @cfg {String} overClass
20313 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20316 * @cfg {String} ddGroup
20317 * The drag drop group to handle drop events for
20321 * @cfg {String} dropAllowed
20322 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20324 dropAllowed : "x-dd-drop-ok",
20326 * @cfg {String} dropNotAllowed
20327 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20329 dropNotAllowed : "x-dd-drop-nodrop",
20331 * @cfg {boolean} success
20332 * set this after drop listener..
20336 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20337 * if the drop point is valid for over/enter..
20344 isNotifyTarget : true,
20349 notifyEnter : function(dd, e, data)
20352 this.fireEvent('enter', dd, e, data);
20353 if(this.overClass){
20354 this.el.addClass(this.overClass);
20356 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20357 this.valid ? this.dropAllowed : this.dropNotAllowed
20364 notifyOver : function(dd, e, data)
20367 this.fireEvent('over', dd, e, data);
20368 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20369 this.valid ? this.dropAllowed : this.dropNotAllowed
20376 notifyOut : function(dd, e, data)
20378 this.fireEvent('out', dd, e, data);
20379 if(this.overClass){
20380 this.el.removeClass(this.overClass);
20387 notifyDrop : function(dd, e, data)
20389 this.success = false;
20390 this.fireEvent('drop', dd, e, data);
20391 return this.success;
20395 * Ext JS Library 1.1.1
20396 * Copyright(c) 2006-2007, Ext JS, LLC.
20398 * Originally Released Under LGPL - original licence link has changed is not relivant.
20401 * <script type="text/javascript">
20406 * @class Roo.dd.DragZone
20407 * @extends Roo.dd.DragSource
20408 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20409 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20411 * @param {String/HTMLElement/Element} el The container element
20412 * @param {Object} config
20414 Roo.dd.DragZone = function(el, config){
20415 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20416 if(this.containerScroll){
20417 Roo.dd.ScrollManager.register(this.el);
20421 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20423 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20424 * for auto scrolling during drag operations.
20427 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20428 * method after a failed drop (defaults to "c3daf9" - light blue)
20432 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20433 * for a valid target to drag based on the mouse down. Override this method
20434 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20435 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20436 * @param {EventObject} e The mouse down event
20437 * @return {Object} The dragData
20439 getDragData : function(e){
20440 return Roo.dd.Registry.getHandleFromEvent(e);
20444 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20445 * this.dragData.ddel
20446 * @param {Number} x The x position of the click on the dragged object
20447 * @param {Number} y The y position of the click on the dragged object
20448 * @return {Boolean} true to continue the drag, false to cancel
20450 onInitDrag : function(x, y){
20451 this.proxy.update(this.dragData.ddel.cloneNode(true));
20452 this.onStartDrag(x, y);
20457 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20459 afterRepair : function(){
20461 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20463 this.dragging = false;
20467 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20468 * the XY of this.dragData.ddel
20469 * @param {EventObject} e The mouse up event
20470 * @return {Array} The xy location (e.g. [100, 200])
20472 getRepairXY : function(e){
20473 return Roo.Element.fly(this.dragData.ddel).getXY();
20477 * Ext JS Library 1.1.1
20478 * Copyright(c) 2006-2007, Ext JS, LLC.
20480 * Originally Released Under LGPL - original licence link has changed is not relivant.
20483 * <script type="text/javascript">
20486 * @class Roo.dd.DropZone
20487 * @extends Roo.dd.DropTarget
20488 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20489 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20491 * @param {String/HTMLElement/Element} el The container element
20492 * @param {Object} config
20494 Roo.dd.DropZone = function(el, config){
20495 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20498 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20500 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20501 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20502 * provide your own custom lookup.
20503 * @param {Event} e The event
20504 * @return {Object} data The custom data
20506 getTargetFromEvent : function(e){
20507 return Roo.dd.Registry.getTargetFromEvent(e);
20511 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20512 * that it has registered. This method has no default implementation and should be overridden to provide
20513 * node-specific processing if necessary.
20514 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20515 * {@link #getTargetFromEvent} for this node)
20516 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20517 * @param {Event} e The event
20518 * @param {Object} data An object containing arbitrary data supplied by the drag source
20520 onNodeEnter : function(n, dd, e, data){
20525 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20526 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20527 * overridden to provide the proper feedback.
20528 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20529 * {@link #getTargetFromEvent} for this node)
20530 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20531 * @param {Event} e The event
20532 * @param {Object} data An object containing arbitrary data supplied by the drag source
20533 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20534 * underlying {@link Roo.dd.StatusProxy} can be updated
20536 onNodeOver : function(n, dd, e, data){
20537 return this.dropAllowed;
20541 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20542 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20543 * node-specific processing if necessary.
20544 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20545 * {@link #getTargetFromEvent} for this node)
20546 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20547 * @param {Event} e The event
20548 * @param {Object} data An object containing arbitrary data supplied by the drag source
20550 onNodeOut : function(n, dd, e, data){
20555 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20556 * the drop node. The default implementation returns false, so it should be overridden to provide the
20557 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20558 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20559 * {@link #getTargetFromEvent} for this node)
20560 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20561 * @param {Event} e The event
20562 * @param {Object} data An object containing arbitrary data supplied by the drag source
20563 * @return {Boolean} True if the drop was valid, else false
20565 onNodeDrop : function(n, dd, e, data){
20570 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20571 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20572 * it should be overridden to provide the proper feedback if necessary.
20573 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20574 * @param {Event} e The event
20575 * @param {Object} data An object containing arbitrary data supplied by the drag source
20576 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20577 * underlying {@link Roo.dd.StatusProxy} can be updated
20579 onContainerOver : function(dd, e, data){
20580 return this.dropNotAllowed;
20584 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20585 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20586 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20587 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20588 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20589 * @param {Event} e The event
20590 * @param {Object} data An object containing arbitrary data supplied by the drag source
20591 * @return {Boolean} True if the drop was valid, else false
20593 onContainerDrop : function(dd, e, data){
20598 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20599 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20600 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20601 * you should override this method and provide a custom implementation.
20602 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20603 * @param {Event} e The event
20604 * @param {Object} data An object containing arbitrary data supplied by the drag source
20605 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20606 * underlying {@link Roo.dd.StatusProxy} can be updated
20608 notifyEnter : function(dd, e, data){
20609 return this.dropNotAllowed;
20613 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20614 * This method will be called on every mouse movement while the drag source is over the drop zone.
20615 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20616 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20617 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20618 * registered node, it will call {@link #onContainerOver}.
20619 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20620 * @param {Event} e The event
20621 * @param {Object} data An object containing arbitrary data supplied by the drag source
20622 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20623 * underlying {@link Roo.dd.StatusProxy} can be updated
20625 notifyOver : function(dd, e, data){
20626 var n = this.getTargetFromEvent(e);
20627 if(!n){ // not over valid drop target
20628 if(this.lastOverNode){
20629 this.onNodeOut(this.lastOverNode, dd, e, data);
20630 this.lastOverNode = null;
20632 return this.onContainerOver(dd, e, data);
20634 if(this.lastOverNode != n){
20635 if(this.lastOverNode){
20636 this.onNodeOut(this.lastOverNode, dd, e, data);
20638 this.onNodeEnter(n, dd, e, data);
20639 this.lastOverNode = n;
20641 return this.onNodeOver(n, dd, e, data);
20645 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20646 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20647 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20648 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20649 * @param {Event} e The event
20650 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20652 notifyOut : function(dd, e, data){
20653 if(this.lastOverNode){
20654 this.onNodeOut(this.lastOverNode, dd, e, data);
20655 this.lastOverNode = null;
20660 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20661 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20662 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20663 * otherwise it will call {@link #onContainerDrop}.
20664 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20665 * @param {Event} e The event
20666 * @param {Object} data An object containing arbitrary data supplied by the drag source
20667 * @return {Boolean} True if the drop was valid, else false
20669 notifyDrop : function(dd, e, data){
20670 if(this.lastOverNode){
20671 this.onNodeOut(this.lastOverNode, dd, e, data);
20672 this.lastOverNode = null;
20674 var n = this.getTargetFromEvent(e);
20676 this.onNodeDrop(n, dd, e, data) :
20677 this.onContainerDrop(dd, e, data);
20681 triggerCacheRefresh : function(){
20682 Roo.dd.DDM.refreshCache(this.groups);
20686 * Ext JS Library 1.1.1
20687 * Copyright(c) 2006-2007, Ext JS, LLC.
20689 * Originally Released Under LGPL - original licence link has changed is not relivant.
20692 * <script type="text/javascript">
20697 * @class Roo.data.SortTypes
20699 * Defines the default sorting (casting?) comparison functions used when sorting data.
20701 Roo.data.SortTypes = {
20703 * Default sort that does nothing
20704 * @param {Mixed} s The value being converted
20705 * @return {Mixed} The comparison value
20707 none : function(s){
20712 * The regular expression used to strip tags
20716 stripTagsRE : /<\/?[^>]+>/gi,
20719 * Strips all HTML tags to sort on text only
20720 * @param {Mixed} s The value being converted
20721 * @return {String} The comparison value
20723 asText : function(s){
20724 return String(s).replace(this.stripTagsRE, "");
20728 * Strips all HTML tags to sort on text only - Case insensitive
20729 * @param {Mixed} s The value being converted
20730 * @return {String} The comparison value
20732 asUCText : function(s){
20733 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20737 * Case insensitive string
20738 * @param {Mixed} s The value being converted
20739 * @return {String} The comparison value
20741 asUCString : function(s) {
20742 return String(s).toUpperCase();
20747 * @param {Mixed} s The value being converted
20748 * @return {Number} The comparison value
20750 asDate : function(s) {
20754 if(s instanceof Date){
20755 return s.getTime();
20757 return Date.parse(String(s));
20762 * @param {Mixed} s The value being converted
20763 * @return {Float} The comparison value
20765 asFloat : function(s) {
20766 var val = parseFloat(String(s).replace(/,/g, ""));
20767 if(isNaN(val)) val = 0;
20773 * @param {Mixed} s The value being converted
20774 * @return {Number} The comparison value
20776 asInt : function(s) {
20777 var val = parseInt(String(s).replace(/,/g, ""));
20778 if(isNaN(val)) val = 0;
20783 * Ext JS Library 1.1.1
20784 * Copyright(c) 2006-2007, Ext JS, LLC.
20786 * Originally Released Under LGPL - original licence link has changed is not relivant.
20789 * <script type="text/javascript">
20793 * @class Roo.data.Record
20794 * Instances of this class encapsulate both record <em>definition</em> information, and record
20795 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20796 * to access Records cached in an {@link Roo.data.Store} object.<br>
20798 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20799 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20802 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20804 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20805 * {@link #create}. The parameters are the same.
20806 * @param {Array} data An associative Array of data values keyed by the field name.
20807 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20808 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20809 * not specified an integer id is generated.
20811 Roo.data.Record = function(data, id){
20812 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20817 * Generate a constructor for a specific record layout.
20818 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20819 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20820 * Each field definition object may contain the following properties: <ul>
20821 * <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,
20822 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20823 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20824 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20825 * is being used, then this is a string containing the javascript expression to reference the data relative to
20826 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20827 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20828 * this may be omitted.</p></li>
20829 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20830 * <ul><li>auto (Default, implies no conversion)</li>
20835 * <li>date</li></ul></p></li>
20836 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20837 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20838 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20839 * by the Reader into an object that will be stored in the Record. It is passed the
20840 * following parameters:<ul>
20841 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20843 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20845 * <br>usage:<br><pre><code>
20846 var TopicRecord = Roo.data.Record.create(
20847 {name: 'title', mapping: 'topic_title'},
20848 {name: 'author', mapping: 'username'},
20849 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20850 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20851 {name: 'lastPoster', mapping: 'user2'},
20852 {name: 'excerpt', mapping: 'post_text'}
20855 var myNewRecord = new TopicRecord({
20856 title: 'Do my job please',
20859 lastPost: new Date(),
20860 lastPoster: 'Animal',
20861 excerpt: 'No way dude!'
20863 myStore.add(myNewRecord);
20868 Roo.data.Record.create = function(o){
20869 var f = function(){
20870 f.superclass.constructor.apply(this, arguments);
20872 Roo.extend(f, Roo.data.Record);
20873 var p = f.prototype;
20874 p.fields = new Roo.util.MixedCollection(false, function(field){
20877 for(var i = 0, len = o.length; i < len; i++){
20878 p.fields.add(new Roo.data.Field(o[i]));
20880 f.getField = function(name){
20881 return p.fields.get(name);
20886 Roo.data.Record.AUTO_ID = 1000;
20887 Roo.data.Record.EDIT = 'edit';
20888 Roo.data.Record.REJECT = 'reject';
20889 Roo.data.Record.COMMIT = 'commit';
20891 Roo.data.Record.prototype = {
20893 * Readonly flag - true if this record has been modified.
20902 join : function(store){
20903 this.store = store;
20907 * Set the named field to the specified value.
20908 * @param {String} name The name of the field to set.
20909 * @param {Object} value The value to set the field to.
20911 set : function(name, value){
20912 if(this.data[name] == value){
20916 if(!this.modified){
20917 this.modified = {};
20919 if(typeof this.modified[name] == 'undefined'){
20920 this.modified[name] = this.data[name];
20922 this.data[name] = value;
20923 if(!this.editing && this.store){
20924 this.store.afterEdit(this);
20929 * Get the value of the named field.
20930 * @param {String} name The name of the field to get the value of.
20931 * @return {Object} The value of the field.
20933 get : function(name){
20934 return this.data[name];
20938 beginEdit : function(){
20939 this.editing = true;
20940 this.modified = {};
20944 cancelEdit : function(){
20945 this.editing = false;
20946 delete this.modified;
20950 endEdit : function(){
20951 this.editing = false;
20952 if(this.dirty && this.store){
20953 this.store.afterEdit(this);
20958 * Usually called by the {@link Roo.data.Store} which owns the Record.
20959 * Rejects all changes made to the Record since either creation, or the last commit operation.
20960 * Modified fields are reverted to their original values.
20962 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20963 * of reject operations.
20965 reject : function(){
20966 var m = this.modified;
20968 if(typeof m[n] != "function"){
20969 this.data[n] = m[n];
20972 this.dirty = false;
20973 delete this.modified;
20974 this.editing = false;
20976 this.store.afterReject(this);
20981 * Usually called by the {@link Roo.data.Store} which owns the Record.
20982 * Commits all changes made to the Record since either creation, or the last commit operation.
20984 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20985 * of commit operations.
20987 commit : function(){
20988 this.dirty = false;
20989 delete this.modified;
20990 this.editing = false;
20992 this.store.afterCommit(this);
20997 hasError : function(){
20998 return this.error != null;
21002 clearError : function(){
21007 * Creates a copy of this record.
21008 * @param {String} id (optional) A new record id if you don't want to use this record's id
21011 copy : function(newId) {
21012 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21016 * Ext JS Library 1.1.1
21017 * Copyright(c) 2006-2007, Ext JS, LLC.
21019 * Originally Released Under LGPL - original licence link has changed is not relivant.
21022 * <script type="text/javascript">
21028 * @class Roo.data.Store
21029 * @extends Roo.util.Observable
21030 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21031 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21033 * 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
21034 * has no knowledge of the format of the data returned by the Proxy.<br>
21036 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21037 * instances from the data object. These records are cached and made available through accessor functions.
21039 * Creates a new Store.
21040 * @param {Object} config A config object containing the objects needed for the Store to access data,
21041 * and read the data into Records.
21043 Roo.data.Store = function(config){
21044 this.data = new Roo.util.MixedCollection(false);
21045 this.data.getKey = function(o){
21048 this.baseParams = {};
21050 this.paramNames = {
21055 "multisort" : "_multisort"
21058 if(config && config.data){
21059 this.inlineData = config.data;
21060 delete config.data;
21063 Roo.apply(this, config);
21065 if(this.reader){ // reader passed
21066 this.reader = Roo.factory(this.reader, Roo.data);
21067 this.reader.xmodule = this.xmodule || false;
21068 if(!this.recordType){
21069 this.recordType = this.reader.recordType;
21071 if(this.reader.onMetaChange){
21072 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21076 if(this.recordType){
21077 this.fields = this.recordType.prototype.fields;
21079 this.modified = [];
21083 * @event datachanged
21084 * Fires when the data cache has changed, and a widget which is using this Store
21085 * as a Record cache should refresh its view.
21086 * @param {Store} this
21088 datachanged : true,
21090 * @event metachange
21091 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21092 * @param {Store} this
21093 * @param {Object} meta The JSON metadata
21098 * Fires when Records have been added to the Store
21099 * @param {Store} this
21100 * @param {Roo.data.Record[]} records The array of Records added
21101 * @param {Number} index The index at which the record(s) were added
21106 * Fires when a Record has been removed from the Store
21107 * @param {Store} this
21108 * @param {Roo.data.Record} record The Record that was removed
21109 * @param {Number} index The index at which the record was removed
21114 * Fires when a Record has been updated
21115 * @param {Store} this
21116 * @param {Roo.data.Record} record The Record that was updated
21117 * @param {String} operation The update operation being performed. Value may be one of:
21119 Roo.data.Record.EDIT
21120 Roo.data.Record.REJECT
21121 Roo.data.Record.COMMIT
21127 * Fires when the data cache has been cleared.
21128 * @param {Store} this
21132 * @event beforeload
21133 * Fires before a request is made for a new data object. If the beforeload handler returns false
21134 * the load action will be canceled.
21135 * @param {Store} this
21136 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21140 * @event beforeloadadd
21141 * Fires after a new set of Records has been loaded.
21142 * @param {Store} this
21143 * @param {Roo.data.Record[]} records The Records that were loaded
21144 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21146 beforeloadadd : true,
21149 * Fires after a new set of Records has been loaded, before they are added to the store.
21150 * @param {Store} this
21151 * @param {Roo.data.Record[]} records The Records that were loaded
21152 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21153 * @params {Object} return from reader
21157 * @event loadexception
21158 * Fires if an exception occurs in the Proxy during loading.
21159 * Called with the signature of the Proxy's "loadexception" event.
21160 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21163 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21164 * @param {Object} load options
21165 * @param {Object} jsonData from your request (normally this contains the Exception)
21167 loadexception : true
21171 this.proxy = Roo.factory(this.proxy, Roo.data);
21172 this.proxy.xmodule = this.xmodule || false;
21173 this.relayEvents(this.proxy, ["loadexception"]);
21175 this.sortToggle = {};
21176 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21178 Roo.data.Store.superclass.constructor.call(this);
21180 if(this.inlineData){
21181 this.loadData(this.inlineData);
21182 delete this.inlineData;
21186 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21188 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21189 * without a remote query - used by combo/forms at present.
21193 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21196 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21199 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21200 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21203 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21204 * on any HTTP request
21207 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21210 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21214 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21215 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21217 remoteSort : false,
21220 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21221 * loaded or when a record is removed. (defaults to false).
21223 pruneModifiedRecords : false,
21226 lastOptions : null,
21229 * Add Records to the Store and fires the add event.
21230 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21232 add : function(records){
21233 records = [].concat(records);
21234 for(var i = 0, len = records.length; i < len; i++){
21235 records[i].join(this);
21237 var index = this.data.length;
21238 this.data.addAll(records);
21239 this.fireEvent("add", this, records, index);
21243 * Remove a Record from the Store and fires the remove event.
21244 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21246 remove : function(record){
21247 var index = this.data.indexOf(record);
21248 this.data.removeAt(index);
21249 if(this.pruneModifiedRecords){
21250 this.modified.remove(record);
21252 this.fireEvent("remove", this, record, index);
21256 * Remove all Records from the Store and fires the clear event.
21258 removeAll : function(){
21260 if(this.pruneModifiedRecords){
21261 this.modified = [];
21263 this.fireEvent("clear", this);
21267 * Inserts Records to the Store at the given index and fires the add event.
21268 * @param {Number} index The start index at which to insert the passed Records.
21269 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21271 insert : function(index, records){
21272 records = [].concat(records);
21273 for(var i = 0, len = records.length; i < len; i++){
21274 this.data.insert(index, records[i]);
21275 records[i].join(this);
21277 this.fireEvent("add", this, records, index);
21281 * Get the index within the cache of the passed Record.
21282 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21283 * @return {Number} The index of the passed Record. Returns -1 if not found.
21285 indexOf : function(record){
21286 return this.data.indexOf(record);
21290 * Get the index within the cache of the Record with the passed id.
21291 * @param {String} id The id of the Record to find.
21292 * @return {Number} The index of the Record. Returns -1 if not found.
21294 indexOfId : function(id){
21295 return this.data.indexOfKey(id);
21299 * Get the Record with the specified id.
21300 * @param {String} id The id of the Record to find.
21301 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21303 getById : function(id){
21304 return this.data.key(id);
21308 * Get the Record at the specified index.
21309 * @param {Number} index The index of the Record to find.
21310 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21312 getAt : function(index){
21313 return this.data.itemAt(index);
21317 * Returns a range of Records between specified indices.
21318 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21319 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21320 * @return {Roo.data.Record[]} An array of Records
21322 getRange : function(start, end){
21323 return this.data.getRange(start, end);
21327 storeOptions : function(o){
21328 o = Roo.apply({}, o);
21331 this.lastOptions = o;
21335 * Loads the Record cache from the configured Proxy using the configured Reader.
21337 * If using remote paging, then the first load call must specify the <em>start</em>
21338 * and <em>limit</em> properties in the options.params property to establish the initial
21339 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21341 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21342 * and this call will return before the new data has been loaded. Perform any post-processing
21343 * in a callback function, or in a "load" event handler.</strong>
21345 * @param {Object} options An object containing properties which control loading options:<ul>
21346 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21347 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21348 * passed the following arguments:<ul>
21349 * <li>r : Roo.data.Record[]</li>
21350 * <li>options: Options object from the load call</li>
21351 * <li>success: Boolean success indicator</li></ul></li>
21352 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21353 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21356 load : function(options){
21357 options = options || {};
21358 if(this.fireEvent("beforeload", this, options) !== false){
21359 this.storeOptions(options);
21360 var p = Roo.apply(options.params || {}, this.baseParams);
21361 // if meta was not loaded from remote source.. try requesting it.
21362 if (!this.reader.metaFromRemote) {
21363 p._requestMeta = 1;
21365 if(this.sortInfo && this.remoteSort){
21366 var pn = this.paramNames;
21367 p[pn["sort"]] = this.sortInfo.field;
21368 p[pn["dir"]] = this.sortInfo.direction;
21370 if (this.multiSort) {
21371 var pn = this.paramNames;
21372 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21375 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21380 * Reloads the Record cache from the configured Proxy using the configured Reader and
21381 * the options from the last load operation performed.
21382 * @param {Object} options (optional) An object containing properties which may override the options
21383 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21384 * the most recently used options are reused).
21386 reload : function(options){
21387 this.load(Roo.applyIf(options||{}, this.lastOptions));
21391 // Called as a callback by the Reader during a load operation.
21392 loadRecords : function(o, options, success){
21393 if(!o || success === false){
21394 if(success !== false){
21395 this.fireEvent("load", this, [], options, o);
21397 if(options.callback){
21398 options.callback.call(options.scope || this, [], options, false);
21402 // if data returned failure - throw an exception.
21403 if (o.success === false) {
21404 // show a message if no listener is registered.
21405 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21406 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21408 // loadmask wil be hooked into this..
21409 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21412 var r = o.records, t = o.totalRecords || r.length;
21414 this.fireEvent("beforeloadadd", this, r, options, o);
21416 if(!options || options.add !== true){
21417 if(this.pruneModifiedRecords){
21418 this.modified = [];
21420 for(var i = 0, len = r.length; i < len; i++){
21424 this.data = this.snapshot;
21425 delete this.snapshot;
21428 this.data.addAll(r);
21429 this.totalLength = t;
21431 this.fireEvent("datachanged", this);
21433 this.totalLength = Math.max(t, this.data.length+r.length);
21436 this.fireEvent("load", this, r, options, o);
21437 if(options.callback){
21438 options.callback.call(options.scope || this, r, options, true);
21444 * Loads data from a passed data block. A Reader which understands the format of the data
21445 * must have been configured in the constructor.
21446 * @param {Object} data The data block from which to read the Records. The format of the data expected
21447 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21448 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21450 loadData : function(o, append){
21451 var r = this.reader.readRecords(o);
21452 this.loadRecords(r, {add: append}, true);
21456 * Gets the number of cached records.
21458 * <em>If using paging, this may not be the total size of the dataset. If the data object
21459 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21460 * the data set size</em>
21462 getCount : function(){
21463 return this.data.length || 0;
21467 * Gets the total number of records in the dataset as returned by the server.
21469 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21470 * the dataset size</em>
21472 getTotalCount : function(){
21473 return this.totalLength || 0;
21477 * Returns the sort state of the Store as an object with two properties:
21479 field {String} The name of the field by which the Records are sorted
21480 direction {String} The sort order, "ASC" or "DESC"
21483 getSortState : function(){
21484 return this.sortInfo;
21488 applySort : function(){
21489 if(this.sortInfo && !this.remoteSort){
21490 var s = this.sortInfo, f = s.field;
21491 var st = this.fields.get(f).sortType;
21492 var fn = function(r1, r2){
21493 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21494 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21496 this.data.sort(s.direction, fn);
21497 if(this.snapshot && this.snapshot != this.data){
21498 this.snapshot.sort(s.direction, fn);
21504 * Sets the default sort column and order to be used by the next load operation.
21505 * @param {String} fieldName The name of the field to sort by.
21506 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21508 setDefaultSort : function(field, dir){
21509 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21513 * Sort the Records.
21514 * If remote sorting is used, the sort is performed on the server, and the cache is
21515 * reloaded. If local sorting is used, the cache is sorted internally.
21516 * @param {String} fieldName The name of the field to sort by.
21517 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21519 sort : function(fieldName, dir){
21520 var f = this.fields.get(fieldName);
21522 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21524 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21525 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21530 this.sortToggle[f.name] = dir;
21531 this.sortInfo = {field: f.name, direction: dir};
21532 if(!this.remoteSort){
21534 this.fireEvent("datachanged", this);
21536 this.load(this.lastOptions);
21541 * Calls the specified function for each of the Records in the cache.
21542 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21543 * Returning <em>false</em> aborts and exits the iteration.
21544 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21546 each : function(fn, scope){
21547 this.data.each(fn, scope);
21551 * Gets all records modified since the last commit. Modified records are persisted across load operations
21552 * (e.g., during paging).
21553 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21555 getModifiedRecords : function(){
21556 return this.modified;
21560 createFilterFn : function(property, value, anyMatch){
21561 if(!value.exec){ // not a regex
21562 value = String(value);
21563 if(value.length == 0){
21566 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21568 return function(r){
21569 return value.test(r.data[property]);
21574 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21575 * @param {String} property A field on your records
21576 * @param {Number} start The record index to start at (defaults to 0)
21577 * @param {Number} end The last record index to include (defaults to length - 1)
21578 * @return {Number} The sum
21580 sum : function(property, start, end){
21581 var rs = this.data.items, v = 0;
21582 start = start || 0;
21583 end = (end || end === 0) ? end : rs.length-1;
21585 for(var i = start; i <= end; i++){
21586 v += (rs[i].data[property] || 0);
21592 * Filter the records by a specified property.
21593 * @param {String} field A field on your records
21594 * @param {String/RegExp} value Either a string that the field
21595 * should start with or a RegExp to test against the field
21596 * @param {Boolean} anyMatch True to match any part not just the beginning
21598 filter : function(property, value, anyMatch){
21599 var fn = this.createFilterFn(property, value, anyMatch);
21600 return fn ? this.filterBy(fn) : this.clearFilter();
21604 * Filter by a function. The specified function will be called with each
21605 * record in this data source. If the function returns true the record is included,
21606 * otherwise it is filtered.
21607 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21608 * @param {Object} scope (optional) The scope of the function (defaults to this)
21610 filterBy : function(fn, scope){
21611 this.snapshot = this.snapshot || this.data;
21612 this.data = this.queryBy(fn, scope||this);
21613 this.fireEvent("datachanged", this);
21617 * Query the records by a specified property.
21618 * @param {String} field A field on your records
21619 * @param {String/RegExp} value Either a string that the field
21620 * should start with or a RegExp to test against the field
21621 * @param {Boolean} anyMatch True to match any part not just the beginning
21622 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21624 query : function(property, value, anyMatch){
21625 var fn = this.createFilterFn(property, value, anyMatch);
21626 return fn ? this.queryBy(fn) : this.data.clone();
21630 * Query by a function. The specified function will be called with each
21631 * record in this data source. If the function returns true the record is included
21633 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21634 * @param {Object} scope (optional) The scope of the function (defaults to this)
21635 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21637 queryBy : function(fn, scope){
21638 var data = this.snapshot || this.data;
21639 return data.filterBy(fn, scope||this);
21643 * Collects unique values for a particular dataIndex from this store.
21644 * @param {String} dataIndex The property to collect
21645 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21646 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21647 * @return {Array} An array of the unique values
21649 collect : function(dataIndex, allowNull, bypassFilter){
21650 var d = (bypassFilter === true && this.snapshot) ?
21651 this.snapshot.items : this.data.items;
21652 var v, sv, r = [], l = {};
21653 for(var i = 0, len = d.length; i < len; i++){
21654 v = d[i].data[dataIndex];
21656 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21665 * Revert to a view of the Record cache with no filtering applied.
21666 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21668 clearFilter : function(suppressEvent){
21669 if(this.snapshot && this.snapshot != this.data){
21670 this.data = this.snapshot;
21671 delete this.snapshot;
21672 if(suppressEvent !== true){
21673 this.fireEvent("datachanged", this);
21679 afterEdit : function(record){
21680 if(this.modified.indexOf(record) == -1){
21681 this.modified.push(record);
21683 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21687 afterReject : function(record){
21688 this.modified.remove(record);
21689 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21693 afterCommit : function(record){
21694 this.modified.remove(record);
21695 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21699 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21700 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21702 commitChanges : function(){
21703 var m = this.modified.slice(0);
21704 this.modified = [];
21705 for(var i = 0, len = m.length; i < len; i++){
21711 * Cancel outstanding changes on all changed records.
21713 rejectChanges : function(){
21714 var m = this.modified.slice(0);
21715 this.modified = [];
21716 for(var i = 0, len = m.length; i < len; i++){
21721 onMetaChange : function(meta, rtype, o){
21722 this.recordType = rtype;
21723 this.fields = rtype.prototype.fields;
21724 delete this.snapshot;
21725 this.sortInfo = meta.sortInfo || this.sortInfo;
21726 this.modified = [];
21727 this.fireEvent('metachange', this, this.reader.meta);
21731 * Ext JS Library 1.1.1
21732 * Copyright(c) 2006-2007, Ext JS, LLC.
21734 * Originally Released Under LGPL - original licence link has changed is not relivant.
21737 * <script type="text/javascript">
21741 * @class Roo.data.SimpleStore
21742 * @extends Roo.data.Store
21743 * Small helper class to make creating Stores from Array data easier.
21744 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21745 * @cfg {Array} fields An array of field definition objects, or field name strings.
21746 * @cfg {Array} data The multi-dimensional array of data
21748 * @param {Object} config
21750 Roo.data.SimpleStore = function(config){
21751 Roo.data.SimpleStore.superclass.constructor.call(this, {
21753 reader: new Roo.data.ArrayReader({
21756 Roo.data.Record.create(config.fields)
21758 proxy : new Roo.data.MemoryProxy(config.data)
21762 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21764 * Ext JS Library 1.1.1
21765 * Copyright(c) 2006-2007, Ext JS, LLC.
21767 * Originally Released Under LGPL - original licence link has changed is not relivant.
21770 * <script type="text/javascript">
21775 * @extends Roo.data.Store
21776 * @class Roo.data.JsonStore
21777 * Small helper class to make creating Stores for JSON data easier. <br/>
21779 var store = new Roo.data.JsonStore({
21780 url: 'get-images.php',
21782 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21785 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21786 * JsonReader and HttpProxy (unless inline data is provided).</b>
21787 * @cfg {Array} fields An array of field definition objects, or field name strings.
21789 * @param {Object} config
21791 Roo.data.JsonStore = function(c){
21792 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21793 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21794 reader: new Roo.data.JsonReader(c, c.fields)
21797 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21799 * Ext JS Library 1.1.1
21800 * Copyright(c) 2006-2007, Ext JS, LLC.
21802 * Originally Released Under LGPL - original licence link has changed is not relivant.
21805 * <script type="text/javascript">
21809 Roo.data.Field = function(config){
21810 if(typeof config == "string"){
21811 config = {name: config};
21813 Roo.apply(this, config);
21816 this.type = "auto";
21819 var st = Roo.data.SortTypes;
21820 // named sortTypes are supported, here we look them up
21821 if(typeof this.sortType == "string"){
21822 this.sortType = st[this.sortType];
21825 // set default sortType for strings and dates
21826 if(!this.sortType){
21829 this.sortType = st.asUCString;
21832 this.sortType = st.asDate;
21835 this.sortType = st.none;
21840 var stripRe = /[\$,%]/g;
21842 // prebuilt conversion function for this field, instead of
21843 // switching every time we're reading a value
21845 var cv, dateFormat = this.dateFormat;
21850 cv = function(v){ return v; };
21853 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21857 return v !== undefined && v !== null && v !== '' ?
21858 parseInt(String(v).replace(stripRe, ""), 10) : '';
21863 return v !== undefined && v !== null && v !== '' ?
21864 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21869 cv = function(v){ return v === true || v === "true" || v == 1; };
21876 if(v instanceof Date){
21880 if(dateFormat == "timestamp"){
21881 return new Date(v*1000);
21883 return Date.parseDate(v, dateFormat);
21885 var parsed = Date.parse(v);
21886 return parsed ? new Date(parsed) : null;
21895 Roo.data.Field.prototype = {
21903 * Ext JS Library 1.1.1
21904 * Copyright(c) 2006-2007, Ext JS, LLC.
21906 * Originally Released Under LGPL - original licence link has changed is not relivant.
21909 * <script type="text/javascript">
21912 // Base class for reading structured data from a data source. This class is intended to be
21913 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
21916 * @class Roo.data.DataReader
21917 * Base class for reading structured data from a data source. This class is intended to be
21918 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
21921 Roo.data.DataReader = function(meta, recordType){
21925 this.recordType = recordType instanceof Array ?
21926 Roo.data.Record.create(recordType) : recordType;
21929 Roo.data.DataReader.prototype = {
21931 * Create an empty record
21932 * @param {Object} data (optional) - overlay some values
21933 * @return {Roo.data.Record} record created.
21935 newRow : function(d) {
21937 this.recordType.prototype.fields.each(function(c) {
21939 case 'int' : da[c.name] = 0; break;
21940 case 'date' : da[c.name] = new Date(); break;
21941 case 'float' : da[c.name] = 0.0; break;
21942 case 'boolean' : da[c.name] = false; break;
21943 default : da[c.name] = ""; break;
21947 return new this.recordType(Roo.apply(da, d));
21952 * Ext JS Library 1.1.1
21953 * Copyright(c) 2006-2007, Ext JS, LLC.
21955 * Originally Released Under LGPL - original licence link has changed is not relivant.
21958 * <script type="text/javascript">
21962 * @class Roo.data.DataProxy
21963 * @extends Roo.data.Observable
21964 * This class is an abstract base class for implementations which provide retrieval of
21965 * unformatted data objects.<br>
21967 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
21968 * (of the appropriate type which knows how to parse the data object) to provide a block of
21969 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
21971 * Custom implementations must implement the load method as described in
21972 * {@link Roo.data.HttpProxy#load}.
21974 Roo.data.DataProxy = function(){
21977 * @event beforeload
21978 * Fires before a network request is made to retrieve a data object.
21979 * @param {Object} This DataProxy object.
21980 * @param {Object} params The params parameter to the load function.
21985 * Fires before the load method's callback is called.
21986 * @param {Object} This DataProxy object.
21987 * @param {Object} o The data object.
21988 * @param {Object} arg The callback argument object passed to the load function.
21992 * @event loadexception
21993 * Fires if an Exception occurs during data retrieval.
21994 * @param {Object} This DataProxy object.
21995 * @param {Object} o The data object.
21996 * @param {Object} arg The callback argument object passed to the load function.
21997 * @param {Object} e The Exception.
21999 loadexception : true
22001 Roo.data.DataProxy.superclass.constructor.call(this);
22004 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22007 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22011 * Ext JS Library 1.1.1
22012 * Copyright(c) 2006-2007, Ext JS, LLC.
22014 * Originally Released Under LGPL - original licence link has changed is not relivant.
22017 * <script type="text/javascript">
22020 * @class Roo.data.MemoryProxy
22021 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22022 * to the Reader when its load method is called.
22024 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22026 Roo.data.MemoryProxy = function(data){
22030 Roo.data.MemoryProxy.superclass.constructor.call(this);
22034 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22036 * Load data from the requested source (in this case an in-memory
22037 * data object passed to the constructor), read the data object into
22038 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22039 * process that block using the passed callback.
22040 * @param {Object} params This parameter is not used by the MemoryProxy class.
22041 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22042 * object into a block of Roo.data.Records.
22043 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22044 * The function must be passed <ul>
22045 * <li>The Record block object</li>
22046 * <li>The "arg" argument from the load function</li>
22047 * <li>A boolean success indicator</li>
22049 * @param {Object} scope The scope in which to call the callback
22050 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22052 load : function(params, reader, callback, scope, arg){
22053 params = params || {};
22056 result = reader.readRecords(this.data);
22058 this.fireEvent("loadexception", this, arg, null, e);
22059 callback.call(scope, null, arg, false);
22062 callback.call(scope, result, arg, true);
22066 update : function(params, records){
22071 * Ext JS Library 1.1.1
22072 * Copyright(c) 2006-2007, Ext JS, LLC.
22074 * Originally Released Under LGPL - original licence link has changed is not relivant.
22077 * <script type="text/javascript">
22080 * @class Roo.data.HttpProxy
22081 * @extends Roo.data.DataProxy
22082 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22083 * configured to reference a certain URL.<br><br>
22085 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22086 * from which the running page was served.<br><br>
22088 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22090 * Be aware that to enable the browser to parse an XML document, the server must set
22091 * the Content-Type header in the HTTP response to "text/xml".
22093 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22094 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22095 * will be used to make the request.
22097 Roo.data.HttpProxy = function(conn){
22098 Roo.data.HttpProxy.superclass.constructor.call(this);
22099 // is conn a conn config or a real conn?
22101 this.useAjax = !conn || !conn.events;
22105 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22106 // thse are take from connection...
22109 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22112 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22113 * extra parameters to each request made by this object. (defaults to undefined)
22116 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22117 * to each request made by this object. (defaults to undefined)
22120 * @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)
22123 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22126 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22132 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22136 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22137 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22138 * a finer-grained basis than the DataProxy events.
22140 getConnection : function(){
22141 return this.useAjax ? Roo.Ajax : this.conn;
22145 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22146 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22147 * process that block using the passed callback.
22148 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22149 * for the request to the remote server.
22150 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22151 * object into a block of Roo.data.Records.
22152 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22153 * The function must be passed <ul>
22154 * <li>The Record block object</li>
22155 * <li>The "arg" argument from the load function</li>
22156 * <li>A boolean success indicator</li>
22158 * @param {Object} scope The scope in which to call the callback
22159 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22161 load : function(params, reader, callback, scope, arg){
22162 if(this.fireEvent("beforeload", this, params) !== false){
22164 params : params || {},
22166 callback : callback,
22171 callback : this.loadResponse,
22175 Roo.applyIf(o, this.conn);
22176 if(this.activeRequest){
22177 Roo.Ajax.abort(this.activeRequest);
22179 this.activeRequest = Roo.Ajax.request(o);
22181 this.conn.request(o);
22184 callback.call(scope||this, null, arg, false);
22189 loadResponse : function(o, success, response){
22190 delete this.activeRequest;
22192 this.fireEvent("loadexception", this, o, response);
22193 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22198 result = o.reader.read(response);
22200 this.fireEvent("loadexception", this, o, response, e);
22201 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22205 this.fireEvent("load", this, o, o.request.arg);
22206 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22210 update : function(dataSet){
22215 updateResponse : function(dataSet){
22220 * Ext JS Library 1.1.1
22221 * Copyright(c) 2006-2007, Ext JS, LLC.
22223 * Originally Released Under LGPL - original licence link has changed is not relivant.
22226 * <script type="text/javascript">
22230 * @class Roo.data.ScriptTagProxy
22231 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22232 * other than the originating domain of the running page.<br><br>
22234 * <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
22235 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22237 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22238 * source code that is used as the source inside a <script> tag.<br><br>
22240 * In order for the browser to process the returned data, the server must wrap the data object
22241 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22242 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22243 * depending on whether the callback name was passed:
22246 boolean scriptTag = false;
22247 String cb = request.getParameter("callback");
22250 response.setContentType("text/javascript");
22252 response.setContentType("application/x-json");
22254 Writer out = response.getWriter();
22256 out.write(cb + "(");
22258 out.print(dataBlock.toJsonString());
22265 * @param {Object} config A configuration object.
22267 Roo.data.ScriptTagProxy = function(config){
22268 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22269 Roo.apply(this, config);
22270 this.head = document.getElementsByTagName("head")[0];
22273 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22275 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22277 * @cfg {String} url The URL from which to request the data object.
22280 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22284 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22285 * the server the name of the callback function set up by the load call to process the returned data object.
22286 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22287 * javascript output which calls this named function passing the data object as its only parameter.
22289 callbackParam : "callback",
22291 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22292 * name to the request.
22297 * Load data from the configured URL, read the data object into
22298 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22299 * process that block using the passed callback.
22300 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22301 * for the request to the remote server.
22302 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22303 * object into a block of Roo.data.Records.
22304 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22305 * The function must be passed <ul>
22306 * <li>The Record block object</li>
22307 * <li>The "arg" argument from the load function</li>
22308 * <li>A boolean success indicator</li>
22310 * @param {Object} scope The scope in which to call the callback
22311 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22313 load : function(params, reader, callback, scope, arg){
22314 if(this.fireEvent("beforeload", this, params) !== false){
22316 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22318 var url = this.url;
22319 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22321 url += "&_dc=" + (new Date().getTime());
22323 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22326 cb : "stcCallback"+transId,
22327 scriptId : "stcScript"+transId,
22331 callback : callback,
22337 window[trans.cb] = function(o){
22338 conn.handleResponse(o, trans);
22341 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22343 if(this.autoAbort !== false){
22347 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22349 var script = document.createElement("script");
22350 script.setAttribute("src", url);
22351 script.setAttribute("type", "text/javascript");
22352 script.setAttribute("id", trans.scriptId);
22353 this.head.appendChild(script);
22355 this.trans = trans;
22357 callback.call(scope||this, null, arg, false);
22362 isLoading : function(){
22363 return this.trans ? true : false;
22367 * Abort the current server request.
22369 abort : function(){
22370 if(this.isLoading()){
22371 this.destroyTrans(this.trans);
22376 destroyTrans : function(trans, isLoaded){
22377 this.head.removeChild(document.getElementById(trans.scriptId));
22378 clearTimeout(trans.timeoutId);
22380 window[trans.cb] = undefined;
22382 delete window[trans.cb];
22385 // if hasn't been loaded, wait for load to remove it to prevent script error
22386 window[trans.cb] = function(){
22387 window[trans.cb] = undefined;
22389 delete window[trans.cb];
22396 handleResponse : function(o, trans){
22397 this.trans = false;
22398 this.destroyTrans(trans, true);
22401 result = trans.reader.readRecords(o);
22403 this.fireEvent("loadexception", this, o, trans.arg, e);
22404 trans.callback.call(trans.scope||window, null, trans.arg, false);
22407 this.fireEvent("load", this, o, trans.arg);
22408 trans.callback.call(trans.scope||window, result, trans.arg, true);
22412 handleFailure : function(trans){
22413 this.trans = false;
22414 this.destroyTrans(trans, false);
22415 this.fireEvent("loadexception", this, null, trans.arg);
22416 trans.callback.call(trans.scope||window, null, trans.arg, false);
22420 * Ext JS Library 1.1.1
22421 * Copyright(c) 2006-2007, Ext JS, LLC.
22423 * Originally Released Under LGPL - original licence link has changed is not relivant.
22426 * <script type="text/javascript">
22430 * @class Roo.data.JsonReader
22431 * @extends Roo.data.DataReader
22432 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22433 * based on mappings in a provided Roo.data.Record constructor.
22435 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22436 * in the reply previously.
22441 var RecordDef = Roo.data.Record.create([
22442 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22443 {name: 'occupation'} // This field will use "occupation" as the mapping.
22445 var myReader = new Roo.data.JsonReader({
22446 totalProperty: "results", // The property which contains the total dataset size (optional)
22447 root: "rows", // The property which contains an Array of row objects
22448 id: "id" // The property within each row object that provides an ID for the record (optional)
22452 * This would consume a JSON file like this:
22454 { 'results': 2, 'rows': [
22455 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22456 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22459 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22460 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22461 * paged from the remote server.
22462 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22463 * @cfg {String} root name of the property which contains the Array of row objects.
22464 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22466 * Create a new JsonReader
22467 * @param {Object} meta Metadata configuration options
22468 * @param {Object} recordType Either an Array of field definition objects,
22469 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22471 Roo.data.JsonReader = function(meta, recordType){
22474 // set some defaults:
22475 Roo.applyIf(meta, {
22476 totalProperty: 'total',
22477 successProperty : 'success',
22482 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22484 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22487 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22488 * Used by Store query builder to append _requestMeta to params.
22491 metaFromRemote : false,
22493 * This method is only used by a DataProxy which has retrieved data from a remote server.
22494 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22495 * @return {Object} data A data block which is used by an Roo.data.Store object as
22496 * a cache of Roo.data.Records.
22498 read : function(response){
22499 var json = response.responseText;
22501 var o = /* eval:var:o */ eval("("+json+")");
22503 throw {message: "JsonReader.read: Json object not found"};
22509 this.metaFromRemote = true;
22510 this.meta = o.metaData;
22511 this.recordType = Roo.data.Record.create(o.metaData.fields);
22512 this.onMetaChange(this.meta, this.recordType, o);
22514 return this.readRecords(o);
22517 // private function a store will implement
22518 onMetaChange : function(meta, recordType, o){
22525 simpleAccess: function(obj, subsc) {
22532 getJsonAccessor: function(){
22534 return function(expr) {
22536 return(re.test(expr))
22537 ? new Function("obj", "return obj." + expr)
22542 return Roo.emptyFn;
22547 * Create a data block containing Roo.data.Records from an XML document.
22548 * @param {Object} o An object which contains an Array of row objects in the property specified
22549 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22550 * which contains the total size of the dataset.
22551 * @return {Object} data A data block which is used by an Roo.data.Store object as
22552 * a cache of Roo.data.Records.
22554 readRecords : function(o){
22556 * After any data loads, the raw JSON data is available for further custom processing.
22560 var s = this.meta, Record = this.recordType,
22561 f = Record.prototype.fields, fi = f.items, fl = f.length;
22563 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22565 if(s.totalProperty) {
22566 this.getTotal = this.getJsonAccessor(s.totalProperty);
22568 if(s.successProperty) {
22569 this.getSuccess = this.getJsonAccessor(s.successProperty);
22571 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22573 var g = this.getJsonAccessor(s.id);
22574 this.getId = function(rec) {
22576 return (r === undefined || r === "") ? null : r;
22579 this.getId = function(){return null;};
22582 for(var jj = 0; jj < fl; jj++){
22584 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22585 this.ef[jj] = this.getJsonAccessor(map);
22589 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22590 if(s.totalProperty){
22591 var vt = parseInt(this.getTotal(o), 10);
22596 if(s.successProperty){
22597 var vs = this.getSuccess(o);
22598 if(vs === false || vs === 'false'){
22603 for(var i = 0; i < c; i++){
22606 var id = this.getId(n);
22607 for(var j = 0; j < fl; j++){
22609 var v = this.ef[j](n);
22611 Roo.log('missing convert for ' + f.name);
22615 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22617 var record = new Record(values, id);
22619 records[i] = record;
22625 totalRecords : totalRecords
22630 * Ext JS Library 1.1.1
22631 * Copyright(c) 2006-2007, Ext JS, LLC.
22633 * Originally Released Under LGPL - original licence link has changed is not relivant.
22636 * <script type="text/javascript">
22640 * @class Roo.data.XmlReader
22641 * @extends Roo.data.DataReader
22642 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22643 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22645 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22646 * header in the HTTP response must be set to "text/xml".</em>
22650 var RecordDef = Roo.data.Record.create([
22651 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22652 {name: 'occupation'} // This field will use "occupation" as the mapping.
22654 var myReader = new Roo.data.XmlReader({
22655 totalRecords: "results", // The element which contains the total dataset size (optional)
22656 record: "row", // The repeated element which contains row information
22657 id: "id" // The element within the row that provides an ID for the record (optional)
22661 * This would consume an XML file like this:
22665 <results>2</results>
22668 <name>Bill</name>
22669 <occupation>Gardener</occupation>
22673 <name>Ben</name>
22674 <occupation>Horticulturalist</occupation>
22678 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22679 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22680 * paged from the remote server.
22681 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22682 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22683 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22684 * a record identifier value.
22686 * Create a new XmlReader
22687 * @param {Object} meta Metadata configuration options
22688 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22689 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22690 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22692 Roo.data.XmlReader = function(meta, recordType){
22694 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22696 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22698 * This method is only used by a DataProxy which has retrieved data from a remote server.
22699 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22700 * to contain a method called 'responseXML' that returns an XML document object.
22701 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22702 * a cache of Roo.data.Records.
22704 read : function(response){
22705 var doc = response.responseXML;
22707 throw {message: "XmlReader.read: XML Document not available"};
22709 return this.readRecords(doc);
22713 * Create a data block containing Roo.data.Records from an XML document.
22714 * @param {Object} doc A parsed XML document.
22715 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22716 * a cache of Roo.data.Records.
22718 readRecords : function(doc){
22720 * After any data loads/reads, the raw XML Document is available for further custom processing.
22721 * @type XMLDocument
22723 this.xmlData = doc;
22724 var root = doc.documentElement || doc;
22725 var q = Roo.DomQuery;
22726 var recordType = this.recordType, fields = recordType.prototype.fields;
22727 var sid = this.meta.id;
22728 var totalRecords = 0, success = true;
22729 if(this.meta.totalRecords){
22730 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22733 if(this.meta.success){
22734 var sv = q.selectValue(this.meta.success, root, true);
22735 success = sv !== false && sv !== 'false';
22738 var ns = q.select(this.meta.record, root);
22739 for(var i = 0, len = ns.length; i < len; i++) {
22742 var id = sid ? q.selectValue(sid, n) : undefined;
22743 for(var j = 0, jlen = fields.length; j < jlen; j++){
22744 var f = fields.items[j];
22745 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22747 values[f.name] = v;
22749 var record = new recordType(values, id);
22751 records[records.length] = record;
22757 totalRecords : totalRecords || records.length
22762 * Ext JS Library 1.1.1
22763 * Copyright(c) 2006-2007, Ext JS, LLC.
22765 * Originally Released Under LGPL - original licence link has changed is not relivant.
22768 * <script type="text/javascript">
22772 * @class Roo.data.ArrayReader
22773 * @extends Roo.data.DataReader
22774 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22775 * Each element of that Array represents a row of data fields. The
22776 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22777 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22781 var RecordDef = Roo.data.Record.create([
22782 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22783 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22785 var myReader = new Roo.data.ArrayReader({
22786 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22790 * This would consume an Array like this:
22792 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22794 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22796 * Create a new JsonReader
22797 * @param {Object} meta Metadata configuration options.
22798 * @param {Object} recordType Either an Array of field definition objects
22799 * as specified to {@link Roo.data.Record#create},
22800 * or an {@link Roo.data.Record} object
22801 * created using {@link Roo.data.Record#create}.
22803 Roo.data.ArrayReader = function(meta, recordType){
22804 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22807 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22809 * Create a data block containing Roo.data.Records from an XML document.
22810 * @param {Object} o An Array of row objects which represents the dataset.
22811 * @return {Object} data A data block which is used by an Roo.data.Store object as
22812 * a cache of Roo.data.Records.
22814 readRecords : function(o){
22815 var sid = this.meta ? this.meta.id : null;
22816 var recordType = this.recordType, fields = recordType.prototype.fields;
22819 for(var i = 0; i < root.length; i++){
22822 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22823 for(var j = 0, jlen = fields.length; j < jlen; j++){
22824 var f = fields.items[j];
22825 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22826 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22828 values[f.name] = v;
22830 var record = new recordType(values, id);
22832 records[records.length] = record;
22836 totalRecords : records.length
22841 * Ext JS Library 1.1.1
22842 * Copyright(c) 2006-2007, Ext JS, LLC.
22844 * Originally Released Under LGPL - original licence link has changed is not relivant.
22847 * <script type="text/javascript">
22852 * @class Roo.data.Tree
22853 * @extends Roo.util.Observable
22854 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22855 * in the tree have most standard DOM functionality.
22857 * @param {Node} root (optional) The root node
22859 Roo.data.Tree = function(root){
22860 this.nodeHash = {};
22862 * The root node for this tree
22867 this.setRootNode(root);
22872 * Fires when a new child node is appended to a node in this tree.
22873 * @param {Tree} tree The owner tree
22874 * @param {Node} parent The parent node
22875 * @param {Node} node The newly appended node
22876 * @param {Number} index The index of the newly appended node
22881 * Fires when a child node is removed from a node in this tree.
22882 * @param {Tree} tree The owner tree
22883 * @param {Node} parent The parent node
22884 * @param {Node} node The child node removed
22889 * Fires when a node is moved to a new location in the tree
22890 * @param {Tree} tree The owner tree
22891 * @param {Node} node The node moved
22892 * @param {Node} oldParent The old parent of this node
22893 * @param {Node} newParent The new parent of this node
22894 * @param {Number} index The index it was moved to
22899 * Fires when a new child node is inserted in a node in this tree.
22900 * @param {Tree} tree The owner tree
22901 * @param {Node} parent The parent node
22902 * @param {Node} node The child node inserted
22903 * @param {Node} refNode The child node the node was inserted before
22907 * @event beforeappend
22908 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
22909 * @param {Tree} tree The owner tree
22910 * @param {Node} parent The parent node
22911 * @param {Node} node The child node to be appended
22913 "beforeappend" : true,
22915 * @event beforeremove
22916 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
22917 * @param {Tree} tree The owner tree
22918 * @param {Node} parent The parent node
22919 * @param {Node} node The child node to be removed
22921 "beforeremove" : true,
22923 * @event beforemove
22924 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
22925 * @param {Tree} tree The owner tree
22926 * @param {Node} node The node being moved
22927 * @param {Node} oldParent The parent of the node
22928 * @param {Node} newParent The new parent the node is moving to
22929 * @param {Number} index The index it is being moved to
22931 "beforemove" : true,
22933 * @event beforeinsert
22934 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
22935 * @param {Tree} tree The owner tree
22936 * @param {Node} parent The parent node
22937 * @param {Node} node The child node to be inserted
22938 * @param {Node} refNode The child node the node is being inserted before
22940 "beforeinsert" : true
22943 Roo.data.Tree.superclass.constructor.call(this);
22946 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
22947 pathSeparator: "/",
22949 proxyNodeEvent : function(){
22950 return this.fireEvent.apply(this, arguments);
22954 * Returns the root node for this tree.
22957 getRootNode : function(){
22962 * Sets the root node for this tree.
22963 * @param {Node} node
22966 setRootNode : function(node){
22968 node.ownerTree = this;
22969 node.isRoot = true;
22970 this.registerNode(node);
22975 * Gets a node in this tree by its id.
22976 * @param {String} id
22979 getNodeById : function(id){
22980 return this.nodeHash[id];
22983 registerNode : function(node){
22984 this.nodeHash[node.id] = node;
22987 unregisterNode : function(node){
22988 delete this.nodeHash[node.id];
22991 toString : function(){
22992 return "[Tree"+(this.id?" "+this.id:"")+"]";
22997 * @class Roo.data.Node
22998 * @extends Roo.util.Observable
22999 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23000 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23002 * @param {Object} attributes The attributes/config for the node
23004 Roo.data.Node = function(attributes){
23006 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23009 this.attributes = attributes || {};
23010 this.leaf = this.attributes.leaf;
23012 * The node id. @type String
23014 this.id = this.attributes.id;
23016 this.id = Roo.id(null, "ynode-");
23017 this.attributes.id = this.id;
23022 * All child nodes of this node. @type Array
23024 this.childNodes = [];
23025 if(!this.childNodes.indexOf){ // indexOf is a must
23026 this.childNodes.indexOf = function(o){
23027 for(var i = 0, len = this.length; i < len; i++){
23036 * The parent node for this node. @type Node
23038 this.parentNode = null;
23040 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23042 this.firstChild = null;
23044 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23046 this.lastChild = null;
23048 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23050 this.previousSibling = null;
23052 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23054 this.nextSibling = null;
23059 * Fires when a new child node is appended
23060 * @param {Tree} tree The owner tree
23061 * @param {Node} this This node
23062 * @param {Node} node The newly appended node
23063 * @param {Number} index The index of the newly appended node
23068 * Fires when a child node is removed
23069 * @param {Tree} tree The owner tree
23070 * @param {Node} this This node
23071 * @param {Node} node The removed node
23076 * Fires when this node is moved to a new location in the tree
23077 * @param {Tree} tree The owner tree
23078 * @param {Node} this This node
23079 * @param {Node} oldParent The old parent of this node
23080 * @param {Node} newParent The new parent of this node
23081 * @param {Number} index The index it was moved to
23086 * Fires when a new child node is inserted.
23087 * @param {Tree} tree The owner tree
23088 * @param {Node} this This node
23089 * @param {Node} node The child node inserted
23090 * @param {Node} refNode The child node the node was inserted before
23094 * @event beforeappend
23095 * Fires before a new child is appended, return false to cancel the append.
23096 * @param {Tree} tree The owner tree
23097 * @param {Node} this This node
23098 * @param {Node} node The child node to be appended
23100 "beforeappend" : true,
23102 * @event beforeremove
23103 * Fires before a child is removed, return false to cancel the remove.
23104 * @param {Tree} tree The owner tree
23105 * @param {Node} this This node
23106 * @param {Node} node The child node to be removed
23108 "beforeremove" : true,
23110 * @event beforemove
23111 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23112 * @param {Tree} tree The owner tree
23113 * @param {Node} this This node
23114 * @param {Node} oldParent The parent of this node
23115 * @param {Node} newParent The new parent this node is moving to
23116 * @param {Number} index The index it is being moved to
23118 "beforemove" : true,
23120 * @event beforeinsert
23121 * Fires before a new child is inserted, return false to cancel the insert.
23122 * @param {Tree} tree The owner tree
23123 * @param {Node} this This node
23124 * @param {Node} node The child node to be inserted
23125 * @param {Node} refNode The child node the node is being inserted before
23127 "beforeinsert" : true
23129 this.listeners = this.attributes.listeners;
23130 Roo.data.Node.superclass.constructor.call(this);
23133 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23134 fireEvent : function(evtName){
23135 // first do standard event for this node
23136 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23139 // then bubble it up to the tree if the event wasn't cancelled
23140 var ot = this.getOwnerTree();
23142 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23150 * Returns true if this node is a leaf
23151 * @return {Boolean}
23153 isLeaf : function(){
23154 return this.leaf === true;
23158 setFirstChild : function(node){
23159 this.firstChild = node;
23163 setLastChild : function(node){
23164 this.lastChild = node;
23169 * Returns true if this node is the last child of its parent
23170 * @return {Boolean}
23172 isLast : function(){
23173 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23177 * Returns true if this node is the first child of its parent
23178 * @return {Boolean}
23180 isFirst : function(){
23181 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23184 hasChildNodes : function(){
23185 return !this.isLeaf() && this.childNodes.length > 0;
23189 * Insert node(s) as the last child node of this node.
23190 * @param {Node/Array} node The node or Array of nodes to append
23191 * @return {Node} The appended node if single append, or null if an array was passed
23193 appendChild : function(node){
23195 if(node instanceof Array){
23197 }else if(arguments.length > 1){
23200 // if passed an array or multiple args do them one by one
23202 for(var i = 0, len = multi.length; i < len; i++) {
23203 this.appendChild(multi[i]);
23206 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23209 var index = this.childNodes.length;
23210 var oldParent = node.parentNode;
23211 // it's a move, make sure we move it cleanly
23213 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23216 oldParent.removeChild(node);
23218 index = this.childNodes.length;
23220 this.setFirstChild(node);
23222 this.childNodes.push(node);
23223 node.parentNode = this;
23224 var ps = this.childNodes[index-1];
23226 node.previousSibling = ps;
23227 ps.nextSibling = node;
23229 node.previousSibling = null;
23231 node.nextSibling = null;
23232 this.setLastChild(node);
23233 node.setOwnerTree(this.getOwnerTree());
23234 this.fireEvent("append", this.ownerTree, this, node, index);
23236 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23243 * Removes a child node from this node.
23244 * @param {Node} node The node to remove
23245 * @return {Node} The removed node
23247 removeChild : function(node){
23248 var index = this.childNodes.indexOf(node);
23252 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23256 // remove it from childNodes collection
23257 this.childNodes.splice(index, 1);
23260 if(node.previousSibling){
23261 node.previousSibling.nextSibling = node.nextSibling;
23263 if(node.nextSibling){
23264 node.nextSibling.previousSibling = node.previousSibling;
23267 // update child refs
23268 if(this.firstChild == node){
23269 this.setFirstChild(node.nextSibling);
23271 if(this.lastChild == node){
23272 this.setLastChild(node.previousSibling);
23275 node.setOwnerTree(null);
23276 // clear any references from the node
23277 node.parentNode = null;
23278 node.previousSibling = null;
23279 node.nextSibling = null;
23280 this.fireEvent("remove", this.ownerTree, this, node);
23285 * Inserts the first node before the second node in this nodes childNodes collection.
23286 * @param {Node} node The node to insert
23287 * @param {Node} refNode The node to insert before (if null the node is appended)
23288 * @return {Node} The inserted node
23290 insertBefore : function(node, refNode){
23291 if(!refNode){ // like standard Dom, refNode can be null for append
23292 return this.appendChild(node);
23295 if(node == refNode){
23299 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23302 var index = this.childNodes.indexOf(refNode);
23303 var oldParent = node.parentNode;
23304 var refIndex = index;
23306 // when moving internally, indexes will change after remove
23307 if(oldParent == this && this.childNodes.indexOf(node) < index){
23311 // it's a move, make sure we move it cleanly
23313 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23316 oldParent.removeChild(node);
23319 this.setFirstChild(node);
23321 this.childNodes.splice(refIndex, 0, node);
23322 node.parentNode = this;
23323 var ps = this.childNodes[refIndex-1];
23325 node.previousSibling = ps;
23326 ps.nextSibling = node;
23328 node.previousSibling = null;
23330 node.nextSibling = refNode;
23331 refNode.previousSibling = node;
23332 node.setOwnerTree(this.getOwnerTree());
23333 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23335 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23341 * Returns the child node at the specified index.
23342 * @param {Number} index
23345 item : function(index){
23346 return this.childNodes[index];
23350 * Replaces one child node in this node with another.
23351 * @param {Node} newChild The replacement node
23352 * @param {Node} oldChild The node to replace
23353 * @return {Node} The replaced node
23355 replaceChild : function(newChild, oldChild){
23356 this.insertBefore(newChild, oldChild);
23357 this.removeChild(oldChild);
23362 * Returns the index of a child node
23363 * @param {Node} node
23364 * @return {Number} The index of the node or -1 if it was not found
23366 indexOf : function(child){
23367 return this.childNodes.indexOf(child);
23371 * Returns the tree this node is in.
23374 getOwnerTree : function(){
23375 // if it doesn't have one, look for one
23376 if(!this.ownerTree){
23380 this.ownerTree = p.ownerTree;
23386 return this.ownerTree;
23390 * Returns depth of this node (the root node has a depth of 0)
23393 getDepth : function(){
23396 while(p.parentNode){
23404 setOwnerTree : function(tree){
23405 // if it's move, we need to update everyone
23406 if(tree != this.ownerTree){
23407 if(this.ownerTree){
23408 this.ownerTree.unregisterNode(this);
23410 this.ownerTree = tree;
23411 var cs = this.childNodes;
23412 for(var i = 0, len = cs.length; i < len; i++) {
23413 cs[i].setOwnerTree(tree);
23416 tree.registerNode(this);
23422 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23423 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23424 * @return {String} The path
23426 getPath : function(attr){
23427 attr = attr || "id";
23428 var p = this.parentNode;
23429 var b = [this.attributes[attr]];
23431 b.unshift(p.attributes[attr]);
23434 var sep = this.getOwnerTree().pathSeparator;
23435 return sep + b.join(sep);
23439 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23440 * function call will be the scope provided or the current node. The arguments to the function
23441 * will be the args provided or the current node. If the function returns false at any point,
23442 * the bubble is stopped.
23443 * @param {Function} fn The function to call
23444 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23445 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23447 bubble : function(fn, scope, args){
23450 if(fn.call(scope || p, args || p) === false){
23458 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23459 * function call will be the scope provided or the current node. The arguments to the function
23460 * will be the args provided or the current node. If the function returns false at any point,
23461 * the cascade is stopped on that branch.
23462 * @param {Function} fn The function to call
23463 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23464 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23466 cascade : function(fn, scope, args){
23467 if(fn.call(scope || this, args || this) !== false){
23468 var cs = this.childNodes;
23469 for(var i = 0, len = cs.length; i < len; i++) {
23470 cs[i].cascade(fn, scope, args);
23476 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23477 * function call will be the scope provided or the current node. The arguments to the function
23478 * will be the args provided or the current node. If the function returns false at any point,
23479 * the iteration stops.
23480 * @param {Function} fn The function to call
23481 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23482 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23484 eachChild : function(fn, scope, args){
23485 var cs = this.childNodes;
23486 for(var i = 0, len = cs.length; i < len; i++) {
23487 if(fn.call(scope || this, args || cs[i]) === false){
23494 * Finds the first child that has the attribute with the specified value.
23495 * @param {String} attribute The attribute name
23496 * @param {Mixed} value The value to search for
23497 * @return {Node} The found child or null if none was found
23499 findChild : function(attribute, value){
23500 var cs = this.childNodes;
23501 for(var i = 0, len = cs.length; i < len; i++) {
23502 if(cs[i].attributes[attribute] == value){
23510 * Finds the first child by a custom function. The child matches if the function passed
23512 * @param {Function} fn
23513 * @param {Object} scope (optional)
23514 * @return {Node} The found child or null if none was found
23516 findChildBy : function(fn, scope){
23517 var cs = this.childNodes;
23518 for(var i = 0, len = cs.length; i < len; i++) {
23519 if(fn.call(scope||cs[i], cs[i]) === true){
23527 * Sorts this nodes children using the supplied sort function
23528 * @param {Function} fn
23529 * @param {Object} scope (optional)
23531 sort : function(fn, scope){
23532 var cs = this.childNodes;
23533 var len = cs.length;
23535 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23537 for(var i = 0; i < len; i++){
23539 n.previousSibling = cs[i-1];
23540 n.nextSibling = cs[i+1];
23542 this.setFirstChild(n);
23545 this.setLastChild(n);
23552 * Returns true if this node is an ancestor (at any point) of the passed node.
23553 * @param {Node} node
23554 * @return {Boolean}
23556 contains : function(node){
23557 return node.isAncestor(this);
23561 * Returns true if the passed node is an ancestor (at any point) of this node.
23562 * @param {Node} node
23563 * @return {Boolean}
23565 isAncestor : function(node){
23566 var p = this.parentNode;
23576 toString : function(){
23577 return "[Node"+(this.id?" "+this.id:"")+"]";
23581 * Ext JS Library 1.1.1
23582 * Copyright(c) 2006-2007, Ext JS, LLC.
23584 * Originally Released Under LGPL - original licence link has changed is not relivant.
23587 * <script type="text/javascript">
23592 * @extends Roo.Element
23593 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23594 * automatic maintaining of shadow/shim positions.
23595 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23596 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23597 * you can pass a string with a CSS class name. False turns off the shadow.
23598 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23599 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23600 * @cfg {String} cls CSS class to add to the element
23601 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23602 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23604 * @param {Object} config An object with config options.
23605 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23608 Roo.Layer = function(config, existingEl){
23609 config = config || {};
23610 var dh = Roo.DomHelper;
23611 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23613 this.dom = Roo.getDom(existingEl);
23616 var o = config.dh || {tag: "div", cls: "x-layer"};
23617 this.dom = dh.append(pel, o);
23620 this.addClass(config.cls);
23622 this.constrain = config.constrain !== false;
23623 this.visibilityMode = Roo.Element.VISIBILITY;
23625 this.id = this.dom.id = config.id;
23627 this.id = Roo.id(this.dom);
23629 this.zindex = config.zindex || this.getZIndex();
23630 this.position("absolute", this.zindex);
23632 this.shadowOffset = config.shadowOffset || 4;
23633 this.shadow = new Roo.Shadow({
23634 offset : this.shadowOffset,
23635 mode : config.shadow
23638 this.shadowOffset = 0;
23640 this.useShim = config.shim !== false && Roo.useShims;
23641 this.useDisplay = config.useDisplay;
23645 var supr = Roo.Element.prototype;
23647 // shims are shared among layer to keep from having 100 iframes
23650 Roo.extend(Roo.Layer, Roo.Element, {
23652 getZIndex : function(){
23653 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23656 getShim : function(){
23663 var shim = shims.shift();
23665 shim = this.createShim();
23666 shim.enableDisplayMode('block');
23667 shim.dom.style.display = 'none';
23668 shim.dom.style.visibility = 'visible';
23670 var pn = this.dom.parentNode;
23671 if(shim.dom.parentNode != pn){
23672 pn.insertBefore(shim.dom, this.dom);
23674 shim.setStyle('z-index', this.getZIndex()-2);
23679 hideShim : function(){
23681 this.shim.setDisplayed(false);
23682 shims.push(this.shim);
23687 disableShadow : function(){
23689 this.shadowDisabled = true;
23690 this.shadow.hide();
23691 this.lastShadowOffset = this.shadowOffset;
23692 this.shadowOffset = 0;
23696 enableShadow : function(show){
23698 this.shadowDisabled = false;
23699 this.shadowOffset = this.lastShadowOffset;
23700 delete this.lastShadowOffset;
23708 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23709 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23710 sync : function(doShow){
23711 var sw = this.shadow;
23712 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23713 var sh = this.getShim();
23715 var w = this.getWidth(),
23716 h = this.getHeight();
23718 var l = this.getLeft(true),
23719 t = this.getTop(true);
23721 if(sw && !this.shadowDisabled){
23722 if(doShow && !sw.isVisible()){
23725 sw.realign(l, t, w, h);
23731 // fit the shim behind the shadow, so it is shimmed too
23732 var a = sw.adjusts, s = sh.dom.style;
23733 s.left = (Math.min(l, l+a.l))+"px";
23734 s.top = (Math.min(t, t+a.t))+"px";
23735 s.width = (w+a.w)+"px";
23736 s.height = (h+a.h)+"px";
23743 sh.setLeftTop(l, t);
23750 destroy : function(){
23753 this.shadow.hide();
23755 this.removeAllListeners();
23756 var pn = this.dom.parentNode;
23758 pn.removeChild(this.dom);
23760 Roo.Element.uncache(this.id);
23763 remove : function(){
23768 beginUpdate : function(){
23769 this.updating = true;
23773 endUpdate : function(){
23774 this.updating = false;
23779 hideUnders : function(negOffset){
23781 this.shadow.hide();
23787 constrainXY : function(){
23788 if(this.constrain){
23789 var vw = Roo.lib.Dom.getViewWidth(),
23790 vh = Roo.lib.Dom.getViewHeight();
23791 var s = Roo.get(document).getScroll();
23793 var xy = this.getXY();
23794 var x = xy[0], y = xy[1];
23795 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23796 // only move it if it needs it
23798 // first validate right/bottom
23799 if((x + w) > vw+s.left){
23800 x = vw - w - this.shadowOffset;
23803 if((y + h) > vh+s.top){
23804 y = vh - h - this.shadowOffset;
23807 // then make sure top/left isn't negative
23818 var ay = this.avoidY;
23819 if(y <= ay && (y+h) >= ay){
23825 supr.setXY.call(this, xy);
23831 isVisible : function(){
23832 return this.visible;
23836 showAction : function(){
23837 this.visible = true; // track visibility to prevent getStyle calls
23838 if(this.useDisplay === true){
23839 this.setDisplayed("");
23840 }else if(this.lastXY){
23841 supr.setXY.call(this, this.lastXY);
23842 }else if(this.lastLT){
23843 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23848 hideAction : function(){
23849 this.visible = false;
23850 if(this.useDisplay === true){
23851 this.setDisplayed(false);
23853 this.setLeftTop(-10000,-10000);
23857 // overridden Element method
23858 setVisible : function(v, a, d, c, e){
23863 var cb = function(){
23868 }.createDelegate(this);
23869 supr.setVisible.call(this, true, true, d, cb, e);
23872 this.hideUnders(true);
23881 }.createDelegate(this);
23883 supr.setVisible.call(this, v, a, d, cb, e);
23892 storeXY : function(xy){
23893 delete this.lastLT;
23897 storeLeftTop : function(left, top){
23898 delete this.lastXY;
23899 this.lastLT = [left, top];
23903 beforeFx : function(){
23904 this.beforeAction();
23905 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23909 afterFx : function(){
23910 Roo.Layer.superclass.afterFx.apply(this, arguments);
23911 this.sync(this.isVisible());
23915 beforeAction : function(){
23916 if(!this.updating && this.shadow){
23917 this.shadow.hide();
23921 // overridden Element method
23922 setLeft : function(left){
23923 this.storeLeftTop(left, this.getTop(true));
23924 supr.setLeft.apply(this, arguments);
23928 setTop : function(top){
23929 this.storeLeftTop(this.getLeft(true), top);
23930 supr.setTop.apply(this, arguments);
23934 setLeftTop : function(left, top){
23935 this.storeLeftTop(left, top);
23936 supr.setLeftTop.apply(this, arguments);
23940 setXY : function(xy, a, d, c, e){
23942 this.beforeAction();
23944 var cb = this.createCB(c);
23945 supr.setXY.call(this, xy, a, d, cb, e);
23952 createCB : function(c){
23963 // overridden Element method
23964 setX : function(x, a, d, c, e){
23965 this.setXY([x, this.getY()], a, d, c, e);
23968 // overridden Element method
23969 setY : function(y, a, d, c, e){
23970 this.setXY([this.getX(), y], a, d, c, e);
23973 // overridden Element method
23974 setSize : function(w, h, a, d, c, e){
23975 this.beforeAction();
23976 var cb = this.createCB(c);
23977 supr.setSize.call(this, w, h, a, d, cb, e);
23983 // overridden Element method
23984 setWidth : function(w, a, d, c, e){
23985 this.beforeAction();
23986 var cb = this.createCB(c);
23987 supr.setWidth.call(this, w, a, d, cb, e);
23993 // overridden Element method
23994 setHeight : function(h, a, d, c, e){
23995 this.beforeAction();
23996 var cb = this.createCB(c);
23997 supr.setHeight.call(this, h, a, d, cb, e);
24003 // overridden Element method
24004 setBounds : function(x, y, w, h, a, d, c, e){
24005 this.beforeAction();
24006 var cb = this.createCB(c);
24008 this.storeXY([x, y]);
24009 supr.setXY.call(this, [x, y]);
24010 supr.setSize.call(this, w, h, a, d, cb, e);
24013 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24019 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24020 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24021 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24022 * @param {Number} zindex The new z-index to set
24023 * @return {this} The Layer
24025 setZIndex : function(zindex){
24026 this.zindex = zindex;
24027 this.setStyle("z-index", zindex + 2);
24029 this.shadow.setZIndex(zindex + 1);
24032 this.shim.setStyle("z-index", zindex);
24038 * Ext JS Library 1.1.1
24039 * Copyright(c) 2006-2007, Ext JS, LLC.
24041 * Originally Released Under LGPL - original licence link has changed is not relivant.
24044 * <script type="text/javascript">
24049 * @class Roo.Shadow
24050 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24051 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24052 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24054 * Create a new Shadow
24055 * @param {Object} config The config object
24057 Roo.Shadow = function(config){
24058 Roo.apply(this, config);
24059 if(typeof this.mode != "string"){
24060 this.mode = this.defaultMode;
24062 var o = this.offset, a = {h: 0};
24063 var rad = Math.floor(this.offset/2);
24064 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24070 a.l -= this.offset + rad;
24071 a.t -= this.offset + rad;
24082 a.l -= (this.offset - rad);
24083 a.t -= this.offset + rad;
24085 a.w -= (this.offset - rad)*2;
24096 a.l -= (this.offset - rad);
24097 a.t -= (this.offset - rad);
24099 a.w -= (this.offset + rad + 1);
24100 a.h -= (this.offset + rad);
24109 Roo.Shadow.prototype = {
24111 * @cfg {String} mode
24112 * The shadow display mode. Supports the following options:<br />
24113 * sides: Shadow displays on both sides and bottom only<br />
24114 * frame: Shadow displays equally on all four sides<br />
24115 * drop: Traditional bottom-right drop shadow (default)
24118 * @cfg {String} offset
24119 * The number of pixels to offset the shadow from the element (defaults to 4)
24124 defaultMode: "drop",
24127 * Displays the shadow under the target element
24128 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24130 show : function(target){
24131 target = Roo.get(target);
24133 this.el = Roo.Shadow.Pool.pull();
24134 if(this.el.dom.nextSibling != target.dom){
24135 this.el.insertBefore(target);
24138 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24140 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24143 target.getLeft(true),
24144 target.getTop(true),
24148 this.el.dom.style.display = "block";
24152 * Returns true if the shadow is visible, else false
24154 isVisible : function(){
24155 return this.el ? true : false;
24159 * Direct alignment when values are already available. Show must be called at least once before
24160 * calling this method to ensure it is initialized.
24161 * @param {Number} left The target element left position
24162 * @param {Number} top The target element top position
24163 * @param {Number} width The target element width
24164 * @param {Number} height The target element height
24166 realign : function(l, t, w, h){
24170 var a = this.adjusts, d = this.el.dom, s = d.style;
24172 s.left = (l+a.l)+"px";
24173 s.top = (t+a.t)+"px";
24174 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24176 if(s.width != sws || s.height != shs){
24180 var cn = d.childNodes;
24181 var sww = Math.max(0, (sw-12))+"px";
24182 cn[0].childNodes[1].style.width = sww;
24183 cn[1].childNodes[1].style.width = sww;
24184 cn[2].childNodes[1].style.width = sww;
24185 cn[1].style.height = Math.max(0, (sh-12))+"px";
24191 * Hides this shadow
24195 this.el.dom.style.display = "none";
24196 Roo.Shadow.Pool.push(this.el);
24202 * Adjust the z-index of this shadow
24203 * @param {Number} zindex The new z-index
24205 setZIndex : function(z){
24208 this.el.setStyle("z-index", z);
24213 // Private utility class that manages the internal Shadow cache
24214 Roo.Shadow.Pool = function(){
24216 var markup = Roo.isIE ?
24217 '<div class="x-ie-shadow"></div>' :
24218 '<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>';
24221 var sh = p.shift();
24223 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24224 sh.autoBoxAdjust = false;
24229 push : function(sh){
24235 * Ext JS Library 1.1.1
24236 * Copyright(c) 2006-2007, Ext JS, LLC.
24238 * Originally Released Under LGPL - original licence link has changed is not relivant.
24241 * <script type="text/javascript">
24246 * @class Roo.SplitBar
24247 * @extends Roo.util.Observable
24248 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24252 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24253 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24254 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24255 split.minSize = 100;
24256 split.maxSize = 600;
24257 split.animate = true;
24258 split.on('moved', splitterMoved);
24261 * Create a new SplitBar
24262 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24263 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24264 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24265 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24266 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24267 position of the SplitBar).
24269 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24272 this.el = Roo.get(dragElement, true);
24273 this.el.dom.unselectable = "on";
24275 this.resizingEl = Roo.get(resizingElement, true);
24279 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24280 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24283 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24286 * The minimum size of the resizing element. (Defaults to 0)
24292 * The maximum size of the resizing element. (Defaults to 2000)
24295 this.maxSize = 2000;
24298 * Whether to animate the transition to the new size
24301 this.animate = false;
24304 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24307 this.useShim = false;
24312 if(!existingProxy){
24314 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24316 this.proxy = Roo.get(existingProxy).dom;
24319 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24322 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24325 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24328 this.dragSpecs = {};
24331 * @private The adapter to use to positon and resize elements
24333 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24334 this.adapter.init(this);
24336 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24338 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24339 this.el.addClass("x-splitbar-h");
24342 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24343 this.el.addClass("x-splitbar-v");
24349 * Fires when the splitter is moved (alias for {@link #event-moved})
24350 * @param {Roo.SplitBar} this
24351 * @param {Number} newSize the new width or height
24356 * Fires when the splitter is moved
24357 * @param {Roo.SplitBar} this
24358 * @param {Number} newSize the new width or height
24362 * @event beforeresize
24363 * Fires before the splitter is dragged
24364 * @param {Roo.SplitBar} this
24366 "beforeresize" : true,
24368 "beforeapply" : true
24371 Roo.util.Observable.call(this);
24374 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24375 onStartProxyDrag : function(x, y){
24376 this.fireEvent("beforeresize", this);
24378 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24380 o.enableDisplayMode("block");
24381 // all splitbars share the same overlay
24382 Roo.SplitBar.prototype.overlay = o;
24384 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24385 this.overlay.show();
24386 Roo.get(this.proxy).setDisplayed("block");
24387 var size = this.adapter.getElementSize(this);
24388 this.activeMinSize = this.getMinimumSize();;
24389 this.activeMaxSize = this.getMaximumSize();;
24390 var c1 = size - this.activeMinSize;
24391 var c2 = Math.max(this.activeMaxSize - size, 0);
24392 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24393 this.dd.resetConstraints();
24394 this.dd.setXConstraint(
24395 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24396 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24398 this.dd.setYConstraint(0, 0);
24400 this.dd.resetConstraints();
24401 this.dd.setXConstraint(0, 0);
24402 this.dd.setYConstraint(
24403 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24404 this.placement == Roo.SplitBar.TOP ? c2 : c1
24407 this.dragSpecs.startSize = size;
24408 this.dragSpecs.startPoint = [x, y];
24409 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24413 * @private Called after the drag operation by the DDProxy
24415 onEndProxyDrag : function(e){
24416 Roo.get(this.proxy).setDisplayed(false);
24417 var endPoint = Roo.lib.Event.getXY(e);
24419 this.overlay.hide();
24422 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24423 newSize = this.dragSpecs.startSize +
24424 (this.placement == Roo.SplitBar.LEFT ?
24425 endPoint[0] - this.dragSpecs.startPoint[0] :
24426 this.dragSpecs.startPoint[0] - endPoint[0]
24429 newSize = this.dragSpecs.startSize +
24430 (this.placement == Roo.SplitBar.TOP ?
24431 endPoint[1] - this.dragSpecs.startPoint[1] :
24432 this.dragSpecs.startPoint[1] - endPoint[1]
24435 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24436 if(newSize != this.dragSpecs.startSize){
24437 if(this.fireEvent('beforeapply', this, newSize) !== false){
24438 this.adapter.setElementSize(this, newSize);
24439 this.fireEvent("moved", this, newSize);
24440 this.fireEvent("resize", this, newSize);
24446 * Get the adapter this SplitBar uses
24447 * @return The adapter object
24449 getAdapter : function(){
24450 return this.adapter;
24454 * Set the adapter this SplitBar uses
24455 * @param {Object} adapter A SplitBar adapter object
24457 setAdapter : function(adapter){
24458 this.adapter = adapter;
24459 this.adapter.init(this);
24463 * Gets the minimum size for the resizing element
24464 * @return {Number} The minimum size
24466 getMinimumSize : function(){
24467 return this.minSize;
24471 * Sets the minimum size for the resizing element
24472 * @param {Number} minSize The minimum size
24474 setMinimumSize : function(minSize){
24475 this.minSize = minSize;
24479 * Gets the maximum size for the resizing element
24480 * @return {Number} The maximum size
24482 getMaximumSize : function(){
24483 return this.maxSize;
24487 * Sets the maximum size for the resizing element
24488 * @param {Number} maxSize The maximum size
24490 setMaximumSize : function(maxSize){
24491 this.maxSize = maxSize;
24495 * Sets the initialize size for the resizing element
24496 * @param {Number} size The initial size
24498 setCurrentSize : function(size){
24499 var oldAnimate = this.animate;
24500 this.animate = false;
24501 this.adapter.setElementSize(this, size);
24502 this.animate = oldAnimate;
24506 * Destroy this splitbar.
24507 * @param {Boolean} removeEl True to remove the element
24509 destroy : function(removeEl){
24511 this.shim.remove();
24514 this.proxy.parentNode.removeChild(this.proxy);
24522 * @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.
24524 Roo.SplitBar.createProxy = function(dir){
24525 var proxy = new Roo.Element(document.createElement("div"));
24526 proxy.unselectable();
24527 var cls = 'x-splitbar-proxy';
24528 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24529 document.body.appendChild(proxy.dom);
24534 * @class Roo.SplitBar.BasicLayoutAdapter
24535 * Default Adapter. It assumes the splitter and resizing element are not positioned
24536 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24538 Roo.SplitBar.BasicLayoutAdapter = function(){
24541 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24542 // do nothing for now
24543 init : function(s){
24547 * Called before drag operations to get the current size of the resizing element.
24548 * @param {Roo.SplitBar} s The SplitBar using this adapter
24550 getElementSize : function(s){
24551 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24552 return s.resizingEl.getWidth();
24554 return s.resizingEl.getHeight();
24559 * Called after drag operations to set the size of the resizing element.
24560 * @param {Roo.SplitBar} s The SplitBar using this adapter
24561 * @param {Number} newSize The new size to set
24562 * @param {Function} onComplete A function to be invoked when resizing is complete
24564 setElementSize : function(s, newSize, onComplete){
24565 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24567 s.resizingEl.setWidth(newSize);
24569 onComplete(s, newSize);
24572 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24577 s.resizingEl.setHeight(newSize);
24579 onComplete(s, newSize);
24582 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24589 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24590 * @extends Roo.SplitBar.BasicLayoutAdapter
24591 * Adapter that moves the splitter element to align with the resized sizing element.
24592 * Used with an absolute positioned SplitBar.
24593 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24594 * document.body, make sure you assign an id to the body element.
24596 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24597 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24598 this.container = Roo.get(container);
24601 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24602 init : function(s){
24603 this.basic.init(s);
24606 getElementSize : function(s){
24607 return this.basic.getElementSize(s);
24610 setElementSize : function(s, newSize, onComplete){
24611 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24614 moveSplitter : function(s){
24615 var yes = Roo.SplitBar;
24616 switch(s.placement){
24618 s.el.setX(s.resizingEl.getRight());
24621 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24624 s.el.setY(s.resizingEl.getBottom());
24627 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24634 * Orientation constant - Create a vertical SplitBar
24638 Roo.SplitBar.VERTICAL = 1;
24641 * Orientation constant - Create a horizontal SplitBar
24645 Roo.SplitBar.HORIZONTAL = 2;
24648 * Placement constant - The resizing element is to the left of the splitter element
24652 Roo.SplitBar.LEFT = 1;
24655 * Placement constant - The resizing element is to the right of the splitter element
24659 Roo.SplitBar.RIGHT = 2;
24662 * Placement constant - The resizing element is positioned above the splitter element
24666 Roo.SplitBar.TOP = 3;
24669 * Placement constant - The resizing element is positioned under splitter element
24673 Roo.SplitBar.BOTTOM = 4;
24676 * Ext JS Library 1.1.1
24677 * Copyright(c) 2006-2007, Ext JS, LLC.
24679 * Originally Released Under LGPL - original licence link has changed is not relivant.
24682 * <script type="text/javascript">
24687 * @extends Roo.util.Observable
24688 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24689 * This class also supports single and multi selection modes. <br>
24690 * Create a data model bound view:
24692 var store = new Roo.data.Store(...);
24694 var view = new Roo.View({
24696 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24698 singleSelect: true,
24699 selectedClass: "ydataview-selected",
24703 // listen for node click?
24704 view.on("click", function(vw, index, node, e){
24705 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24709 dataModel.load("foobar.xml");
24711 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24713 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24714 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24716 * Note: old style constructor is still suported (container, template, config)
24719 * Create a new View
24720 * @param {Object} config The config object
24723 Roo.View = function(config, depreciated_tpl, depreciated_config){
24725 if (typeof(depreciated_tpl) == 'undefined') {
24726 // new way.. - universal constructor.
24727 Roo.apply(this, config);
24728 this.el = Roo.get(this.el);
24731 this.el = Roo.get(config);
24732 this.tpl = depreciated_tpl;
24733 Roo.apply(this, depreciated_config);
24735 this.wrapEl = this.el.wrap().wrap();
24736 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24739 if(typeof(this.tpl) == "string"){
24740 this.tpl = new Roo.Template(this.tpl);
24742 // support xtype ctors..
24743 this.tpl = new Roo.factory(this.tpl, Roo);
24747 this.tpl.compile();
24755 * @event beforeclick
24756 * Fires before a click is processed. Returns false to cancel the default action.
24757 * @param {Roo.View} this
24758 * @param {Number} index The index of the target node
24759 * @param {HTMLElement} node The target node
24760 * @param {Roo.EventObject} e The raw event object
24762 "beforeclick" : true,
24765 * Fires when a template node is clicked.
24766 * @param {Roo.View} this
24767 * @param {Number} index The index of the target node
24768 * @param {HTMLElement} node The target node
24769 * @param {Roo.EventObject} e The raw event object
24774 * Fires when a template node is double clicked.
24775 * @param {Roo.View} this
24776 * @param {Number} index The index of the target node
24777 * @param {HTMLElement} node The target node
24778 * @param {Roo.EventObject} e The raw event object
24782 * @event contextmenu
24783 * Fires when a template node is right clicked.
24784 * @param {Roo.View} this
24785 * @param {Number} index The index of the target node
24786 * @param {HTMLElement} node The target node
24787 * @param {Roo.EventObject} e The raw event object
24789 "contextmenu" : true,
24791 * @event selectionchange
24792 * Fires when the selected nodes change.
24793 * @param {Roo.View} this
24794 * @param {Array} selections Array of the selected nodes
24796 "selectionchange" : true,
24799 * @event beforeselect
24800 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24801 * @param {Roo.View} this
24802 * @param {HTMLElement} node The node to be selected
24803 * @param {Array} selections Array of currently selected nodes
24805 "beforeselect" : true,
24807 * @event preparedata
24808 * Fires on every row to render, to allow you to change the data.
24809 * @param {Roo.View} this
24810 * @param {Object} data to be rendered (change this)
24812 "preparedata" : true
24820 "click": this.onClick,
24821 "dblclick": this.onDblClick,
24822 "contextmenu": this.onContextMenu,
24826 this.selections = [];
24828 this.cmp = new Roo.CompositeElementLite([]);
24830 this.store = Roo.factory(this.store, Roo.data);
24831 this.setStore(this.store, true);
24834 if ( this.footer && this.footer.xtype) {
24836 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24838 this.footer.dataSource = this.store
24839 this.footer.container = fctr;
24840 this.footer = Roo.factory(this.footer, Roo);
24841 fctr.insertFirst(this.el);
24843 // this is a bit insane - as the paging toolbar seems to detach the el..
24844 // dom.parentNode.parentNode.parentNode
24845 // they get detached?
24849 Roo.View.superclass.constructor.call(this);
24854 Roo.extend(Roo.View, Roo.util.Observable, {
24857 * @cfg {Roo.data.Store} store Data store to load data from.
24862 * @cfg {String|Roo.Element} el The container element.
24867 * @cfg {String|Roo.Template} tpl The template used by this View
24871 * @cfg {String} dataName the named area of the template to use as the data area
24872 * Works with domtemplates roo-name="name"
24876 * @cfg {String} selectedClass The css class to add to selected nodes
24878 selectedClass : "x-view-selected",
24880 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24885 * @cfg {String} text to display on mask (default Loading)
24889 * @cfg {Boolean} multiSelect Allow multiple selection
24891 multiSelect : false,
24893 * @cfg {Boolean} singleSelect Allow single selection
24895 singleSelect: false,
24898 * @cfg {Boolean} toggleSelect - selecting
24900 toggleSelect : false,
24903 * Returns the element this view is bound to.
24904 * @return {Roo.Element}
24906 getEl : function(){
24907 return this.wrapEl;
24913 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24915 refresh : function(){
24918 // if we are using something like 'domtemplate', then
24919 // the what gets used is:
24920 // t.applySubtemplate(NAME, data, wrapping data..)
24921 // the outer template then get' applied with
24922 // the store 'extra data'
24923 // and the body get's added to the
24924 // roo-name="data" node?
24925 // <span class='roo-tpl-{name}'></span> ?????
24929 this.clearSelections();
24930 this.el.update("");
24932 var records = this.store.getRange();
24933 if(records.length < 1) {
24935 // is this valid?? = should it render a template??
24937 this.el.update(this.emptyText);
24941 if (this.dataName) {
24942 this.el.update(t.apply(this.store.meta)); //????
24943 el = this.el.child('.roo-tpl-' + this.dataName);
24946 for(var i = 0, len = records.length; i < len; i++){
24947 var data = this.prepareData(records[i].data, i, records[i]);
24948 this.fireEvent("preparedata", this, data, i, records[i]);
24949 html[html.length] = Roo.util.Format.trim(
24951 t.applySubtemplate(this.dataName, data, this.store.meta) :
24958 el.update(html.join(""));
24959 this.nodes = el.dom.childNodes;
24960 this.updateIndexes(0);
24964 * Function to override to reformat the data that is sent to
24965 * the template for each node.
24966 * DEPRICATED - use the preparedata event handler.
24967 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24968 * a JSON object for an UpdateManager bound view).
24970 prepareData : function(data, index, record)
24972 this.fireEvent("preparedata", this, data, index, record);
24976 onUpdate : function(ds, record){
24977 this.clearSelections();
24978 var index = this.store.indexOf(record);
24979 var n = this.nodes[index];
24980 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24981 n.parentNode.removeChild(n);
24982 this.updateIndexes(index, index);
24988 onAdd : function(ds, records, index)
24990 this.clearSelections();
24991 if(this.nodes.length == 0){
24995 var n = this.nodes[index];
24996 for(var i = 0, len = records.length; i < len; i++){
24997 var d = this.prepareData(records[i].data, i, records[i]);
24999 this.tpl.insertBefore(n, d);
25002 this.tpl.append(this.el, d);
25005 this.updateIndexes(index);
25008 onRemove : function(ds, record, index){
25009 this.clearSelections();
25010 var el = this.dataName ?
25011 this.el.child('.roo-tpl-' + this.dataName) :
25013 el.dom.removeChild(this.nodes[index]);
25014 this.updateIndexes(index);
25018 * Refresh an individual node.
25019 * @param {Number} index
25021 refreshNode : function(index){
25022 this.onUpdate(this.store, this.store.getAt(index));
25025 updateIndexes : function(startIndex, endIndex){
25026 var ns = this.nodes;
25027 startIndex = startIndex || 0;
25028 endIndex = endIndex || ns.length - 1;
25029 for(var i = startIndex; i <= endIndex; i++){
25030 ns[i].nodeIndex = i;
25035 * Changes the data store this view uses and refresh the view.
25036 * @param {Store} store
25038 setStore : function(store, initial){
25039 if(!initial && this.store){
25040 this.store.un("datachanged", this.refresh);
25041 this.store.un("add", this.onAdd);
25042 this.store.un("remove", this.onRemove);
25043 this.store.un("update", this.onUpdate);
25044 this.store.un("clear", this.refresh);
25045 this.store.un("beforeload", this.onBeforeLoad);
25046 this.store.un("load", this.onLoad);
25047 this.store.un("loadexception", this.onLoad);
25051 store.on("datachanged", this.refresh, this);
25052 store.on("add", this.onAdd, this);
25053 store.on("remove", this.onRemove, this);
25054 store.on("update", this.onUpdate, this);
25055 store.on("clear", this.refresh, this);
25056 store.on("beforeload", this.onBeforeLoad, this);
25057 store.on("load", this.onLoad, this);
25058 store.on("loadexception", this.onLoad, this);
25066 * onbeforeLoad - masks the loading area.
25069 onBeforeLoad : function()
25071 this.el.update("");
25072 this.el.mask(this.mask ? this.mask : "Loading" );
25074 onLoad : function ()
25081 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25082 * @param {HTMLElement} node
25083 * @return {HTMLElement} The template node
25085 findItemFromChild : function(node){
25086 var el = this.dataName ?
25087 this.el.child('.roo-tpl-' + this.dataName,true) :
25090 if(!node || node.parentNode == el){
25093 var p = node.parentNode;
25094 while(p && p != el){
25095 if(p.parentNode == el){
25104 onClick : function(e){
25105 var item = this.findItemFromChild(e.getTarget());
25107 var index = this.indexOf(item);
25108 if(this.onItemClick(item, index, e) !== false){
25109 this.fireEvent("click", this, index, item, e);
25112 this.clearSelections();
25117 onContextMenu : function(e){
25118 var item = this.findItemFromChild(e.getTarget());
25120 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25125 onDblClick : function(e){
25126 var item = this.findItemFromChild(e.getTarget());
25128 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25132 onItemClick : function(item, index, e)
25134 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25137 if (this.toggleSelect) {
25138 var m = this.isSelected(item) ? 'unselect' : 'select';
25141 _t[m](item, true, false);
25144 if(this.multiSelect || this.singleSelect){
25145 if(this.multiSelect && e.shiftKey && this.lastSelection){
25146 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25148 this.select(item, this.multiSelect && e.ctrlKey);
25149 this.lastSelection = item;
25151 e.preventDefault();
25157 * Get the number of selected nodes.
25160 getSelectionCount : function(){
25161 return this.selections.length;
25165 * Get the currently selected nodes.
25166 * @return {Array} An array of HTMLElements
25168 getSelectedNodes : function(){
25169 return this.selections;
25173 * Get the indexes of the selected nodes.
25176 getSelectedIndexes : function(){
25177 var indexes = [], s = this.selections;
25178 for(var i = 0, len = s.length; i < len; i++){
25179 indexes.push(s[i].nodeIndex);
25185 * Clear all selections
25186 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25188 clearSelections : function(suppressEvent){
25189 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25190 this.cmp.elements = this.selections;
25191 this.cmp.removeClass(this.selectedClass);
25192 this.selections = [];
25193 if(!suppressEvent){
25194 this.fireEvent("selectionchange", this, this.selections);
25200 * Returns true if the passed node is selected
25201 * @param {HTMLElement/Number} node The node or node index
25202 * @return {Boolean}
25204 isSelected : function(node){
25205 var s = this.selections;
25209 node = this.getNode(node);
25210 return s.indexOf(node) !== -1;
25215 * @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
25216 * @param {Boolean} keepExisting (optional) true to keep existing selections
25217 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25219 select : function(nodeInfo, keepExisting, suppressEvent){
25220 if(nodeInfo instanceof Array){
25222 this.clearSelections(true);
25224 for(var i = 0, len = nodeInfo.length; i < len; i++){
25225 this.select(nodeInfo[i], true, true);
25229 var node = this.getNode(nodeInfo);
25230 if(!node || this.isSelected(node)){
25231 return; // already selected.
25234 this.clearSelections(true);
25236 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25237 Roo.fly(node).addClass(this.selectedClass);
25238 this.selections.push(node);
25239 if(!suppressEvent){
25240 this.fireEvent("selectionchange", this, this.selections);
25248 * @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
25249 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25250 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25252 unselect : function(nodeInfo, keepExisting, suppressEvent)
25254 if(nodeInfo instanceof Array){
25255 Roo.each(this.selections, function(s) {
25256 this.unselect(s, nodeInfo);
25260 var node = this.getNode(nodeInfo);
25261 if(!node || !this.isSelected(node)){
25262 Roo.log("not selected");
25263 return; // not selected.
25267 Roo.each(this.selections, function(s) {
25269 Roo.fly(node).removeClass(this.selectedClass);
25276 this.selections= ns;
25277 this.fireEvent("selectionchange", this, this.selections);
25281 * Gets a template node.
25282 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25283 * @return {HTMLElement} The node or null if it wasn't found
25285 getNode : function(nodeInfo){
25286 if(typeof nodeInfo == "string"){
25287 return document.getElementById(nodeInfo);
25288 }else if(typeof nodeInfo == "number"){
25289 return this.nodes[nodeInfo];
25295 * Gets a range template nodes.
25296 * @param {Number} startIndex
25297 * @param {Number} endIndex
25298 * @return {Array} An array of nodes
25300 getNodes : function(start, end){
25301 var ns = this.nodes;
25302 start = start || 0;
25303 end = typeof end == "undefined" ? ns.length - 1 : end;
25306 for(var i = start; i <= end; i++){
25310 for(var i = start; i >= end; i--){
25318 * Finds the index of the passed node
25319 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25320 * @return {Number} The index of the node or -1
25322 indexOf : function(node){
25323 node = this.getNode(node);
25324 if(typeof node.nodeIndex == "number"){
25325 return node.nodeIndex;
25327 var ns = this.nodes;
25328 for(var i = 0, len = ns.length; i < len; i++){
25338 * Ext JS Library 1.1.1
25339 * Copyright(c) 2006-2007, Ext JS, LLC.
25341 * Originally Released Under LGPL - original licence link has changed is not relivant.
25344 * <script type="text/javascript">
25348 * @class Roo.JsonView
25349 * @extends Roo.View
25350 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25352 var view = new Roo.JsonView({
25353 container: "my-element",
25354 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25359 // listen for node click?
25360 view.on("click", function(vw, index, node, e){
25361 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25364 // direct load of JSON data
25365 view.load("foobar.php");
25367 // Example from my blog list
25368 var tpl = new Roo.Template(
25369 '<div class="entry">' +
25370 '<a class="entry-title" href="{link}">{title}</a>' +
25371 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25372 "</div><hr />"
25375 var moreView = new Roo.JsonView({
25376 container : "entry-list",
25380 moreView.on("beforerender", this.sortEntries, this);
25382 url: "/blog/get-posts.php",
25383 params: "allposts=true",
25384 text: "Loading Blog Entries..."
25388 * Note: old code is supported with arguments : (container, template, config)
25392 * Create a new JsonView
25394 * @param {Object} config The config object
25397 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25400 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25402 var um = this.el.getUpdateManager();
25403 um.setRenderer(this);
25404 um.on("update", this.onLoad, this);
25405 um.on("failure", this.onLoadException, this);
25408 * @event beforerender
25409 * Fires before rendering of the downloaded JSON data.
25410 * @param {Roo.JsonView} this
25411 * @param {Object} data The JSON data loaded
25415 * Fires when data is loaded.
25416 * @param {Roo.JsonView} this
25417 * @param {Object} data The JSON data loaded
25418 * @param {Object} response The raw Connect response object
25421 * @event loadexception
25422 * Fires when loading fails.
25423 * @param {Roo.JsonView} this
25424 * @param {Object} response The raw Connect response object
25427 'beforerender' : true,
25429 'loadexception' : true
25432 Roo.extend(Roo.JsonView, Roo.View, {
25434 * @type {String} The root property in the loaded JSON object that contains the data
25439 * Refreshes the view.
25441 refresh : function(){
25442 this.clearSelections();
25443 this.el.update("");
25445 var o = this.jsonData;
25446 if(o && o.length > 0){
25447 for(var i = 0, len = o.length; i < len; i++){
25448 var data = this.prepareData(o[i], i, o);
25449 html[html.length] = this.tpl.apply(data);
25452 html.push(this.emptyText);
25454 this.el.update(html.join(""));
25455 this.nodes = this.el.dom.childNodes;
25456 this.updateIndexes(0);
25460 * 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.
25461 * @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:
25464 url: "your-url.php",
25465 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25466 callback: yourFunction,
25467 scope: yourObject, //(optional scope)
25470 text: "Loading...",
25475 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25476 * 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.
25477 * @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}
25478 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25479 * @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.
25482 var um = this.el.getUpdateManager();
25483 um.update.apply(um, arguments);
25486 render : function(el, response){
25487 this.clearSelections();
25488 this.el.update("");
25491 o = Roo.util.JSON.decode(response.responseText);
25494 o = o[this.jsonRoot];
25499 * The current JSON data or null
25502 this.beforeRender();
25507 * Get the number of records in the current JSON dataset
25510 getCount : function(){
25511 return this.jsonData ? this.jsonData.length : 0;
25515 * Returns the JSON object for the specified node(s)
25516 * @param {HTMLElement/Array} node The node or an array of nodes
25517 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25518 * you get the JSON object for the node
25520 getNodeData : function(node){
25521 if(node instanceof Array){
25523 for(var i = 0, len = node.length; i < len; i++){
25524 data.push(this.getNodeData(node[i]));
25528 return this.jsonData[this.indexOf(node)] || null;
25531 beforeRender : function(){
25532 this.snapshot = this.jsonData;
25534 this.sort.apply(this, this.sortInfo);
25536 this.fireEvent("beforerender", this, this.jsonData);
25539 onLoad : function(el, o){
25540 this.fireEvent("load", this, this.jsonData, o);
25543 onLoadException : function(el, o){
25544 this.fireEvent("loadexception", this, o);
25548 * Filter the data by a specific property.
25549 * @param {String} property A property on your JSON objects
25550 * @param {String/RegExp} value Either string that the property values
25551 * should start with, or a RegExp to test against the property
25553 filter : function(property, value){
25556 var ss = this.snapshot;
25557 if(typeof value == "string"){
25558 var vlen = value.length;
25560 this.clearFilter();
25563 value = value.toLowerCase();
25564 for(var i = 0, len = ss.length; i < len; i++){
25566 if(o[property].substr(0, vlen).toLowerCase() == value){
25570 } else if(value.exec){ // regex?
25571 for(var i = 0, len = ss.length; i < len; i++){
25573 if(value.test(o[property])){
25580 this.jsonData = data;
25586 * Filter by a function. The passed function will be called with each
25587 * object in the current dataset. If the function returns true the value is kept,
25588 * otherwise it is filtered.
25589 * @param {Function} fn
25590 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25592 filterBy : function(fn, scope){
25595 var ss = this.snapshot;
25596 for(var i = 0, len = ss.length; i < len; i++){
25598 if(fn.call(scope || this, o)){
25602 this.jsonData = data;
25608 * Clears the current filter.
25610 clearFilter : function(){
25611 if(this.snapshot && this.jsonData != this.snapshot){
25612 this.jsonData = this.snapshot;
25619 * Sorts the data for this view and refreshes it.
25620 * @param {String} property A property on your JSON objects to sort on
25621 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25622 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25624 sort : function(property, dir, sortType){
25625 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25628 var dsc = dir && dir.toLowerCase() == "desc";
25629 var f = function(o1, o2){
25630 var v1 = sortType ? sortType(o1[p]) : o1[p];
25631 var v2 = sortType ? sortType(o2[p]) : o2[p];
25634 return dsc ? +1 : -1;
25635 } else if(v1 > v2){
25636 return dsc ? -1 : +1;
25641 this.jsonData.sort(f);
25643 if(this.jsonData != this.snapshot){
25644 this.snapshot.sort(f);
25650 * Ext JS Library 1.1.1
25651 * Copyright(c) 2006-2007, Ext JS, LLC.
25653 * Originally Released Under LGPL - original licence link has changed is not relivant.
25656 * <script type="text/javascript">
25661 * @class Roo.ColorPalette
25662 * @extends Roo.Component
25663 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25664 * Here's an example of typical usage:
25666 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25667 cp.render('my-div');
25669 cp.on('select', function(palette, selColor){
25670 // do something with selColor
25674 * Create a new ColorPalette
25675 * @param {Object} config The config object
25677 Roo.ColorPalette = function(config){
25678 Roo.ColorPalette.superclass.constructor.call(this, config);
25682 * Fires when a color is selected
25683 * @param {ColorPalette} this
25684 * @param {String} color The 6-digit color hex code (without the # symbol)
25690 this.on("select", this.handler, this.scope, true);
25693 Roo.extend(Roo.ColorPalette, Roo.Component, {
25695 * @cfg {String} itemCls
25696 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25698 itemCls : "x-color-palette",
25700 * @cfg {String} value
25701 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25702 * the hex codes are case-sensitive.
25705 clickEvent:'click',
25707 ctype: "Roo.ColorPalette",
25710 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25712 allowReselect : false,
25715 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25716 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25717 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25718 * of colors with the width setting until the box is symmetrical.</p>
25719 * <p>You can override individual colors if needed:</p>
25721 var cp = new Roo.ColorPalette();
25722 cp.colors[0] = "FF0000"; // change the first box to red
25725 Or you can provide a custom array of your own for complete control:
25727 var cp = new Roo.ColorPalette();
25728 cp.colors = ["000000", "993300", "333300"];
25733 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25734 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25735 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25736 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25737 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25741 onRender : function(container, position){
25742 var t = new Roo.MasterTemplate(
25743 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25745 var c = this.colors;
25746 for(var i = 0, len = c.length; i < len; i++){
25749 var el = document.createElement("div");
25750 el.className = this.itemCls;
25752 container.dom.insertBefore(el, position);
25753 this.el = Roo.get(el);
25754 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25755 if(this.clickEvent != 'click'){
25756 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25761 afterRender : function(){
25762 Roo.ColorPalette.superclass.afterRender.call(this);
25764 var s = this.value;
25771 handleClick : function(e, t){
25772 e.preventDefault();
25773 if(!this.disabled){
25774 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25775 this.select(c.toUpperCase());
25780 * Selects the specified color in the palette (fires the select event)
25781 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25783 select : function(color){
25784 color = color.replace("#", "");
25785 if(color != this.value || this.allowReselect){
25788 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25790 el.child("a.color-"+color).addClass("x-color-palette-sel");
25791 this.value = color;
25792 this.fireEvent("select", this, color);
25797 * Ext JS Library 1.1.1
25798 * Copyright(c) 2006-2007, Ext JS, LLC.
25800 * Originally Released Under LGPL - original licence link has changed is not relivant.
25803 * <script type="text/javascript">
25807 * @class Roo.DatePicker
25808 * @extends Roo.Component
25809 * Simple date picker class.
25811 * Create a new DatePicker
25812 * @param {Object} config The config object
25814 Roo.DatePicker = function(config){
25815 Roo.DatePicker.superclass.constructor.call(this, config);
25817 this.value = config && config.value ?
25818 config.value.clearTime() : new Date().clearTime();
25823 * Fires when a date is selected
25824 * @param {DatePicker} this
25825 * @param {Date} date The selected date
25829 * @event monthchange
25830 * Fires when the displayed month changes
25831 * @param {DatePicker} this
25832 * @param {Date} date The selected month
25834 'monthchange': true
25838 this.on("select", this.handler, this.scope || this);
25840 // build the disabledDatesRE
25841 if(!this.disabledDatesRE && this.disabledDates){
25842 var dd = this.disabledDates;
25844 for(var i = 0; i < dd.length; i++){
25846 if(i != dd.length-1) re += "|";
25848 this.disabledDatesRE = new RegExp(re + ")");
25852 Roo.extend(Roo.DatePicker, Roo.Component, {
25854 * @cfg {String} todayText
25855 * The text to display on the button that selects the current date (defaults to "Today")
25857 todayText : "Today",
25859 * @cfg {String} okText
25860 * The text to display on the ok button
25862 okText : " OK ", //   to give the user extra clicking room
25864 * @cfg {String} cancelText
25865 * The text to display on the cancel button
25867 cancelText : "Cancel",
25869 * @cfg {String} todayTip
25870 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25872 todayTip : "{0} (Spacebar)",
25874 * @cfg {Date} minDate
25875 * Minimum allowable date (JavaScript date object, defaults to null)
25879 * @cfg {Date} maxDate
25880 * Maximum allowable date (JavaScript date object, defaults to null)
25884 * @cfg {String} minText
25885 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25887 minText : "This date is before the minimum date",
25889 * @cfg {String} maxText
25890 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25892 maxText : "This date is after the maximum date",
25894 * @cfg {String} format
25895 * The default date format string which can be overriden for localization support. The format must be
25896 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25900 * @cfg {Array} disabledDays
25901 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25903 disabledDays : null,
25905 * @cfg {String} disabledDaysText
25906 * The tooltip to display when the date falls on a disabled day (defaults to "")
25908 disabledDaysText : "",
25910 * @cfg {RegExp} disabledDatesRE
25911 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25913 disabledDatesRE : null,
25915 * @cfg {String} disabledDatesText
25916 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25918 disabledDatesText : "",
25920 * @cfg {Boolean} constrainToViewport
25921 * True to constrain the date picker to the viewport (defaults to true)
25923 constrainToViewport : true,
25925 * @cfg {Array} monthNames
25926 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25928 monthNames : Date.monthNames,
25930 * @cfg {Array} dayNames
25931 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25933 dayNames : Date.dayNames,
25935 * @cfg {String} nextText
25936 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25938 nextText: 'Next Month (Control+Right)',
25940 * @cfg {String} prevText
25941 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25943 prevText: 'Previous Month (Control+Left)',
25945 * @cfg {String} monthYearText
25946 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25948 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25950 * @cfg {Number} startDay
25951 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25955 * @cfg {Bool} showClear
25956 * Show a clear button (usefull for date form elements that can be blank.)
25962 * Sets the value of the date field
25963 * @param {Date} value The date to set
25965 setValue : function(value){
25966 var old = this.value;
25968 if (typeof(value) == 'string') {
25970 value = Date.parseDate(value, this.format);
25973 value = new Date();
25976 this.value = value.clearTime(true);
25978 this.update(this.value);
25983 * Gets the current selected value of the date field
25984 * @return {Date} The selected date
25986 getValue : function(){
25991 focus : function(){
25993 this.update(this.activeDate);
25998 onRender : function(container, position){
26001 '<table cellspacing="0">',
26002 '<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>',
26003 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26004 var dn = this.dayNames;
26005 for(var i = 0; i < 7; i++){
26006 var d = this.startDay+i;
26010 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26012 m[m.length] = "</tr></thead><tbody><tr>";
26013 for(var i = 0; i < 42; i++) {
26014 if(i % 7 == 0 && i != 0){
26015 m[m.length] = "</tr><tr>";
26017 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26019 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26020 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26022 var el = document.createElement("div");
26023 el.className = "x-date-picker";
26024 el.innerHTML = m.join("");
26026 container.dom.insertBefore(el, position);
26028 this.el = Roo.get(el);
26029 this.eventEl = Roo.get(el.firstChild);
26031 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26032 handler: this.showPrevMonth,
26034 preventDefault:true,
26038 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26039 handler: this.showNextMonth,
26041 preventDefault:true,
26045 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26047 this.monthPicker = this.el.down('div.x-date-mp');
26048 this.monthPicker.enableDisplayMode('block');
26050 var kn = new Roo.KeyNav(this.eventEl, {
26051 "left" : function(e){
26053 this.showPrevMonth() :
26054 this.update(this.activeDate.add("d", -1));
26057 "right" : function(e){
26059 this.showNextMonth() :
26060 this.update(this.activeDate.add("d", 1));
26063 "up" : function(e){
26065 this.showNextYear() :
26066 this.update(this.activeDate.add("d", -7));
26069 "down" : function(e){
26071 this.showPrevYear() :
26072 this.update(this.activeDate.add("d", 7));
26075 "pageUp" : function(e){
26076 this.showNextMonth();
26079 "pageDown" : function(e){
26080 this.showPrevMonth();
26083 "enter" : function(e){
26084 e.stopPropagation();
26091 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26093 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26095 this.el.unselectable();
26097 this.cells = this.el.select("table.x-date-inner tbody td");
26098 this.textNodes = this.el.query("table.x-date-inner tbody span");
26100 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26102 tooltip: this.monthYearText
26105 this.mbtn.on('click', this.showMonthPicker, this);
26106 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26109 var today = (new Date()).dateFormat(this.format);
26111 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26112 if (this.showClear) {
26113 baseTb.add( new Roo.Toolbar.Fill());
26116 text: String.format(this.todayText, today),
26117 tooltip: String.format(this.todayTip, today),
26118 handler: this.selectToday,
26122 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26125 if (this.showClear) {
26127 baseTb.add( new Roo.Toolbar.Fill());
26130 cls: 'x-btn-icon x-btn-clear',
26131 handler: function() {
26133 this.fireEvent("select", this, '');
26143 this.update(this.value);
26146 createMonthPicker : function(){
26147 if(!this.monthPicker.dom.firstChild){
26148 var buf = ['<table border="0" cellspacing="0">'];
26149 for(var i = 0; i < 6; i++){
26151 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26152 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26154 '<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>' :
26155 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26159 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26161 '</button><button type="button" class="x-date-mp-cancel">',
26163 '</button></td></tr>',
26166 this.monthPicker.update(buf.join(''));
26167 this.monthPicker.on('click', this.onMonthClick, this);
26168 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26170 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26171 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26173 this.mpMonths.each(function(m, a, i){
26176 m.dom.xmonth = 5 + Math.round(i * .5);
26178 m.dom.xmonth = Math.round((i-1) * .5);
26184 showMonthPicker : function(){
26185 this.createMonthPicker();
26186 var size = this.el.getSize();
26187 this.monthPicker.setSize(size);
26188 this.monthPicker.child('table').setSize(size);
26190 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26191 this.updateMPMonth(this.mpSelMonth);
26192 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26193 this.updateMPYear(this.mpSelYear);
26195 this.monthPicker.slideIn('t', {duration:.2});
26198 updateMPYear : function(y){
26200 var ys = this.mpYears.elements;
26201 for(var i = 1; i <= 10; i++){
26202 var td = ys[i-1], y2;
26204 y2 = y + Math.round(i * .5);
26205 td.firstChild.innerHTML = y2;
26208 y2 = y - (5-Math.round(i * .5));
26209 td.firstChild.innerHTML = y2;
26212 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26216 updateMPMonth : function(sm){
26217 this.mpMonths.each(function(m, a, i){
26218 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26222 selectMPMonth: function(m){
26226 onMonthClick : function(e, t){
26228 var el = new Roo.Element(t), pn;
26229 if(el.is('button.x-date-mp-cancel')){
26230 this.hideMonthPicker();
26232 else if(el.is('button.x-date-mp-ok')){
26233 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26234 this.hideMonthPicker();
26236 else if(pn = el.up('td.x-date-mp-month', 2)){
26237 this.mpMonths.removeClass('x-date-mp-sel');
26238 pn.addClass('x-date-mp-sel');
26239 this.mpSelMonth = pn.dom.xmonth;
26241 else if(pn = el.up('td.x-date-mp-year', 2)){
26242 this.mpYears.removeClass('x-date-mp-sel');
26243 pn.addClass('x-date-mp-sel');
26244 this.mpSelYear = pn.dom.xyear;
26246 else if(el.is('a.x-date-mp-prev')){
26247 this.updateMPYear(this.mpyear-10);
26249 else if(el.is('a.x-date-mp-next')){
26250 this.updateMPYear(this.mpyear+10);
26254 onMonthDblClick : function(e, t){
26256 var el = new Roo.Element(t), pn;
26257 if(pn = el.up('td.x-date-mp-month', 2)){
26258 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26259 this.hideMonthPicker();
26261 else if(pn = el.up('td.x-date-mp-year', 2)){
26262 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26263 this.hideMonthPicker();
26267 hideMonthPicker : function(disableAnim){
26268 if(this.monthPicker){
26269 if(disableAnim === true){
26270 this.monthPicker.hide();
26272 this.monthPicker.slideOut('t', {duration:.2});
26278 showPrevMonth : function(e){
26279 this.update(this.activeDate.add("mo", -1));
26283 showNextMonth : function(e){
26284 this.update(this.activeDate.add("mo", 1));
26288 showPrevYear : function(){
26289 this.update(this.activeDate.add("y", -1));
26293 showNextYear : function(){
26294 this.update(this.activeDate.add("y", 1));
26298 handleMouseWheel : function(e){
26299 var delta = e.getWheelDelta();
26301 this.showPrevMonth();
26303 } else if(delta < 0){
26304 this.showNextMonth();
26310 handleDateClick : function(e, t){
26312 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26313 this.setValue(new Date(t.dateValue));
26314 this.fireEvent("select", this, this.value);
26319 selectToday : function(){
26320 this.setValue(new Date().clearTime());
26321 this.fireEvent("select", this, this.value);
26325 update : function(date)
26327 var vd = this.activeDate;
26328 this.activeDate = date;
26330 var t = date.getTime();
26331 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26332 this.cells.removeClass("x-date-selected");
26333 this.cells.each(function(c){
26334 if(c.dom.firstChild.dateValue == t){
26335 c.addClass("x-date-selected");
26336 setTimeout(function(){
26337 try{c.dom.firstChild.focus();}catch(e){}
26346 var days = date.getDaysInMonth();
26347 var firstOfMonth = date.getFirstDateOfMonth();
26348 var startingPos = firstOfMonth.getDay()-this.startDay;
26350 if(startingPos <= this.startDay){
26354 var pm = date.add("mo", -1);
26355 var prevStart = pm.getDaysInMonth()-startingPos;
26357 var cells = this.cells.elements;
26358 var textEls = this.textNodes;
26359 days += startingPos;
26361 // convert everything to numbers so it's fast
26362 var day = 86400000;
26363 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26364 var today = new Date().clearTime().getTime();
26365 var sel = date.clearTime().getTime();
26366 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26367 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26368 var ddMatch = this.disabledDatesRE;
26369 var ddText = this.disabledDatesText;
26370 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26371 var ddaysText = this.disabledDaysText;
26372 var format = this.format;
26374 var setCellClass = function(cal, cell){
26376 var t = d.getTime();
26377 cell.firstChild.dateValue = t;
26379 cell.className += " x-date-today";
26380 cell.title = cal.todayText;
26383 cell.className += " x-date-selected";
26384 setTimeout(function(){
26385 try{cell.firstChild.focus();}catch(e){}
26390 cell.className = " x-date-disabled";
26391 cell.title = cal.minText;
26395 cell.className = " x-date-disabled";
26396 cell.title = cal.maxText;
26400 if(ddays.indexOf(d.getDay()) != -1){
26401 cell.title = ddaysText;
26402 cell.className = " x-date-disabled";
26405 if(ddMatch && format){
26406 var fvalue = d.dateFormat(format);
26407 if(ddMatch.test(fvalue)){
26408 cell.title = ddText.replace("%0", fvalue);
26409 cell.className = " x-date-disabled";
26415 for(; i < startingPos; i++) {
26416 textEls[i].innerHTML = (++prevStart);
26417 d.setDate(d.getDate()+1);
26418 cells[i].className = "x-date-prevday";
26419 setCellClass(this, cells[i]);
26421 for(; i < days; i++){
26422 intDay = i - startingPos + 1;
26423 textEls[i].innerHTML = (intDay);
26424 d.setDate(d.getDate()+1);
26425 cells[i].className = "x-date-active";
26426 setCellClass(this, cells[i]);
26429 for(; i < 42; i++) {
26430 textEls[i].innerHTML = (++extraDays);
26431 d.setDate(d.getDate()+1);
26432 cells[i].className = "x-date-nextday";
26433 setCellClass(this, cells[i]);
26436 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26437 this.fireEvent('monthchange', this, date);
26439 if(!this.internalRender){
26440 var main = this.el.dom.firstChild;
26441 var w = main.offsetWidth;
26442 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26443 Roo.fly(main).setWidth(w);
26444 this.internalRender = true;
26445 // opera does not respect the auto grow header center column
26446 // then, after it gets a width opera refuses to recalculate
26447 // without a second pass
26448 if(Roo.isOpera && !this.secondPass){
26449 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26450 this.secondPass = true;
26451 this.update.defer(10, this, [date]);
26459 * Ext JS Library 1.1.1
26460 * Copyright(c) 2006-2007, Ext JS, LLC.
26462 * Originally Released Under LGPL - original licence link has changed is not relivant.
26465 * <script type="text/javascript">
26468 * @class Roo.TabPanel
26469 * @extends Roo.util.Observable
26470 * A lightweight tab container.
26474 // basic tabs 1, built from existing content
26475 var tabs = new Roo.TabPanel("tabs1");
26476 tabs.addTab("script", "View Script");
26477 tabs.addTab("markup", "View Markup");
26478 tabs.activate("script");
26480 // more advanced tabs, built from javascript
26481 var jtabs = new Roo.TabPanel("jtabs");
26482 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26484 // set up the UpdateManager
26485 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26486 var updater = tab2.getUpdateManager();
26487 updater.setDefaultUrl("ajax1.htm");
26488 tab2.on('activate', updater.refresh, updater, true);
26490 // Use setUrl for Ajax loading
26491 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26492 tab3.setUrl("ajax2.htm", null, true);
26495 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26498 jtabs.activate("jtabs-1");
26501 * Create a new TabPanel.
26502 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26503 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26505 Roo.TabPanel = function(container, config){
26507 * The container element for this TabPanel.
26508 * @type Roo.Element
26510 this.el = Roo.get(container, true);
26512 if(typeof config == "boolean"){
26513 this.tabPosition = config ? "bottom" : "top";
26515 Roo.apply(this, config);
26518 if(this.tabPosition == "bottom"){
26519 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26520 this.el.addClass("x-tabs-bottom");
26522 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26523 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26524 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26526 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26528 if(this.tabPosition != "bottom"){
26529 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26530 * @type Roo.Element
26532 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26533 this.el.addClass("x-tabs-top");
26537 this.bodyEl.setStyle("position", "relative");
26539 this.active = null;
26540 this.activateDelegate = this.activate.createDelegate(this);
26545 * Fires when the active tab changes
26546 * @param {Roo.TabPanel} this
26547 * @param {Roo.TabPanelItem} activePanel The new active tab
26551 * @event beforetabchange
26552 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26553 * @param {Roo.TabPanel} this
26554 * @param {Object} e Set cancel to true on this object to cancel the tab change
26555 * @param {Roo.TabPanelItem} tab The tab being changed to
26557 "beforetabchange" : true
26560 Roo.EventManager.onWindowResize(this.onResize, this);
26561 this.cpad = this.el.getPadding("lr");
26562 this.hiddenCount = 0;
26565 // toolbar on the tabbar support...
26566 if (this.toolbar) {
26567 var tcfg = this.toolbar;
26568 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26569 this.toolbar = new Roo.Toolbar(tcfg);
26570 if (Roo.isSafari) {
26571 var tbl = tcfg.container.child('table', true);
26572 tbl.setAttribute('width', '100%');
26579 Roo.TabPanel.superclass.constructor.call(this);
26582 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26584 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26586 tabPosition : "top",
26588 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26590 currentTabWidth : 0,
26592 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26596 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26600 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26602 preferredTabWidth : 175,
26604 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26606 resizeTabs : false,
26608 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26610 monitorResize : true,
26612 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26617 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26618 * @param {String} id The id of the div to use <b>or create</b>
26619 * @param {String} text The text for the tab
26620 * @param {String} content (optional) Content to put in the TabPanelItem body
26621 * @param {Boolean} closable (optional) True to create a close icon on the tab
26622 * @return {Roo.TabPanelItem} The created TabPanelItem
26624 addTab : function(id, text, content, closable){
26625 var item = new Roo.TabPanelItem(this, id, text, closable);
26626 this.addTabItem(item);
26628 item.setContent(content);
26634 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26635 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26636 * @return {Roo.TabPanelItem}
26638 getTab : function(id){
26639 return this.items[id];
26643 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26644 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26646 hideTab : function(id){
26647 var t = this.items[id];
26650 this.hiddenCount++;
26651 this.autoSizeTabs();
26656 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26657 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26659 unhideTab : function(id){
26660 var t = this.items[id];
26662 t.setHidden(false);
26663 this.hiddenCount--;
26664 this.autoSizeTabs();
26669 * Adds an existing {@link Roo.TabPanelItem}.
26670 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26672 addTabItem : function(item){
26673 this.items[item.id] = item;
26674 this.items.push(item);
26675 if(this.resizeTabs){
26676 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26677 this.autoSizeTabs();
26684 * Removes a {@link Roo.TabPanelItem}.
26685 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26687 removeTab : function(id){
26688 var items = this.items;
26689 var tab = items[id];
26690 if(!tab) { return; }
26691 var index = items.indexOf(tab);
26692 if(this.active == tab && items.length > 1){
26693 var newTab = this.getNextAvailable(index);
26698 this.stripEl.dom.removeChild(tab.pnode.dom);
26699 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26700 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26702 items.splice(index, 1);
26703 delete this.items[tab.id];
26704 tab.fireEvent("close", tab);
26705 tab.purgeListeners();
26706 this.autoSizeTabs();
26709 getNextAvailable : function(start){
26710 var items = this.items;
26712 // look for a next tab that will slide over to
26713 // replace the one being removed
26714 while(index < items.length){
26715 var item = items[++index];
26716 if(item && !item.isHidden()){
26720 // if one isn't found select the previous tab (on the left)
26723 var item = items[--index];
26724 if(item && !item.isHidden()){
26732 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26733 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26735 disableTab : function(id){
26736 var tab = this.items[id];
26737 if(tab && this.active != tab){
26743 * Enables a {@link Roo.TabPanelItem} that is disabled.
26744 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26746 enableTab : function(id){
26747 var tab = this.items[id];
26752 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26753 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26754 * @return {Roo.TabPanelItem} The TabPanelItem.
26756 activate : function(id){
26757 var tab = this.items[id];
26761 if(tab == this.active || tab.disabled){
26765 this.fireEvent("beforetabchange", this, e, tab);
26766 if(e.cancel !== true && !tab.disabled){
26768 this.active.hide();
26770 this.active = this.items[id];
26771 this.active.show();
26772 this.fireEvent("tabchange", this, this.active);
26778 * Gets the active {@link Roo.TabPanelItem}.
26779 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26781 getActiveTab : function(){
26782 return this.active;
26786 * Updates the tab body element to fit the height of the container element
26787 * for overflow scrolling
26788 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26790 syncHeight : function(targetHeight){
26791 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26792 var bm = this.bodyEl.getMargins();
26793 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26794 this.bodyEl.setHeight(newHeight);
26798 onResize : function(){
26799 if(this.monitorResize){
26800 this.autoSizeTabs();
26805 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26807 beginUpdate : function(){
26808 this.updating = true;
26812 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26814 endUpdate : function(){
26815 this.updating = false;
26816 this.autoSizeTabs();
26820 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26822 autoSizeTabs : function(){
26823 var count = this.items.length;
26824 var vcount = count - this.hiddenCount;
26825 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26826 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26827 var availWidth = Math.floor(w / vcount);
26828 var b = this.stripBody;
26829 if(b.getWidth() > w){
26830 var tabs = this.items;
26831 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26832 if(availWidth < this.minTabWidth){
26833 /*if(!this.sleft){ // incomplete scrolling code
26834 this.createScrollButtons();
26837 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26840 if(this.currentTabWidth < this.preferredTabWidth){
26841 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26847 * Returns the number of tabs in this TabPanel.
26850 getCount : function(){
26851 return this.items.length;
26855 * Resizes all the tabs to the passed width
26856 * @param {Number} The new width
26858 setTabWidth : function(width){
26859 this.currentTabWidth = width;
26860 for(var i = 0, len = this.items.length; i < len; i++) {
26861 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26866 * Destroys this TabPanel
26867 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26869 destroy : function(removeEl){
26870 Roo.EventManager.removeResizeListener(this.onResize, this);
26871 for(var i = 0, len = this.items.length; i < len; i++){
26872 this.items[i].purgeListeners();
26874 if(removeEl === true){
26875 this.el.update("");
26882 * @class Roo.TabPanelItem
26883 * @extends Roo.util.Observable
26884 * Represents an individual item (tab plus body) in a TabPanel.
26885 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26886 * @param {String} id The id of this TabPanelItem
26887 * @param {String} text The text for the tab of this TabPanelItem
26888 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26890 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26892 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26893 * @type Roo.TabPanel
26895 this.tabPanel = tabPanel;
26897 * The id for this TabPanelItem
26902 this.disabled = false;
26906 this.loaded = false;
26907 this.closable = closable;
26910 * The body element for this TabPanelItem.
26911 * @type Roo.Element
26913 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26914 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26915 this.bodyEl.setStyle("display", "block");
26916 this.bodyEl.setStyle("zoom", "1");
26919 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26921 this.el = Roo.get(els.el, true);
26922 this.inner = Roo.get(els.inner, true);
26923 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26924 this.pnode = Roo.get(els.el.parentNode, true);
26925 this.el.on("mousedown", this.onTabMouseDown, this);
26926 this.el.on("click", this.onTabClick, this);
26929 var c = Roo.get(els.close, true);
26930 c.dom.title = this.closeText;
26931 c.addClassOnOver("close-over");
26932 c.on("click", this.closeClick, this);
26938 * Fires when this tab becomes the active tab.
26939 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26940 * @param {Roo.TabPanelItem} this
26944 * @event beforeclose
26945 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26946 * @param {Roo.TabPanelItem} this
26947 * @param {Object} e Set cancel to true on this object to cancel the close.
26949 "beforeclose": true,
26952 * Fires when this tab is closed.
26953 * @param {Roo.TabPanelItem} this
26957 * @event deactivate
26958 * Fires when this tab is no longer the active tab.
26959 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26960 * @param {Roo.TabPanelItem} this
26962 "deactivate" : true
26964 this.hidden = false;
26966 Roo.TabPanelItem.superclass.constructor.call(this);
26969 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26970 purgeListeners : function(){
26971 Roo.util.Observable.prototype.purgeListeners.call(this);
26972 this.el.removeAllListeners();
26975 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26978 this.pnode.addClass("on");
26981 this.tabPanel.stripWrap.repaint();
26983 this.fireEvent("activate", this.tabPanel, this);
26987 * Returns true if this tab is the active tab.
26988 * @return {Boolean}
26990 isActive : function(){
26991 return this.tabPanel.getActiveTab() == this;
26995 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
26998 this.pnode.removeClass("on");
27000 this.fireEvent("deactivate", this.tabPanel, this);
27003 hideAction : function(){
27004 this.bodyEl.hide();
27005 this.bodyEl.setStyle("position", "absolute");
27006 this.bodyEl.setLeft("-20000px");
27007 this.bodyEl.setTop("-20000px");
27010 showAction : function(){
27011 this.bodyEl.setStyle("position", "relative");
27012 this.bodyEl.setTop("");
27013 this.bodyEl.setLeft("");
27014 this.bodyEl.show();
27018 * Set the tooltip for the tab.
27019 * @param {String} tooltip The tab's tooltip
27021 setTooltip : function(text){
27022 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27023 this.textEl.dom.qtip = text;
27024 this.textEl.dom.removeAttribute('title');
27026 this.textEl.dom.title = text;
27030 onTabClick : function(e){
27031 e.preventDefault();
27032 this.tabPanel.activate(this.id);
27035 onTabMouseDown : function(e){
27036 e.preventDefault();
27037 this.tabPanel.activate(this.id);
27040 getWidth : function(){
27041 return this.inner.getWidth();
27044 setWidth : function(width){
27045 var iwidth = width - this.pnode.getPadding("lr");
27046 this.inner.setWidth(iwidth);
27047 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27048 this.pnode.setWidth(width);
27052 * Show or hide the tab
27053 * @param {Boolean} hidden True to hide or false to show.
27055 setHidden : function(hidden){
27056 this.hidden = hidden;
27057 this.pnode.setStyle("display", hidden ? "none" : "");
27061 * Returns true if this tab is "hidden"
27062 * @return {Boolean}
27064 isHidden : function(){
27065 return this.hidden;
27069 * Returns the text for this tab
27072 getText : function(){
27076 autoSize : function(){
27077 //this.el.beginMeasure();
27078 this.textEl.setWidth(1);
27079 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
27080 //this.el.endMeasure();
27084 * Sets the text for the tab (Note: this also sets the tooltip text)
27085 * @param {String} text The tab's text and tooltip
27087 setText : function(text){
27089 this.textEl.update(text);
27090 this.setTooltip(text);
27091 if(!this.tabPanel.resizeTabs){
27096 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27098 activate : function(){
27099 this.tabPanel.activate(this.id);
27103 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27105 disable : function(){
27106 if(this.tabPanel.active != this){
27107 this.disabled = true;
27108 this.pnode.addClass("disabled");
27113 * Enables this TabPanelItem if it was previously disabled.
27115 enable : function(){
27116 this.disabled = false;
27117 this.pnode.removeClass("disabled");
27121 * Sets the content for this TabPanelItem.
27122 * @param {String} content The content
27123 * @param {Boolean} loadScripts true to look for and load scripts
27125 setContent : function(content, loadScripts){
27126 this.bodyEl.update(content, loadScripts);
27130 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27131 * @return {Roo.UpdateManager} The UpdateManager
27133 getUpdateManager : function(){
27134 return this.bodyEl.getUpdateManager();
27138 * Set a URL to be used to load the content for this TabPanelItem.
27139 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27140 * @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)
27141 * @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)
27142 * @return {Roo.UpdateManager} The UpdateManager
27144 setUrl : function(url, params, loadOnce){
27145 if(this.refreshDelegate){
27146 this.un('activate', this.refreshDelegate);
27148 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27149 this.on("activate", this.refreshDelegate);
27150 return this.bodyEl.getUpdateManager();
27154 _handleRefresh : function(url, params, loadOnce){
27155 if(!loadOnce || !this.loaded){
27156 var updater = this.bodyEl.getUpdateManager();
27157 updater.update(url, params, this._setLoaded.createDelegate(this));
27162 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27163 * Will fail silently if the setUrl method has not been called.
27164 * This does not activate the panel, just updates its content.
27166 refresh : function(){
27167 if(this.refreshDelegate){
27168 this.loaded = false;
27169 this.refreshDelegate();
27174 _setLoaded : function(){
27175 this.loaded = true;
27179 closeClick : function(e){
27182 this.fireEvent("beforeclose", this, o);
27183 if(o.cancel !== true){
27184 this.tabPanel.removeTab(this.id);
27188 * The text displayed in the tooltip for the close icon.
27191 closeText : "Close this tab"
27195 Roo.TabPanel.prototype.createStrip = function(container){
27196 var strip = document.createElement("div");
27197 strip.className = "x-tabs-wrap";
27198 container.appendChild(strip);
27202 Roo.TabPanel.prototype.createStripList = function(strip){
27203 // div wrapper for retard IE
27204 // returns the "tr" element.
27205 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27206 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27207 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27208 return strip.firstChild.firstChild.firstChild.firstChild;
27211 Roo.TabPanel.prototype.createBody = function(container){
27212 var body = document.createElement("div");
27213 Roo.id(body, "tab-body");
27214 Roo.fly(body).addClass("x-tabs-body");
27215 container.appendChild(body);
27219 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27220 var body = Roo.getDom(id);
27222 body = document.createElement("div");
27225 Roo.fly(body).addClass("x-tabs-item-body");
27226 bodyEl.insertBefore(body, bodyEl.firstChild);
27230 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27231 var td = document.createElement("td");
27232 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27233 //stripEl.appendChild(td);
27235 td.className = "x-tabs-closable";
27236 if(!this.closeTpl){
27237 this.closeTpl = new Roo.Template(
27238 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27239 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27240 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27243 var el = this.closeTpl.overwrite(td, {"text": text});
27244 var close = el.getElementsByTagName("div")[0];
27245 var inner = el.getElementsByTagName("em")[0];
27246 return {"el": el, "close": close, "inner": inner};
27249 this.tabTpl = new Roo.Template(
27250 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27251 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27254 var el = this.tabTpl.overwrite(td, {"text": text});
27255 var inner = el.getElementsByTagName("em")[0];
27256 return {"el": el, "inner": inner};
27260 * Ext JS Library 1.1.1
27261 * Copyright(c) 2006-2007, Ext JS, LLC.
27263 * Originally Released Under LGPL - original licence link has changed is not relivant.
27266 * <script type="text/javascript">
27270 * @class Roo.Button
27271 * @extends Roo.util.Observable
27272 * Simple Button class
27273 * @cfg {String} text The button text
27274 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27275 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27276 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27277 * @cfg {Object} scope The scope of the handler
27278 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27279 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27280 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27281 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27282 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27283 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27284 applies if enableToggle = true)
27285 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27286 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27287 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27289 * Create a new button
27290 * @param {Object} config The config object
27292 Roo.Button = function(renderTo, config)
27296 renderTo = config.renderTo || false;
27299 Roo.apply(this, config);
27303 * Fires when this button is clicked
27304 * @param {Button} this
27305 * @param {EventObject} e The click event
27310 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27311 * @param {Button} this
27312 * @param {Boolean} pressed
27317 * Fires when the mouse hovers over the button
27318 * @param {Button} this
27319 * @param {Event} e The event object
27321 'mouseover' : true,
27324 * Fires when the mouse exits the button
27325 * @param {Button} this
27326 * @param {Event} e The event object
27331 * Fires when the button is rendered
27332 * @param {Button} this
27337 this.menu = Roo.menu.MenuMgr.get(this.menu);
27339 // register listeners first!! - so render can be captured..
27340 Roo.util.Observable.call(this);
27342 this.render(renderTo);
27348 Roo.extend(Roo.Button, Roo.util.Observable, {
27354 * Read-only. True if this button is hidden
27359 * Read-only. True if this button is disabled
27364 * Read-only. True if this button is pressed (only if enableToggle = true)
27370 * @cfg {Number} tabIndex
27371 * The DOM tabIndex for this button (defaults to undefined)
27373 tabIndex : undefined,
27376 * @cfg {Boolean} enableToggle
27377 * True to enable pressed/not pressed toggling (defaults to false)
27379 enableToggle: false,
27381 * @cfg {Mixed} menu
27382 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27386 * @cfg {String} menuAlign
27387 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27389 menuAlign : "tl-bl?",
27392 * @cfg {String} iconCls
27393 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27395 iconCls : undefined,
27397 * @cfg {String} type
27398 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27403 menuClassTarget: 'tr',
27406 * @cfg {String} clickEvent
27407 * The type of event to map to the button's event handler (defaults to 'click')
27409 clickEvent : 'click',
27412 * @cfg {Boolean} handleMouseEvents
27413 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27415 handleMouseEvents : true,
27418 * @cfg {String} tooltipType
27419 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27421 tooltipType : 'qtip',
27424 * @cfg {String} cls
27425 * A CSS class to apply to the button's main element.
27429 * @cfg {Roo.Template} template (Optional)
27430 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27431 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27432 * require code modifications if required elements (e.g. a button) aren't present.
27436 render : function(renderTo){
27438 if(this.hideParent){
27439 this.parentEl = Roo.get(renderTo);
27441 if(!this.dhconfig){
27442 if(!this.template){
27443 if(!Roo.Button.buttonTemplate){
27444 // hideous table template
27445 Roo.Button.buttonTemplate = new Roo.Template(
27446 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27447 '<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>',
27448 "</tr></tbody></table>");
27450 this.template = Roo.Button.buttonTemplate;
27452 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27453 var btnEl = btn.child("button:first");
27454 btnEl.on('focus', this.onFocus, this);
27455 btnEl.on('blur', this.onBlur, this);
27457 btn.addClass(this.cls);
27460 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27463 btnEl.addClass(this.iconCls);
27465 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27468 if(this.tabIndex !== undefined){
27469 btnEl.dom.tabIndex = this.tabIndex;
27472 if(typeof this.tooltip == 'object'){
27473 Roo.QuickTips.tips(Roo.apply({
27477 btnEl.dom[this.tooltipType] = this.tooltip;
27481 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27485 this.el.dom.id = this.el.id = this.id;
27488 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27489 this.menu.on("show", this.onMenuShow, this);
27490 this.menu.on("hide", this.onMenuHide, this);
27492 btn.addClass("x-btn");
27493 if(Roo.isIE && !Roo.isIE7){
27494 this.autoWidth.defer(1, this);
27498 if(this.handleMouseEvents){
27499 btn.on("mouseover", this.onMouseOver, this);
27500 btn.on("mouseout", this.onMouseOut, this);
27501 btn.on("mousedown", this.onMouseDown, this);
27503 btn.on(this.clickEvent, this.onClick, this);
27504 //btn.on("mouseup", this.onMouseUp, this);
27511 Roo.ButtonToggleMgr.register(this);
27513 this.el.addClass("x-btn-pressed");
27516 var repeater = new Roo.util.ClickRepeater(btn,
27517 typeof this.repeat == "object" ? this.repeat : {}
27519 repeater.on("click", this.onClick, this);
27522 this.fireEvent('render', this);
27526 * Returns the button's underlying element
27527 * @return {Roo.Element} The element
27529 getEl : function(){
27534 * Destroys this Button and removes any listeners.
27536 destroy : function(){
27537 Roo.ButtonToggleMgr.unregister(this);
27538 this.el.removeAllListeners();
27539 this.purgeListeners();
27544 autoWidth : function(){
27546 this.el.setWidth("auto");
27547 if(Roo.isIE7 && Roo.isStrict){
27548 var ib = this.el.child('button');
27549 if(ib && ib.getWidth() > 20){
27551 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27556 this.el.beginMeasure();
27558 if(this.el.getWidth() < this.minWidth){
27559 this.el.setWidth(this.minWidth);
27562 this.el.endMeasure();
27569 * Assigns this button's click handler
27570 * @param {Function} handler The function to call when the button is clicked
27571 * @param {Object} scope (optional) Scope for the function passed in
27573 setHandler : function(handler, scope){
27574 this.handler = handler;
27575 this.scope = scope;
27579 * Sets this button's text
27580 * @param {String} text The button text
27582 setText : function(text){
27585 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27591 * Gets the text for this button
27592 * @return {String} The button text
27594 getText : function(){
27602 this.hidden = false;
27604 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27612 this.hidden = true;
27614 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27619 * Convenience function for boolean show/hide
27620 * @param {Boolean} visible True to show, false to hide
27622 setVisible: function(visible){
27631 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27632 * @param {Boolean} state (optional) Force a particular state
27634 toggle : function(state){
27635 state = state === undefined ? !this.pressed : state;
27636 if(state != this.pressed){
27638 this.el.addClass("x-btn-pressed");
27639 this.pressed = true;
27640 this.fireEvent("toggle", this, true);
27642 this.el.removeClass("x-btn-pressed");
27643 this.pressed = false;
27644 this.fireEvent("toggle", this, false);
27646 if(this.toggleHandler){
27647 this.toggleHandler.call(this.scope || this, this, state);
27655 focus : function(){
27656 this.el.child('button:first').focus();
27660 * Disable this button
27662 disable : function(){
27664 this.el.addClass("x-btn-disabled");
27666 this.disabled = true;
27670 * Enable this button
27672 enable : function(){
27674 this.el.removeClass("x-btn-disabled");
27676 this.disabled = false;
27680 * Convenience function for boolean enable/disable
27681 * @param {Boolean} enabled True to enable, false to disable
27683 setDisabled : function(v){
27684 this[v !== true ? "enable" : "disable"]();
27688 onClick : function(e){
27690 e.preventDefault();
27695 if(!this.disabled){
27696 if(this.enableToggle){
27699 if(this.menu && !this.menu.isVisible()){
27700 this.menu.show(this.el, this.menuAlign);
27702 this.fireEvent("click", this, e);
27704 this.el.removeClass("x-btn-over");
27705 this.handler.call(this.scope || this, this, e);
27710 onMouseOver : function(e){
27711 if(!this.disabled){
27712 this.el.addClass("x-btn-over");
27713 this.fireEvent('mouseover', this, e);
27717 onMouseOut : function(e){
27718 if(!e.within(this.el, true)){
27719 this.el.removeClass("x-btn-over");
27720 this.fireEvent('mouseout', this, e);
27724 onFocus : function(e){
27725 if(!this.disabled){
27726 this.el.addClass("x-btn-focus");
27730 onBlur : function(e){
27731 this.el.removeClass("x-btn-focus");
27734 onMouseDown : function(e){
27735 if(!this.disabled && e.button == 0){
27736 this.el.addClass("x-btn-click");
27737 Roo.get(document).on('mouseup', this.onMouseUp, this);
27741 onMouseUp : function(e){
27743 this.el.removeClass("x-btn-click");
27744 Roo.get(document).un('mouseup', this.onMouseUp, this);
27748 onMenuShow : function(e){
27749 this.el.addClass("x-btn-menu-active");
27752 onMenuHide : function(e){
27753 this.el.removeClass("x-btn-menu-active");
27757 // Private utility class used by Button
27758 Roo.ButtonToggleMgr = function(){
27761 function toggleGroup(btn, state){
27763 var g = groups[btn.toggleGroup];
27764 for(var i = 0, l = g.length; i < l; i++){
27766 g[i].toggle(false);
27773 register : function(btn){
27774 if(!btn.toggleGroup){
27777 var g = groups[btn.toggleGroup];
27779 g = groups[btn.toggleGroup] = [];
27782 btn.on("toggle", toggleGroup);
27785 unregister : function(btn){
27786 if(!btn.toggleGroup){
27789 var g = groups[btn.toggleGroup];
27792 btn.un("toggle", toggleGroup);
27798 * Ext JS Library 1.1.1
27799 * Copyright(c) 2006-2007, Ext JS, LLC.
27801 * Originally Released Under LGPL - original licence link has changed is not relivant.
27804 * <script type="text/javascript">
27808 * @class Roo.SplitButton
27809 * @extends Roo.Button
27810 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27811 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27812 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27813 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27814 * @cfg {String} arrowTooltip The title attribute of the arrow
27816 * Create a new menu button
27817 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27818 * @param {Object} config The config object
27820 Roo.SplitButton = function(renderTo, config){
27821 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27823 * @event arrowclick
27824 * Fires when this button's arrow is clicked
27825 * @param {SplitButton} this
27826 * @param {EventObject} e The click event
27828 this.addEvents({"arrowclick":true});
27831 Roo.extend(Roo.SplitButton, Roo.Button, {
27832 render : function(renderTo){
27833 // this is one sweet looking template!
27834 var tpl = new Roo.Template(
27835 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27836 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27837 '<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>',
27838 "</tbody></table></td><td>",
27839 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27840 '<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>',
27841 "</tbody></table></td></tr></table>"
27843 var btn = tpl.append(renderTo, [this.text, this.type], true);
27844 var btnEl = btn.child("button");
27846 btn.addClass(this.cls);
27849 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27852 btnEl.addClass(this.iconCls);
27854 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27858 if(this.handleMouseEvents){
27859 btn.on("mouseover", this.onMouseOver, this);
27860 btn.on("mouseout", this.onMouseOut, this);
27861 btn.on("mousedown", this.onMouseDown, this);
27862 btn.on("mouseup", this.onMouseUp, this);
27864 btn.on(this.clickEvent, this.onClick, this);
27866 if(typeof this.tooltip == 'object'){
27867 Roo.QuickTips.tips(Roo.apply({
27871 btnEl.dom[this.tooltipType] = this.tooltip;
27874 if(this.arrowTooltip){
27875 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27884 this.el.addClass("x-btn-pressed");
27886 if(Roo.isIE && !Roo.isIE7){
27887 this.autoWidth.defer(1, this);
27892 this.menu.on("show", this.onMenuShow, this);
27893 this.menu.on("hide", this.onMenuHide, this);
27895 this.fireEvent('render', this);
27899 autoWidth : function(){
27901 var tbl = this.el.child("table:first");
27902 var tbl2 = this.el.child("table:last");
27903 this.el.setWidth("auto");
27904 tbl.setWidth("auto");
27905 if(Roo.isIE7 && Roo.isStrict){
27906 var ib = this.el.child('button:first');
27907 if(ib && ib.getWidth() > 20){
27909 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27914 this.el.beginMeasure();
27916 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27917 tbl.setWidth(this.minWidth-tbl2.getWidth());
27920 this.el.endMeasure();
27923 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27927 * Sets this button's click handler
27928 * @param {Function} handler The function to call when the button is clicked
27929 * @param {Object} scope (optional) Scope for the function passed above
27931 setHandler : function(handler, scope){
27932 this.handler = handler;
27933 this.scope = scope;
27937 * Sets this button's arrow click handler
27938 * @param {Function} handler The function to call when the arrow is clicked
27939 * @param {Object} scope (optional) Scope for the function passed above
27941 setArrowHandler : function(handler, scope){
27942 this.arrowHandler = handler;
27943 this.scope = scope;
27949 focus : function(){
27951 this.el.child("button:first").focus();
27956 onClick : function(e){
27957 e.preventDefault();
27958 if(!this.disabled){
27959 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27960 if(this.menu && !this.menu.isVisible()){
27961 this.menu.show(this.el, this.menuAlign);
27963 this.fireEvent("arrowclick", this, e);
27964 if(this.arrowHandler){
27965 this.arrowHandler.call(this.scope || this, this, e);
27968 this.fireEvent("click", this, e);
27970 this.handler.call(this.scope || this, this, e);
27976 onMouseDown : function(e){
27977 if(!this.disabled){
27978 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27982 onMouseUp : function(e){
27983 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27988 // backwards compat
27989 Roo.MenuButton = Roo.SplitButton;/*
27991 * Ext JS Library 1.1.1
27992 * Copyright(c) 2006-2007, Ext JS, LLC.
27994 * Originally Released Under LGPL - original licence link has changed is not relivant.
27997 * <script type="text/javascript">
28001 * @class Roo.Toolbar
28002 * Basic Toolbar class.
28004 * Creates a new Toolbar
28005 * @param {Object} container The config object
28007 Roo.Toolbar = function(container, buttons, config)
28009 /// old consturctor format still supported..
28010 if(container instanceof Array){ // omit the container for later rendering
28011 buttons = container;
28015 if (typeof(container) == 'object' && container.xtype) {
28016 config = container;
28017 container = config.container;
28018 buttons = config.buttons || []; // not really - use items!!
28021 if (config && config.items) {
28022 xitems = config.items;
28023 delete config.items;
28025 Roo.apply(this, config);
28026 this.buttons = buttons;
28029 this.render(container);
28031 this.xitems = xitems;
28032 Roo.each(xitems, function(b) {
28038 Roo.Toolbar.prototype = {
28040 * @cfg {Array} items
28041 * array of button configs or elements to add (will be converted to a MixedCollection)
28045 * @cfg {String/HTMLElement/Element} container
28046 * The id or element that will contain the toolbar
28049 render : function(ct){
28050 this.el = Roo.get(ct);
28052 this.el.addClass(this.cls);
28054 // using a table allows for vertical alignment
28055 // 100% width is needed by Safari...
28056 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28057 this.tr = this.el.child("tr", true);
28059 this.items = new Roo.util.MixedCollection(false, function(o){
28060 return o.id || ("item" + (++autoId));
28063 this.add.apply(this, this.buttons);
28064 delete this.buttons;
28069 * Adds element(s) to the toolbar -- this function takes a variable number of
28070 * arguments of mixed type and adds them to the toolbar.
28071 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28073 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28074 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28075 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28076 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28077 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28078 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28079 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28080 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28081 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28083 * @param {Mixed} arg2
28084 * @param {Mixed} etc.
28087 var a = arguments, l = a.length;
28088 for(var i = 0; i < l; i++){
28093 _add : function(el) {
28096 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28099 if (el.applyTo){ // some kind of form field
28100 return this.addField(el);
28102 if (el.render){ // some kind of Toolbar.Item
28103 return this.addItem(el);
28105 if (typeof el == "string"){ // string
28106 if(el == "separator" || el == "-"){
28107 return this.addSeparator();
28110 return this.addSpacer();
28113 return this.addFill();
28115 return this.addText(el);
28118 if(el.tagName){ // element
28119 return this.addElement(el);
28121 if(typeof el == "object"){ // must be button config?
28122 return this.addButton(el);
28124 // and now what?!?!
28130 * Add an Xtype element
28131 * @param {Object} xtype Xtype Object
28132 * @return {Object} created Object
28134 addxtype : function(e){
28135 return this.add(e);
28139 * Returns the Element for this toolbar.
28140 * @return {Roo.Element}
28142 getEl : function(){
28148 * @return {Roo.Toolbar.Item} The separator item
28150 addSeparator : function(){
28151 return this.addItem(new Roo.Toolbar.Separator());
28155 * Adds a spacer element
28156 * @return {Roo.Toolbar.Spacer} The spacer item
28158 addSpacer : function(){
28159 return this.addItem(new Roo.Toolbar.Spacer());
28163 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28164 * @return {Roo.Toolbar.Fill} The fill item
28166 addFill : function(){
28167 return this.addItem(new Roo.Toolbar.Fill());
28171 * Adds any standard HTML element to the toolbar
28172 * @param {String/HTMLElement/Element} el The element or id of the element to add
28173 * @return {Roo.Toolbar.Item} The element's item
28175 addElement : function(el){
28176 return this.addItem(new Roo.Toolbar.Item(el));
28179 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28180 * @type Roo.util.MixedCollection
28185 * Adds any Toolbar.Item or subclass
28186 * @param {Roo.Toolbar.Item} item
28187 * @return {Roo.Toolbar.Item} The item
28189 addItem : function(item){
28190 var td = this.nextBlock();
28192 this.items.add(item);
28197 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28198 * @param {Object/Array} config A button config or array of configs
28199 * @return {Roo.Toolbar.Button/Array}
28201 addButton : function(config){
28202 if(config instanceof Array){
28204 for(var i = 0, len = config.length; i < len; i++) {
28205 buttons.push(this.addButton(config[i]));
28210 if(!(config instanceof Roo.Toolbar.Button)){
28212 new Roo.Toolbar.SplitButton(config) :
28213 new Roo.Toolbar.Button(config);
28215 var td = this.nextBlock();
28222 * Adds text to the toolbar
28223 * @param {String} text The text to add
28224 * @return {Roo.Toolbar.Item} The element's item
28226 addText : function(text){
28227 return this.addItem(new Roo.Toolbar.TextItem(text));
28231 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28232 * @param {Number} index The index where the item is to be inserted
28233 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28234 * @return {Roo.Toolbar.Button/Item}
28236 insertButton : function(index, item){
28237 if(item instanceof Array){
28239 for(var i = 0, len = item.length; i < len; i++) {
28240 buttons.push(this.insertButton(index + i, item[i]));
28244 if (!(item instanceof Roo.Toolbar.Button)){
28245 item = new Roo.Toolbar.Button(item);
28247 var td = document.createElement("td");
28248 this.tr.insertBefore(td, this.tr.childNodes[index]);
28250 this.items.insert(index, item);
28255 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28256 * @param {Object} config
28257 * @return {Roo.Toolbar.Item} The element's item
28259 addDom : function(config, returnEl){
28260 var td = this.nextBlock();
28261 Roo.DomHelper.overwrite(td, config);
28262 var ti = new Roo.Toolbar.Item(td.firstChild);
28264 this.items.add(ti);
28269 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28270 * @type Roo.util.MixedCollection
28275 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28276 * Note: the field should not have been rendered yet. For a field that has already been
28277 * rendered, use {@link #addElement}.
28278 * @param {Roo.form.Field} field
28279 * @return {Roo.ToolbarItem}
28283 addField : function(field) {
28284 if (!this.fields) {
28286 this.fields = new Roo.util.MixedCollection(false, function(o){
28287 return o.id || ("item" + (++autoId));
28292 var td = this.nextBlock();
28294 var ti = new Roo.Toolbar.Item(td.firstChild);
28296 this.items.add(ti);
28297 this.fields.add(field);
28308 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28309 this.el.child('div').hide();
28317 this.el.child('div').show();
28321 nextBlock : function(){
28322 var td = document.createElement("td");
28323 this.tr.appendChild(td);
28328 destroy : function(){
28329 if(this.items){ // rendered?
28330 Roo.destroy.apply(Roo, this.items.items);
28332 if(this.fields){ // rendered?
28333 Roo.destroy.apply(Roo, this.fields.items);
28335 Roo.Element.uncache(this.el, this.tr);
28340 * @class Roo.Toolbar.Item
28341 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28343 * Creates a new Item
28344 * @param {HTMLElement} el
28346 Roo.Toolbar.Item = function(el){
28347 this.el = Roo.getDom(el);
28348 this.id = Roo.id(this.el);
28349 this.hidden = false;
28352 Roo.Toolbar.Item.prototype = {
28355 * Get this item's HTML Element
28356 * @return {HTMLElement}
28358 getEl : function(){
28363 render : function(td){
28365 td.appendChild(this.el);
28369 * Removes and destroys this item.
28371 destroy : function(){
28372 this.td.parentNode.removeChild(this.td);
28379 this.hidden = false;
28380 this.td.style.display = "";
28387 this.hidden = true;
28388 this.td.style.display = "none";
28392 * Convenience function for boolean show/hide.
28393 * @param {Boolean} visible true to show/false to hide
28395 setVisible: function(visible){
28404 * Try to focus this item.
28406 focus : function(){
28407 Roo.fly(this.el).focus();
28411 * Disables this item.
28413 disable : function(){
28414 Roo.fly(this.td).addClass("x-item-disabled");
28415 this.disabled = true;
28416 this.el.disabled = true;
28420 * Enables this item.
28422 enable : function(){
28423 Roo.fly(this.td).removeClass("x-item-disabled");
28424 this.disabled = false;
28425 this.el.disabled = false;
28431 * @class Roo.Toolbar.Separator
28432 * @extends Roo.Toolbar.Item
28433 * A simple toolbar separator class
28435 * Creates a new Separator
28437 Roo.Toolbar.Separator = function(){
28438 var s = document.createElement("span");
28439 s.className = "ytb-sep";
28440 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28442 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28443 enable:Roo.emptyFn,
28444 disable:Roo.emptyFn,
28449 * @class Roo.Toolbar.Spacer
28450 * @extends Roo.Toolbar.Item
28451 * A simple element that adds extra horizontal space to a toolbar.
28453 * Creates a new Spacer
28455 Roo.Toolbar.Spacer = function(){
28456 var s = document.createElement("div");
28457 s.className = "ytb-spacer";
28458 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28460 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28461 enable:Roo.emptyFn,
28462 disable:Roo.emptyFn,
28467 * @class Roo.Toolbar.Fill
28468 * @extends Roo.Toolbar.Spacer
28469 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28471 * Creates a new Spacer
28473 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28475 render : function(td){
28476 td.style.width = '100%';
28477 Roo.Toolbar.Fill.superclass.render.call(this, td);
28482 * @class Roo.Toolbar.TextItem
28483 * @extends Roo.Toolbar.Item
28484 * A simple class that renders text directly into a toolbar.
28486 * Creates a new TextItem
28487 * @param {String} text
28489 Roo.Toolbar.TextItem = function(text){
28490 if (typeof(text) == 'object') {
28493 var s = document.createElement("span");
28494 s.className = "ytb-text";
28495 s.innerHTML = text;
28496 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28498 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28499 enable:Roo.emptyFn,
28500 disable:Roo.emptyFn,
28505 * @class Roo.Toolbar.Button
28506 * @extends Roo.Button
28507 * A button that renders into a toolbar.
28509 * Creates a new Button
28510 * @param {Object} config A standard {@link Roo.Button} config object
28512 Roo.Toolbar.Button = function(config){
28513 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28515 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28516 render : function(td){
28518 Roo.Toolbar.Button.superclass.render.call(this, td);
28522 * Removes and destroys this button
28524 destroy : function(){
28525 Roo.Toolbar.Button.superclass.destroy.call(this);
28526 this.td.parentNode.removeChild(this.td);
28530 * Shows this button
28533 this.hidden = false;
28534 this.td.style.display = "";
28538 * Hides this button
28541 this.hidden = true;
28542 this.td.style.display = "none";
28546 * Disables this item
28548 disable : function(){
28549 Roo.fly(this.td).addClass("x-item-disabled");
28550 this.disabled = true;
28554 * Enables this item
28556 enable : function(){
28557 Roo.fly(this.td).removeClass("x-item-disabled");
28558 this.disabled = false;
28561 // backwards compat
28562 Roo.ToolbarButton = Roo.Toolbar.Button;
28565 * @class Roo.Toolbar.SplitButton
28566 * @extends Roo.SplitButton
28567 * A menu button that renders into a toolbar.
28569 * Creates a new SplitButton
28570 * @param {Object} config A standard {@link Roo.SplitButton} config object
28572 Roo.Toolbar.SplitButton = function(config){
28573 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28575 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28576 render : function(td){
28578 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28582 * Removes and destroys this button
28584 destroy : function(){
28585 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28586 this.td.parentNode.removeChild(this.td);
28590 * Shows this button
28593 this.hidden = false;
28594 this.td.style.display = "";
28598 * Hides this button
28601 this.hidden = true;
28602 this.td.style.display = "none";
28606 // backwards compat
28607 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28609 * Ext JS Library 1.1.1
28610 * Copyright(c) 2006-2007, Ext JS, LLC.
28612 * Originally Released Under LGPL - original licence link has changed is not relivant.
28615 * <script type="text/javascript">
28619 * @class Roo.PagingToolbar
28620 * @extends Roo.Toolbar
28621 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28623 * Create a new PagingToolbar
28624 * @param {Object} config The config object
28626 Roo.PagingToolbar = function(el, ds, config)
28628 // old args format still supported... - xtype is prefered..
28629 if (typeof(el) == 'object' && el.xtype) {
28630 // created from xtype...
28632 ds = el.dataSource;
28633 el = config.container;
28636 if (config.items) {
28637 items = config.items;
28641 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28644 this.renderButtons(this.el);
28647 // supprot items array.
28649 Roo.each(items, function(e) {
28650 this.add(Roo.factory(e));
28655 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28657 * @cfg {Roo.data.Store} dataSource
28658 * The underlying data store providing the paged data
28661 * @cfg {String/HTMLElement/Element} container
28662 * container The id or element that will contain the toolbar
28665 * @cfg {Boolean} displayInfo
28666 * True to display the displayMsg (defaults to false)
28669 * @cfg {Number} pageSize
28670 * The number of records to display per page (defaults to 20)
28674 * @cfg {String} displayMsg
28675 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28677 displayMsg : 'Displaying {0} - {1} of {2}',
28679 * @cfg {String} emptyMsg
28680 * The message to display when no records are found (defaults to "No data to display")
28682 emptyMsg : 'No data to display',
28684 * Customizable piece of the default paging text (defaults to "Page")
28687 beforePageText : "Page",
28689 * Customizable piece of the default paging text (defaults to "of %0")
28692 afterPageText : "of {0}",
28694 * Customizable piece of the default paging text (defaults to "First Page")
28697 firstText : "First Page",
28699 * Customizable piece of the default paging text (defaults to "Previous Page")
28702 prevText : "Previous Page",
28704 * Customizable piece of the default paging text (defaults to "Next Page")
28707 nextText : "Next Page",
28709 * Customizable piece of the default paging text (defaults to "Last Page")
28712 lastText : "Last Page",
28714 * Customizable piece of the default paging text (defaults to "Refresh")
28717 refreshText : "Refresh",
28720 renderButtons : function(el){
28721 Roo.PagingToolbar.superclass.render.call(this, el);
28722 this.first = this.addButton({
28723 tooltip: this.firstText,
28724 cls: "x-btn-icon x-grid-page-first",
28726 handler: this.onClick.createDelegate(this, ["first"])
28728 this.prev = this.addButton({
28729 tooltip: this.prevText,
28730 cls: "x-btn-icon x-grid-page-prev",
28732 handler: this.onClick.createDelegate(this, ["prev"])
28734 //this.addSeparator();
28735 this.add(this.beforePageText);
28736 this.field = Roo.get(this.addDom({
28741 cls: "x-grid-page-number"
28743 this.field.on("keydown", this.onPagingKeydown, this);
28744 this.field.on("focus", function(){this.dom.select();});
28745 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28746 this.field.setHeight(18);
28747 //this.addSeparator();
28748 this.next = this.addButton({
28749 tooltip: this.nextText,
28750 cls: "x-btn-icon x-grid-page-next",
28752 handler: this.onClick.createDelegate(this, ["next"])
28754 this.last = this.addButton({
28755 tooltip: this.lastText,
28756 cls: "x-btn-icon x-grid-page-last",
28758 handler: this.onClick.createDelegate(this, ["last"])
28760 //this.addSeparator();
28761 this.loading = this.addButton({
28762 tooltip: this.refreshText,
28763 cls: "x-btn-icon x-grid-loading",
28764 handler: this.onClick.createDelegate(this, ["refresh"])
28767 if(this.displayInfo){
28768 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28773 updateInfo : function(){
28774 if(this.displayEl){
28775 var count = this.ds.getCount();
28776 var msg = count == 0 ?
28780 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28782 this.displayEl.update(msg);
28787 onLoad : function(ds, r, o){
28788 this.cursor = o.params ? o.params.start : 0;
28789 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28791 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28792 this.field.dom.value = ap;
28793 this.first.setDisabled(ap == 1);
28794 this.prev.setDisabled(ap == 1);
28795 this.next.setDisabled(ap == ps);
28796 this.last.setDisabled(ap == ps);
28797 this.loading.enable();
28802 getPageData : function(){
28803 var total = this.ds.getTotalCount();
28806 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28807 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28812 onLoadError : function(){
28813 this.loading.enable();
28817 onPagingKeydown : function(e){
28818 var k = e.getKey();
28819 var d = this.getPageData();
28821 var v = this.field.dom.value, pageNum;
28822 if(!v || isNaN(pageNum = parseInt(v, 10))){
28823 this.field.dom.value = d.activePage;
28826 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28827 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28830 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))
28832 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28833 this.field.dom.value = pageNum;
28834 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28837 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28839 var v = this.field.dom.value, pageNum;
28840 var increment = (e.shiftKey) ? 10 : 1;
28841 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28843 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28844 this.field.dom.value = d.activePage;
28847 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28849 this.field.dom.value = parseInt(v, 10) + increment;
28850 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28851 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28858 beforeLoad : function(){
28860 this.loading.disable();
28865 onClick : function(which){
28869 ds.load({params:{start: 0, limit: this.pageSize}});
28872 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28875 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28878 var total = ds.getTotalCount();
28879 var extra = total % this.pageSize;
28880 var lastStart = extra ? (total - extra) : total-this.pageSize;
28881 ds.load({params:{start: lastStart, limit: this.pageSize}});
28884 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28890 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28891 * @param {Roo.data.Store} store The data store to unbind
28893 unbind : function(ds){
28894 ds.un("beforeload", this.beforeLoad, this);
28895 ds.un("load", this.onLoad, this);
28896 ds.un("loadexception", this.onLoadError, this);
28897 ds.un("remove", this.updateInfo, this);
28898 ds.un("add", this.updateInfo, this);
28899 this.ds = undefined;
28903 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28904 * @param {Roo.data.Store} store The data store to bind
28906 bind : function(ds){
28907 ds.on("beforeload", this.beforeLoad, this);
28908 ds.on("load", this.onLoad, this);
28909 ds.on("loadexception", this.onLoadError, this);
28910 ds.on("remove", this.updateInfo, this);
28911 ds.on("add", this.updateInfo, this);
28916 * Ext JS Library 1.1.1
28917 * Copyright(c) 2006-2007, Ext JS, LLC.
28919 * Originally Released Under LGPL - original licence link has changed is not relivant.
28922 * <script type="text/javascript">
28926 * @class Roo.Resizable
28927 * @extends Roo.util.Observable
28928 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28929 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28930 * 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
28931 * the element will be wrapped for you automatically.</p>
28932 * <p>Here is the list of valid resize handles:</p>
28935 ------ -------------------
28944 'hd' horizontal drag
28947 * <p>Here's an example showing the creation of a typical Resizable:</p>
28949 var resizer = new Roo.Resizable("element-id", {
28957 resizer.on("resize", myHandler);
28959 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28960 * resizer.east.setDisplayed(false);</p>
28961 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28962 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28963 * resize operation's new size (defaults to [0, 0])
28964 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28965 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28966 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28967 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28968 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28969 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28970 * @cfg {Number} width The width of the element in pixels (defaults to null)
28971 * @cfg {Number} height The height of the element in pixels (defaults to null)
28972 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28973 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28974 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28975 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28976 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28977 * in favor of the handles config option (defaults to false)
28978 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28979 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28980 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28981 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28982 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28983 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28984 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28985 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28986 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28987 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28988 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28990 * Create a new resizable component
28991 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28992 * @param {Object} config configuration options
28994 Roo.Resizable = function(el, config)
28996 this.el = Roo.get(el);
28998 if(config && config.wrap){
28999 config.resizeChild = this.el;
29000 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29001 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29002 this.el.setStyle("overflow", "hidden");
29003 this.el.setPositioning(config.resizeChild.getPositioning());
29004 config.resizeChild.clearPositioning();
29005 if(!config.width || !config.height){
29006 var csize = config.resizeChild.getSize();
29007 this.el.setSize(csize.width, csize.height);
29009 if(config.pinned && !config.adjustments){
29010 config.adjustments = "auto";
29014 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29015 this.proxy.unselectable();
29016 this.proxy.enableDisplayMode('block');
29018 Roo.apply(this, config);
29021 this.disableTrackOver = true;
29022 this.el.addClass("x-resizable-pinned");
29024 // if the element isn't positioned, make it relative
29025 var position = this.el.getStyle("position");
29026 if(position != "absolute" && position != "fixed"){
29027 this.el.setStyle("position", "relative");
29029 if(!this.handles){ // no handles passed, must be legacy style
29030 this.handles = 's,e,se';
29031 if(this.multiDirectional){
29032 this.handles += ',n,w';
29035 if(this.handles == "all"){
29036 this.handles = "n s e w ne nw se sw";
29038 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29039 var ps = Roo.Resizable.positions;
29040 for(var i = 0, len = hs.length; i < len; i++){
29041 if(hs[i] && ps[hs[i]]){
29042 var pos = ps[hs[i]];
29043 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29047 this.corner = this.southeast;
29049 // updateBox = the box can move..
29050 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29051 this.updateBox = true;
29054 this.activeHandle = null;
29056 if(this.resizeChild){
29057 if(typeof this.resizeChild == "boolean"){
29058 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29060 this.resizeChild = Roo.get(this.resizeChild, true);
29064 if(this.adjustments == "auto"){
29065 var rc = this.resizeChild;
29066 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29067 if(rc && (hw || hn)){
29068 rc.position("relative");
29069 rc.setLeft(hw ? hw.el.getWidth() : 0);
29070 rc.setTop(hn ? hn.el.getHeight() : 0);
29072 this.adjustments = [
29073 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29074 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29078 if(this.draggable){
29079 this.dd = this.dynamic ?
29080 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29081 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29087 * @event beforeresize
29088 * Fired before resize is allowed. Set enabled to false to cancel resize.
29089 * @param {Roo.Resizable} this
29090 * @param {Roo.EventObject} e The mousedown event
29092 "beforeresize" : true,
29095 * Fired a resizing.
29096 * @param {Roo.Resizable} this
29097 * @param {Number} x The new x position
29098 * @param {Number} y The new y position
29099 * @param {Number} w The new w width
29100 * @param {Number} h The new h hight
29101 * @param {Roo.EventObject} e The mouseup event
29106 * Fired after a resize.
29107 * @param {Roo.Resizable} this
29108 * @param {Number} width The new width
29109 * @param {Number} height The new height
29110 * @param {Roo.EventObject} e The mouseup event
29115 if(this.width !== null && this.height !== null){
29116 this.resizeTo(this.width, this.height);
29118 this.updateChildSize();
29121 this.el.dom.style.zoom = 1;
29123 Roo.Resizable.superclass.constructor.call(this);
29126 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29127 resizeChild : false,
29128 adjustments : [0, 0],
29138 multiDirectional : false,
29139 disableTrackOver : false,
29140 easing : 'easeOutStrong',
29141 widthIncrement : 0,
29142 heightIncrement : 0,
29146 preserveRatio : false,
29147 transparent: false,
29153 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29155 constrainTo: undefined,
29157 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29159 resizeRegion: undefined,
29163 * Perform a manual resize
29164 * @param {Number} width
29165 * @param {Number} height
29167 resizeTo : function(width, height){
29168 this.el.setSize(width, height);
29169 this.updateChildSize();
29170 this.fireEvent("resize", this, width, height, null);
29174 startSizing : function(e, handle){
29175 this.fireEvent("beforeresize", this, e);
29176 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29179 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29180 this.overlay.unselectable();
29181 this.overlay.enableDisplayMode("block");
29182 this.overlay.on("mousemove", this.onMouseMove, this);
29183 this.overlay.on("mouseup", this.onMouseUp, this);
29185 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29187 this.resizing = true;
29188 this.startBox = this.el.getBox();
29189 this.startPoint = e.getXY();
29190 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29191 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29193 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29194 this.overlay.show();
29196 if(this.constrainTo) {
29197 var ct = Roo.get(this.constrainTo);
29198 this.resizeRegion = ct.getRegion().adjust(
29199 ct.getFrameWidth('t'),
29200 ct.getFrameWidth('l'),
29201 -ct.getFrameWidth('b'),
29202 -ct.getFrameWidth('r')
29206 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29208 this.proxy.setBox(this.startBox);
29210 this.proxy.setStyle('visibility', 'visible');
29216 onMouseDown : function(handle, e){
29219 this.activeHandle = handle;
29220 this.startSizing(e, handle);
29225 onMouseUp : function(e){
29226 var size = this.resizeElement();
29227 this.resizing = false;
29229 this.overlay.hide();
29231 this.fireEvent("resize", this, size.width, size.height, e);
29235 updateChildSize : function(){
29237 if(this.resizeChild){
29239 var child = this.resizeChild;
29240 var adj = this.adjustments;
29241 if(el.dom.offsetWidth){
29242 var b = el.getSize(true);
29243 child.setSize(b.width+adj[0], b.height+adj[1]);
29245 // Second call here for IE
29246 // The first call enables instant resizing and
29247 // the second call corrects scroll bars if they
29250 setTimeout(function(){
29251 if(el.dom.offsetWidth){
29252 var b = el.getSize(true);
29253 child.setSize(b.width+adj[0], b.height+adj[1]);
29261 snap : function(value, inc, min){
29262 if(!inc || !value) return value;
29263 var newValue = value;
29264 var m = value % inc;
29267 newValue = value + (inc-m);
29269 newValue = value - m;
29272 return Math.max(min, newValue);
29276 resizeElement : function(){
29277 var box = this.proxy.getBox();
29278 if(this.updateBox){
29279 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29281 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29283 this.updateChildSize();
29291 constrain : function(v, diff, m, mx){
29294 }else if(v - diff > mx){
29301 onMouseMove : function(e){
29304 try{// try catch so if something goes wrong the user doesn't get hung
29306 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29310 //var curXY = this.startPoint;
29311 var curSize = this.curSize || this.startBox;
29312 var x = this.startBox.x, y = this.startBox.y;
29313 var ox = x, oy = y;
29314 var w = curSize.width, h = curSize.height;
29315 var ow = w, oh = h;
29316 var mw = this.minWidth, mh = this.minHeight;
29317 var mxw = this.maxWidth, mxh = this.maxHeight;
29318 var wi = this.widthIncrement;
29319 var hi = this.heightIncrement;
29321 var eventXY = e.getXY();
29322 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29323 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29325 var pos = this.activeHandle.position;
29330 w = Math.min(Math.max(mw, w), mxw);
29335 h = Math.min(Math.max(mh, h), mxh);
29340 w = Math.min(Math.max(mw, w), mxw);
29341 h = Math.min(Math.max(mh, h), mxh);
29344 diffY = this.constrain(h, diffY, mh, mxh);
29351 var adiffX = Math.abs(diffX);
29352 var sub = (adiffX % wi); // how much
29353 if (sub > (wi/2)) { // far enough to snap
29354 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29356 // remove difference..
29357 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29361 x = Math.max(this.minX, x);
29364 diffX = this.constrain(w, diffX, mw, mxw);
29370 w = Math.min(Math.max(mw, w), mxw);
29371 diffY = this.constrain(h, diffY, mh, mxh);
29376 diffX = this.constrain(w, diffX, mw, mxw);
29377 diffY = this.constrain(h, diffY, mh, mxh);
29384 diffX = this.constrain(w, diffX, mw, mxw);
29386 h = Math.min(Math.max(mh, h), mxh);
29392 var sw = this.snap(w, wi, mw);
29393 var sh = this.snap(h, hi, mh);
29394 if(sw != w || sh != h){
29417 if(this.preserveRatio){
29422 h = Math.min(Math.max(mh, h), mxh);
29427 w = Math.min(Math.max(mw, w), mxw);
29432 w = Math.min(Math.max(mw, w), mxw);
29438 w = Math.min(Math.max(mw, w), mxw);
29444 h = Math.min(Math.max(mh, h), mxh);
29452 h = Math.min(Math.max(mh, h), mxh);
29462 h = Math.min(Math.max(mh, h), mxh);
29470 if (pos == 'hdrag') {
29473 this.proxy.setBounds(x, y, w, h);
29475 this.resizeElement();
29479 this.fireEvent("resizing", this, x, y, w, h, e);
29483 handleOver : function(){
29485 this.el.addClass("x-resizable-over");
29490 handleOut : function(){
29491 if(!this.resizing){
29492 this.el.removeClass("x-resizable-over");
29497 * Returns the element this component is bound to.
29498 * @return {Roo.Element}
29500 getEl : function(){
29505 * Returns the resizeChild element (or null).
29506 * @return {Roo.Element}
29508 getResizeChild : function(){
29509 return this.resizeChild;
29511 groupHandler : function()
29516 * Destroys this resizable. If the element was wrapped and
29517 * removeEl is not true then the element remains.
29518 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29520 destroy : function(removeEl){
29521 this.proxy.remove();
29523 this.overlay.removeAllListeners();
29524 this.overlay.remove();
29526 var ps = Roo.Resizable.positions;
29528 if(typeof ps[k] != "function" && this[ps[k]]){
29529 var h = this[ps[k]];
29530 h.el.removeAllListeners();
29535 this.el.update("");
29542 // hash to map config positions to true positions
29543 Roo.Resizable.positions = {
29544 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29549 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29551 // only initialize the template if resizable is used
29552 var tpl = Roo.DomHelper.createTemplate(
29553 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29556 Roo.Resizable.Handle.prototype.tpl = tpl;
29558 this.position = pos;
29560 // show north drag fro topdra
29561 var handlepos = pos == 'hdrag' ? 'north' : pos;
29563 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29564 if (pos == 'hdrag') {
29565 this.el.setStyle('cursor', 'pointer');
29567 this.el.unselectable();
29569 this.el.setOpacity(0);
29571 this.el.on("mousedown", this.onMouseDown, this);
29572 if(!disableTrackOver){
29573 this.el.on("mouseover", this.onMouseOver, this);
29574 this.el.on("mouseout", this.onMouseOut, this);
29579 Roo.Resizable.Handle.prototype = {
29580 afterResize : function(rz){
29585 onMouseDown : function(e){
29586 this.rz.onMouseDown(this, e);
29589 onMouseOver : function(e){
29590 this.rz.handleOver(this, e);
29593 onMouseOut : function(e){
29594 this.rz.handleOut(this, e);
29598 * Ext JS Library 1.1.1
29599 * Copyright(c) 2006-2007, Ext JS, LLC.
29601 * Originally Released Under LGPL - original licence link has changed is not relivant.
29604 * <script type="text/javascript">
29608 * @class Roo.Editor
29609 * @extends Roo.Component
29610 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29612 * Create a new Editor
29613 * @param {Roo.form.Field} field The Field object (or descendant)
29614 * @param {Object} config The config object
29616 Roo.Editor = function(field, config){
29617 Roo.Editor.superclass.constructor.call(this, config);
29618 this.field = field;
29621 * @event beforestartedit
29622 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29623 * false from the handler of this event.
29624 * @param {Editor} this
29625 * @param {Roo.Element} boundEl The underlying element bound to this editor
29626 * @param {Mixed} value The field value being set
29628 "beforestartedit" : true,
29631 * Fires when this editor is displayed
29632 * @param {Roo.Element} boundEl The underlying element bound to this editor
29633 * @param {Mixed} value The starting field value
29635 "startedit" : true,
29637 * @event beforecomplete
29638 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29639 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29640 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29641 * event will not fire since no edit actually occurred.
29642 * @param {Editor} this
29643 * @param {Mixed} value The current field value
29644 * @param {Mixed} startValue The original field value
29646 "beforecomplete" : true,
29649 * Fires after editing is complete and any changed value has been written to the underlying field.
29650 * @param {Editor} this
29651 * @param {Mixed} value The current field value
29652 * @param {Mixed} startValue The original field value
29656 * @event specialkey
29657 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29658 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29659 * @param {Roo.form.Field} this
29660 * @param {Roo.EventObject} e The event object
29662 "specialkey" : true
29666 Roo.extend(Roo.Editor, Roo.Component, {
29668 * @cfg {Boolean/String} autosize
29669 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29670 * or "height" to adopt the height only (defaults to false)
29673 * @cfg {Boolean} revertInvalid
29674 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29675 * validation fails (defaults to true)
29678 * @cfg {Boolean} ignoreNoChange
29679 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29680 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29681 * will never be ignored.
29684 * @cfg {Boolean} hideEl
29685 * False to keep the bound element visible while the editor is displayed (defaults to true)
29688 * @cfg {Mixed} value
29689 * The data value of the underlying field (defaults to "")
29693 * @cfg {String} alignment
29694 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29698 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29699 * for bottom-right shadow (defaults to "frame")
29703 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29707 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29709 completeOnEnter : false,
29711 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29713 cancelOnEsc : false,
29715 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29720 onRender : function(ct, position){
29721 this.el = new Roo.Layer({
29722 shadow: this.shadow,
29728 constrain: this.constrain
29730 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29731 if(this.field.msgTarget != 'title'){
29732 this.field.msgTarget = 'qtip';
29734 this.field.render(this.el);
29736 this.field.el.dom.setAttribute('autocomplete', 'off');
29738 this.field.on("specialkey", this.onSpecialKey, this);
29739 if(this.swallowKeys){
29740 this.field.el.swallowEvent(['keydown','keypress']);
29743 this.field.on("blur", this.onBlur, this);
29744 if(this.field.grow){
29745 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29749 onSpecialKey : function(field, e)
29751 //Roo.log('editor onSpecialKey');
29752 if(this.completeOnEnter && e.getKey() == e.ENTER){
29754 this.completeEdit();
29757 // do not fire special key otherwise it might hide close the editor...
29758 if(e.getKey() == e.ENTER){
29761 if(this.cancelOnEsc && e.getKey() == e.ESC){
29765 this.fireEvent('specialkey', field, e);
29770 * Starts the editing process and shows the editor.
29771 * @param {String/HTMLElement/Element} el The element to edit
29772 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29773 * to the innerHTML of el.
29775 startEdit : function(el, value){
29777 this.completeEdit();
29779 this.boundEl = Roo.get(el);
29780 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29781 if(!this.rendered){
29782 this.render(this.parentEl || document.body);
29784 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29787 this.startValue = v;
29788 this.field.setValue(v);
29790 var sz = this.boundEl.getSize();
29791 switch(this.autoSize){
29793 this.setSize(sz.width, "");
29796 this.setSize("", sz.height);
29799 this.setSize(sz.width, sz.height);
29802 this.el.alignTo(this.boundEl, this.alignment);
29803 this.editing = true;
29805 Roo.QuickTips.disable();
29811 * Sets the height and width of this editor.
29812 * @param {Number} width The new width
29813 * @param {Number} height The new height
29815 setSize : function(w, h){
29816 this.field.setSize(w, h);
29823 * Realigns the editor to the bound field based on the current alignment config value.
29825 realign : function(){
29826 this.el.alignTo(this.boundEl, this.alignment);
29830 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29831 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29833 completeEdit : function(remainVisible){
29837 var v = this.getValue();
29838 if(this.revertInvalid !== false && !this.field.isValid()){
29839 v = this.startValue;
29840 this.cancelEdit(true);
29842 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29843 this.editing = false;
29847 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29848 this.editing = false;
29849 if(this.updateEl && this.boundEl){
29850 this.boundEl.update(v);
29852 if(remainVisible !== true){
29855 this.fireEvent("complete", this, v, this.startValue);
29860 onShow : function(){
29862 if(this.hideEl !== false){
29863 this.boundEl.hide();
29866 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29867 this.fixIEFocus = true;
29868 this.deferredFocus.defer(50, this);
29870 this.field.focus();
29872 this.fireEvent("startedit", this.boundEl, this.startValue);
29875 deferredFocus : function(){
29877 this.field.focus();
29882 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29883 * reverted to the original starting value.
29884 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29885 * cancel (defaults to false)
29887 cancelEdit : function(remainVisible){
29889 this.setValue(this.startValue);
29890 if(remainVisible !== true){
29897 onBlur : function(){
29898 if(this.allowBlur !== true && this.editing){
29899 this.completeEdit();
29904 onHide : function(){
29906 this.completeEdit();
29910 if(this.field.collapse){
29911 this.field.collapse();
29914 if(this.hideEl !== false){
29915 this.boundEl.show();
29918 Roo.QuickTips.enable();
29923 * Sets the data value of the editor
29924 * @param {Mixed} value Any valid value supported by the underlying field
29926 setValue : function(v){
29927 this.field.setValue(v);
29931 * Gets the data value of the editor
29932 * @return {Mixed} The data value
29934 getValue : function(){
29935 return this.field.getValue();
29939 * Ext JS Library 1.1.1
29940 * Copyright(c) 2006-2007, Ext JS, LLC.
29942 * Originally Released Under LGPL - original licence link has changed is not relivant.
29945 * <script type="text/javascript">
29949 * @class Roo.BasicDialog
29950 * @extends Roo.util.Observable
29951 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29953 var dlg = new Roo.BasicDialog("my-dlg", {
29962 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29963 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29964 dlg.addButton('Cancel', dlg.hide, dlg);
29967 <b>A Dialog should always be a direct child of the body element.</b>
29968 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29969 * @cfg {String} title Default text to display in the title bar (defaults to null)
29970 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29971 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29972 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29973 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29974 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29975 * (defaults to null with no animation)
29976 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29977 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29978 * property for valid values (defaults to 'all')
29979 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29980 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29981 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29982 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29983 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29984 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29985 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29986 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29987 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29988 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29989 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29990 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29991 * draggable = true (defaults to false)
29992 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29993 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29994 * shadow (defaults to false)
29995 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29996 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29997 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
29998 * @cfg {Array} buttons Array of buttons
29999 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30001 * Create a new BasicDialog.
30002 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30003 * @param {Object} config Configuration options
30005 Roo.BasicDialog = function(el, config){
30006 this.el = Roo.get(el);
30007 var dh = Roo.DomHelper;
30008 if(!this.el && config && config.autoCreate){
30009 if(typeof config.autoCreate == "object"){
30010 if(!config.autoCreate.id){
30011 config.autoCreate.id = el;
30013 this.el = dh.append(document.body,
30014 config.autoCreate, true);
30016 this.el = dh.append(document.body,
30017 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30021 el.setDisplayed(true);
30022 el.hide = this.hideAction;
30024 el.addClass("x-dlg");
30026 Roo.apply(this, config);
30028 this.proxy = el.createProxy("x-dlg-proxy");
30029 this.proxy.hide = this.hideAction;
30030 this.proxy.setOpacity(.5);
30034 el.setWidth(config.width);
30037 el.setHeight(config.height);
30039 this.size = el.getSize();
30040 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30041 this.xy = [config.x,config.y];
30043 this.xy = el.getCenterXY(true);
30045 /** The header element @type Roo.Element */
30046 this.header = el.child("> .x-dlg-hd");
30047 /** The body element @type Roo.Element */
30048 this.body = el.child("> .x-dlg-bd");
30049 /** The footer element @type Roo.Element */
30050 this.footer = el.child("> .x-dlg-ft");
30053 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30056 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30059 this.header.unselectable();
30061 this.header.update(this.title);
30063 // this element allows the dialog to be focused for keyboard event
30064 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30065 this.focusEl.swallowEvent("click", true);
30067 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30069 // wrap the body and footer for special rendering
30070 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30072 this.bwrap.dom.appendChild(this.footer.dom);
30075 this.bg = this.el.createChild({
30076 tag: "div", cls:"x-dlg-bg",
30077 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30079 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30082 if(this.autoScroll !== false && !this.autoTabs){
30083 this.body.setStyle("overflow", "auto");
30086 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30088 if(this.closable !== false){
30089 this.el.addClass("x-dlg-closable");
30090 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30091 this.close.on("click", this.closeClick, this);
30092 this.close.addClassOnOver("x-dlg-close-over");
30094 if(this.collapsible !== false){
30095 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30096 this.collapseBtn.on("click", this.collapseClick, this);
30097 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30098 this.header.on("dblclick", this.collapseClick, this);
30100 if(this.resizable !== false){
30101 this.el.addClass("x-dlg-resizable");
30102 this.resizer = new Roo.Resizable(el, {
30103 minWidth: this.minWidth || 80,
30104 minHeight:this.minHeight || 80,
30105 handles: this.resizeHandles || "all",
30108 this.resizer.on("beforeresize", this.beforeResize, this);
30109 this.resizer.on("resize", this.onResize, this);
30111 if(this.draggable !== false){
30112 el.addClass("x-dlg-draggable");
30113 if (!this.proxyDrag) {
30114 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30117 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30119 dd.setHandleElId(this.header.id);
30120 dd.endDrag = this.endMove.createDelegate(this);
30121 dd.startDrag = this.startMove.createDelegate(this);
30122 dd.onDrag = this.onDrag.createDelegate(this);
30127 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30128 this.mask.enableDisplayMode("block");
30130 this.el.addClass("x-dlg-modal");
30133 this.shadow = new Roo.Shadow({
30134 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30135 offset : this.shadowOffset
30138 this.shadowOffset = 0;
30140 if(Roo.useShims && this.shim !== false){
30141 this.shim = this.el.createShim();
30142 this.shim.hide = this.hideAction;
30150 if (this.buttons) {
30151 var bts= this.buttons;
30153 Roo.each(bts, function(b) {
30162 * Fires when a key is pressed
30163 * @param {Roo.BasicDialog} this
30164 * @param {Roo.EventObject} e
30169 * Fires when this dialog is moved by the user.
30170 * @param {Roo.BasicDialog} this
30171 * @param {Number} x The new page X
30172 * @param {Number} y The new page Y
30177 * Fires when this dialog is resized by the user.
30178 * @param {Roo.BasicDialog} this
30179 * @param {Number} width The new width
30180 * @param {Number} height The new height
30184 * @event beforehide
30185 * Fires before this dialog is hidden.
30186 * @param {Roo.BasicDialog} this
30188 "beforehide" : true,
30191 * Fires when this dialog is hidden.
30192 * @param {Roo.BasicDialog} this
30196 * @event beforeshow
30197 * Fires before this dialog is shown.
30198 * @param {Roo.BasicDialog} this
30200 "beforeshow" : true,
30203 * Fires when this dialog is shown.
30204 * @param {Roo.BasicDialog} this
30208 el.on("keydown", this.onKeyDown, this);
30209 el.on("mousedown", this.toFront, this);
30210 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30212 Roo.DialogManager.register(this);
30213 Roo.BasicDialog.superclass.constructor.call(this);
30216 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30217 shadowOffset: Roo.isIE ? 6 : 5,
30220 minButtonWidth: 75,
30221 defaultButton: null,
30222 buttonAlign: "right",
30227 * Sets the dialog title text
30228 * @param {String} text The title text to display
30229 * @return {Roo.BasicDialog} this
30231 setTitle : function(text){
30232 this.header.update(text);
30237 closeClick : function(){
30242 collapseClick : function(){
30243 this[this.collapsed ? "expand" : "collapse"]();
30247 * Collapses the dialog to its minimized state (only the title bar is visible).
30248 * Equivalent to the user clicking the collapse dialog button.
30250 collapse : function(){
30251 if(!this.collapsed){
30252 this.collapsed = true;
30253 this.el.addClass("x-dlg-collapsed");
30254 this.restoreHeight = this.el.getHeight();
30255 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30260 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30261 * clicking the expand dialog button.
30263 expand : function(){
30264 if(this.collapsed){
30265 this.collapsed = false;
30266 this.el.removeClass("x-dlg-collapsed");
30267 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30272 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30273 * @return {Roo.TabPanel} The tabs component
30275 initTabs : function(){
30276 var tabs = this.getTabs();
30277 while(tabs.getTab(0)){
30280 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30282 tabs.addTab(Roo.id(dom), dom.title);
30290 beforeResize : function(){
30291 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30295 onResize : function(){
30296 this.refreshSize();
30297 this.syncBodyHeight();
30298 this.adjustAssets();
30300 this.fireEvent("resize", this, this.size.width, this.size.height);
30304 onKeyDown : function(e){
30305 if(this.isVisible()){
30306 this.fireEvent("keydown", this, e);
30311 * Resizes the dialog.
30312 * @param {Number} width
30313 * @param {Number} height
30314 * @return {Roo.BasicDialog} this
30316 resizeTo : function(width, height){
30317 this.el.setSize(width, height);
30318 this.size = {width: width, height: height};
30319 this.syncBodyHeight();
30320 if(this.fixedcenter){
30323 if(this.isVisible()){
30324 this.constrainXY();
30325 this.adjustAssets();
30327 this.fireEvent("resize", this, width, height);
30333 * Resizes the dialog to fit the specified content size.
30334 * @param {Number} width
30335 * @param {Number} height
30336 * @return {Roo.BasicDialog} this
30338 setContentSize : function(w, h){
30339 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30340 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30341 //if(!this.el.isBorderBox()){
30342 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30343 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30346 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30347 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30349 this.resizeTo(w, h);
30354 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30355 * executed in response to a particular key being pressed while the dialog is active.
30356 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30357 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30358 * @param {Function} fn The function to call
30359 * @param {Object} scope (optional) The scope of the function
30360 * @return {Roo.BasicDialog} this
30362 addKeyListener : function(key, fn, scope){
30363 var keyCode, shift, ctrl, alt;
30364 if(typeof key == "object" && !(key instanceof Array)){
30365 keyCode = key["key"];
30366 shift = key["shift"];
30367 ctrl = key["ctrl"];
30372 var handler = function(dlg, e){
30373 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30374 var k = e.getKey();
30375 if(keyCode instanceof Array){
30376 for(var i = 0, len = keyCode.length; i < len; i++){
30377 if(keyCode[i] == k){
30378 fn.call(scope || window, dlg, k, e);
30384 fn.call(scope || window, dlg, k, e);
30389 this.on("keydown", handler);
30394 * Returns the TabPanel component (creates it if it doesn't exist).
30395 * Note: If you wish to simply check for the existence of tabs without creating them,
30396 * check for a null 'tabs' property.
30397 * @return {Roo.TabPanel} The tabs component
30399 getTabs : function(){
30401 this.el.addClass("x-dlg-auto-tabs");
30402 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30403 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30409 * Adds a button to the footer section of the dialog.
30410 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30411 * object or a valid Roo.DomHelper element config
30412 * @param {Function} handler The function called when the button is clicked
30413 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30414 * @return {Roo.Button} The new button
30416 addButton : function(config, handler, scope){
30417 var dh = Roo.DomHelper;
30419 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30421 if(!this.btnContainer){
30422 var tb = this.footer.createChild({
30424 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30425 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30427 this.btnContainer = tb.firstChild.firstChild.firstChild;
30432 minWidth: this.minButtonWidth,
30435 if(typeof config == "string"){
30436 bconfig.text = config;
30439 bconfig.dhconfig = config;
30441 Roo.apply(bconfig, config);
30445 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30446 bconfig.position = Math.max(0, bconfig.position);
30447 fc = this.btnContainer.childNodes[bconfig.position];
30450 var btn = new Roo.Button(
30452 this.btnContainer.insertBefore(document.createElement("td"),fc)
30453 : this.btnContainer.appendChild(document.createElement("td")),
30454 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30457 this.syncBodyHeight();
30460 * Array of all the buttons that have been added to this dialog via addButton
30465 this.buttons.push(btn);
30470 * Sets the default button to be focused when the dialog is displayed.
30471 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30472 * @return {Roo.BasicDialog} this
30474 setDefaultButton : function(btn){
30475 this.defaultButton = btn;
30480 getHeaderFooterHeight : function(safe){
30483 height += this.header.getHeight();
30486 var fm = this.footer.getMargins();
30487 height += (this.footer.getHeight()+fm.top+fm.bottom);
30489 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30490 height += this.centerBg.getPadding("tb");
30495 syncBodyHeight : function()
30497 var bd = this.body, // the text
30498 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30500 var height = this.size.height - this.getHeaderFooterHeight(false);
30501 bd.setHeight(height-bd.getMargins("tb"));
30502 var hh = this.header.getHeight();
30503 var h = this.size.height-hh;
30506 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30507 bw.setHeight(h-cb.getPadding("tb"));
30509 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30510 bd.setWidth(bw.getWidth(true));
30512 this.tabs.syncHeight();
30514 this.tabs.el.repaint();
30520 * Restores the previous state of the dialog if Roo.state is configured.
30521 * @return {Roo.BasicDialog} this
30523 restoreState : function(){
30524 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30525 if(box && box.width){
30526 this.xy = [box.x, box.y];
30527 this.resizeTo(box.width, box.height);
30533 beforeShow : function(){
30535 if(this.fixedcenter){
30536 this.xy = this.el.getCenterXY(true);
30539 Roo.get(document.body).addClass("x-body-masked");
30540 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30543 this.constrainXY();
30547 animShow : function(){
30548 var b = Roo.get(this.animateTarget).getBox();
30549 this.proxy.setSize(b.width, b.height);
30550 this.proxy.setLocation(b.x, b.y);
30552 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30553 true, .35, this.showEl.createDelegate(this));
30557 * Shows the dialog.
30558 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30559 * @return {Roo.BasicDialog} this
30561 show : function(animateTarget){
30562 if (this.fireEvent("beforeshow", this) === false){
30565 if(this.syncHeightBeforeShow){
30566 this.syncBodyHeight();
30567 }else if(this.firstShow){
30568 this.firstShow = false;
30569 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30571 this.animateTarget = animateTarget || this.animateTarget;
30572 if(!this.el.isVisible()){
30574 if(this.animateTarget && Roo.get(this.animateTarget)){
30584 showEl : function(){
30586 this.el.setXY(this.xy);
30588 this.adjustAssets(true);
30591 // IE peekaboo bug - fix found by Dave Fenwick
30595 this.fireEvent("show", this);
30599 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30600 * dialog itself will receive focus.
30602 focus : function(){
30603 if(this.defaultButton){
30604 this.defaultButton.focus();
30606 this.focusEl.focus();
30611 constrainXY : function(){
30612 if(this.constraintoviewport !== false){
30613 if(!this.viewSize){
30614 if(this.container){
30615 var s = this.container.getSize();
30616 this.viewSize = [s.width, s.height];
30618 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30621 var s = Roo.get(this.container||document).getScroll();
30623 var x = this.xy[0], y = this.xy[1];
30624 var w = this.size.width, h = this.size.height;
30625 var vw = this.viewSize[0], vh = this.viewSize[1];
30626 // only move it if it needs it
30628 // first validate right/bottom
30629 if(x + w > vw+s.left){
30633 if(y + h > vh+s.top){
30637 // then make sure top/left isn't negative
30649 if(this.isVisible()){
30650 this.el.setLocation(x, y);
30651 this.adjustAssets();
30658 onDrag : function(){
30659 if(!this.proxyDrag){
30660 this.xy = this.el.getXY();
30661 this.adjustAssets();
30666 adjustAssets : function(doShow){
30667 var x = this.xy[0], y = this.xy[1];
30668 var w = this.size.width, h = this.size.height;
30669 if(doShow === true){
30671 this.shadow.show(this.el);
30677 if(this.shadow && this.shadow.isVisible()){
30678 this.shadow.show(this.el);
30680 if(this.shim && this.shim.isVisible()){
30681 this.shim.setBounds(x, y, w, h);
30686 adjustViewport : function(w, h){
30688 w = Roo.lib.Dom.getViewWidth();
30689 h = Roo.lib.Dom.getViewHeight();
30692 this.viewSize = [w, h];
30693 if(this.modal && this.mask.isVisible()){
30694 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30695 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30697 if(this.isVisible()){
30698 this.constrainXY();
30703 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30704 * shadow, proxy, mask, etc.) Also removes all event listeners.
30705 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30707 destroy : function(removeEl){
30708 if(this.isVisible()){
30709 this.animateTarget = null;
30712 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30714 this.tabs.destroy(removeEl);
30727 for(var i = 0, len = this.buttons.length; i < len; i++){
30728 this.buttons[i].destroy();
30731 this.el.removeAllListeners();
30732 if(removeEl === true){
30733 this.el.update("");
30736 Roo.DialogManager.unregister(this);
30740 startMove : function(){
30741 if(this.proxyDrag){
30744 if(this.constraintoviewport !== false){
30745 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30750 endMove : function(){
30751 if(!this.proxyDrag){
30752 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30754 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30757 this.refreshSize();
30758 this.adjustAssets();
30760 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30764 * Brings this dialog to the front of any other visible dialogs
30765 * @return {Roo.BasicDialog} this
30767 toFront : function(){
30768 Roo.DialogManager.bringToFront(this);
30773 * Sends this dialog to the back (under) of any other visible dialogs
30774 * @return {Roo.BasicDialog} this
30776 toBack : function(){
30777 Roo.DialogManager.sendToBack(this);
30782 * Centers this dialog in the viewport
30783 * @return {Roo.BasicDialog} this
30785 center : function(){
30786 var xy = this.el.getCenterXY(true);
30787 this.moveTo(xy[0], xy[1]);
30792 * Moves the dialog's top-left corner to the specified point
30793 * @param {Number} x
30794 * @param {Number} y
30795 * @return {Roo.BasicDialog} this
30797 moveTo : function(x, y){
30799 if(this.isVisible()){
30800 this.el.setXY(this.xy);
30801 this.adjustAssets();
30807 * Aligns the dialog to the specified element
30808 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30809 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30810 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30811 * @return {Roo.BasicDialog} this
30813 alignTo : function(element, position, offsets){
30814 this.xy = this.el.getAlignToXY(element, position, offsets);
30815 if(this.isVisible()){
30816 this.el.setXY(this.xy);
30817 this.adjustAssets();
30823 * Anchors an element to another element and realigns it when the window is resized.
30824 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30825 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30826 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30827 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30828 * is a number, it is used as the buffer delay (defaults to 50ms).
30829 * @return {Roo.BasicDialog} this
30831 anchorTo : function(el, alignment, offsets, monitorScroll){
30832 var action = function(){
30833 this.alignTo(el, alignment, offsets);
30835 Roo.EventManager.onWindowResize(action, this);
30836 var tm = typeof monitorScroll;
30837 if(tm != 'undefined'){
30838 Roo.EventManager.on(window, 'scroll', action, this,
30839 {buffer: tm == 'number' ? monitorScroll : 50});
30846 * Returns true if the dialog is visible
30847 * @return {Boolean}
30849 isVisible : function(){
30850 return this.el.isVisible();
30854 animHide : function(callback){
30855 var b = Roo.get(this.animateTarget).getBox();
30857 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30859 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30860 this.hideEl.createDelegate(this, [callback]));
30864 * Hides the dialog.
30865 * @param {Function} callback (optional) Function to call when the dialog is hidden
30866 * @return {Roo.BasicDialog} this
30868 hide : function(callback){
30869 if (this.fireEvent("beforehide", this) === false){
30873 this.shadow.hide();
30878 // sometimes animateTarget seems to get set.. causing problems...
30879 // this just double checks..
30880 if(this.animateTarget && Roo.get(this.animateTarget)) {
30881 this.animHide(callback);
30884 this.hideEl(callback);
30890 hideEl : function(callback){
30894 Roo.get(document.body).removeClass("x-body-masked");
30896 this.fireEvent("hide", this);
30897 if(typeof callback == "function"){
30903 hideAction : function(){
30904 this.setLeft("-10000px");
30905 this.setTop("-10000px");
30906 this.setStyle("visibility", "hidden");
30910 refreshSize : function(){
30911 this.size = this.el.getSize();
30912 this.xy = this.el.getXY();
30913 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30917 // z-index is managed by the DialogManager and may be overwritten at any time
30918 setZIndex : function(index){
30920 this.mask.setStyle("z-index", index);
30923 this.shim.setStyle("z-index", ++index);
30926 this.shadow.setZIndex(++index);
30928 this.el.setStyle("z-index", ++index);
30930 this.proxy.setStyle("z-index", ++index);
30933 this.resizer.proxy.setStyle("z-index", ++index);
30936 this.lastZIndex = index;
30940 * Returns the element for this dialog
30941 * @return {Roo.Element} The underlying dialog Element
30943 getEl : function(){
30949 * @class Roo.DialogManager
30950 * Provides global access to BasicDialogs that have been created and
30951 * support for z-indexing (layering) multiple open dialogs.
30953 Roo.DialogManager = function(){
30955 var accessList = [];
30959 var sortDialogs = function(d1, d2){
30960 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30964 var orderDialogs = function(){
30965 accessList.sort(sortDialogs);
30966 var seed = Roo.DialogManager.zseed;
30967 for(var i = 0, len = accessList.length; i < len; i++){
30968 var dlg = accessList[i];
30970 dlg.setZIndex(seed + (i*10));
30977 * The starting z-index for BasicDialogs (defaults to 9000)
30978 * @type Number The z-index value
30983 register : function(dlg){
30984 list[dlg.id] = dlg;
30985 accessList.push(dlg);
30989 unregister : function(dlg){
30990 delete list[dlg.id];
30993 if(!accessList.indexOf){
30994 for( i = 0, len = accessList.length; i < len; i++){
30995 if(accessList[i] == dlg){
30996 accessList.splice(i, 1);
31001 i = accessList.indexOf(dlg);
31003 accessList.splice(i, 1);
31009 * Gets a registered dialog by id
31010 * @param {String/Object} id The id of the dialog or a dialog
31011 * @return {Roo.BasicDialog} this
31013 get : function(id){
31014 return typeof id == "object" ? id : list[id];
31018 * Brings the specified dialog to the front
31019 * @param {String/Object} dlg The id of the dialog or a dialog
31020 * @return {Roo.BasicDialog} this
31022 bringToFront : function(dlg){
31023 dlg = this.get(dlg);
31026 dlg._lastAccess = new Date().getTime();
31033 * Sends the specified dialog to the back
31034 * @param {String/Object} dlg The id of the dialog or a dialog
31035 * @return {Roo.BasicDialog} this
31037 sendToBack : function(dlg){
31038 dlg = this.get(dlg);
31039 dlg._lastAccess = -(new Date().getTime());
31045 * Hides all dialogs
31047 hideAll : function(){
31048 for(var id in list){
31049 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31058 * @class Roo.LayoutDialog
31059 * @extends Roo.BasicDialog
31060 * Dialog which provides adjustments for working with a layout in a Dialog.
31061 * Add your necessary layout config options to the dialog's config.<br>
31062 * Example usage (including a nested layout):
31065 dialog = new Roo.LayoutDialog("download-dlg", {
31074 // layout config merges with the dialog config
31076 tabPosition: "top",
31077 alwaysShowTabs: true
31080 dialog.addKeyListener(27, dialog.hide, dialog);
31081 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31082 dialog.addButton("Build It!", this.getDownload, this);
31084 // we can even add nested layouts
31085 var innerLayout = new Roo.BorderLayout("dl-inner", {
31095 innerLayout.beginUpdate();
31096 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31097 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31098 innerLayout.endUpdate(true);
31100 var layout = dialog.getLayout();
31101 layout.beginUpdate();
31102 layout.add("center", new Roo.ContentPanel("standard-panel",
31103 {title: "Download the Source", fitToFrame:true}));
31104 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31105 {title: "Build your own roo.js"}));
31106 layout.getRegion("center").showPanel(sp);
31107 layout.endUpdate();
31111 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31112 * @param {Object} config configuration options
31114 Roo.LayoutDialog = function(el, cfg){
31117 if (typeof(cfg) == 'undefined') {
31118 config = Roo.apply({}, el);
31119 // not sure why we use documentElement here.. - it should always be body.
31120 // IE7 borks horribly if we use documentElement.
31121 // webkit also does not like documentElement - it creates a body element...
31122 el = Roo.get( document.body || document.documentElement ).createChild();
31123 //config.autoCreate = true;
31127 config.autoTabs = false;
31128 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31129 this.body.setStyle({overflow:"hidden", position:"relative"});
31130 this.layout = new Roo.BorderLayout(this.body.dom, config);
31131 this.layout.monitorWindowResize = false;
31132 this.el.addClass("x-dlg-auto-layout");
31133 // fix case when center region overwrites center function
31134 this.center = Roo.BasicDialog.prototype.center;
31135 this.on("show", this.layout.layout, this.layout, true);
31136 if (config.items) {
31137 var xitems = config.items;
31138 delete config.items;
31139 Roo.each(xitems, this.addxtype, this);
31144 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31146 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31149 endUpdate : function(){
31150 this.layout.endUpdate();
31154 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31157 beginUpdate : function(){
31158 this.layout.beginUpdate();
31162 * Get the BorderLayout for this dialog
31163 * @return {Roo.BorderLayout}
31165 getLayout : function(){
31166 return this.layout;
31169 showEl : function(){
31170 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31172 this.layout.layout();
31177 // Use the syncHeightBeforeShow config option to control this automatically
31178 syncBodyHeight : function(){
31179 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31180 if(this.layout){this.layout.layout();}
31184 * Add an xtype element (actually adds to the layout.)
31185 * @return {Object} xdata xtype object data.
31188 addxtype : function(c) {
31189 return this.layout.addxtype(c);
31193 * Ext JS Library 1.1.1
31194 * Copyright(c) 2006-2007, Ext JS, LLC.
31196 * Originally Released Under LGPL - original licence link has changed is not relivant.
31199 * <script type="text/javascript">
31203 * @class Roo.MessageBox
31204 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31208 Roo.Msg.alert('Status', 'Changes saved successfully.');
31210 // Prompt for user data:
31211 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31213 // process text value...
31217 // Show a dialog using config options:
31219 title:'Save Changes?',
31220 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31221 buttons: Roo.Msg.YESNOCANCEL,
31228 Roo.MessageBox = function(){
31229 var dlg, opt, mask, waitTimer;
31230 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31231 var buttons, activeTextEl, bwidth;
31234 var handleButton = function(button){
31236 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31240 var handleHide = function(){
31241 if(opt && opt.cls){
31242 dlg.el.removeClass(opt.cls);
31245 Roo.TaskMgr.stop(waitTimer);
31251 var updateButtons = function(b){
31254 buttons["ok"].hide();
31255 buttons["cancel"].hide();
31256 buttons["yes"].hide();
31257 buttons["no"].hide();
31258 dlg.footer.dom.style.display = 'none';
31261 dlg.footer.dom.style.display = '';
31262 for(var k in buttons){
31263 if(typeof buttons[k] != "function"){
31266 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31267 width += buttons[k].el.getWidth()+15;
31277 var handleEsc = function(d, k, e){
31278 if(opt && opt.closable !== false){
31288 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31289 * @return {Roo.BasicDialog} The BasicDialog element
31291 getDialog : function(){
31293 dlg = new Roo.BasicDialog("x-msg-box", {
31298 constraintoviewport:false,
31300 collapsible : false,
31303 width:400, height:100,
31304 buttonAlign:"center",
31305 closeClick : function(){
31306 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31307 handleButton("no");
31309 handleButton("cancel");
31313 dlg.on("hide", handleHide);
31315 dlg.addKeyListener(27, handleEsc);
31317 var bt = this.buttonText;
31318 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31319 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31320 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31321 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31322 bodyEl = dlg.body.createChild({
31324 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>'
31326 msgEl = bodyEl.dom.firstChild;
31327 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31328 textboxEl.enableDisplayMode();
31329 textboxEl.addKeyListener([10,13], function(){
31330 if(dlg.isVisible() && opt && opt.buttons){
31331 if(opt.buttons.ok){
31332 handleButton("ok");
31333 }else if(opt.buttons.yes){
31334 handleButton("yes");
31338 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31339 textareaEl.enableDisplayMode();
31340 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31341 progressEl.enableDisplayMode();
31342 var pf = progressEl.dom.firstChild;
31344 pp = Roo.get(pf.firstChild);
31345 pp.setHeight(pf.offsetHeight);
31353 * Updates the message box body text
31354 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31355 * the XHTML-compliant non-breaking space character '&#160;')
31356 * @return {Roo.MessageBox} This message box
31358 updateText : function(text){
31359 if(!dlg.isVisible() && !opt.width){
31360 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31362 msgEl.innerHTML = text || ' ';
31364 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31365 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31367 Math.min(opt.width || cw , this.maxWidth),
31368 Math.max(opt.minWidth || this.minWidth, bwidth)
31371 activeTextEl.setWidth(w);
31373 if(dlg.isVisible()){
31374 dlg.fixedcenter = false;
31376 // to big, make it scroll. = But as usual stupid IE does not support
31379 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31380 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31381 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31383 bodyEl.dom.style.height = '';
31384 bodyEl.dom.style.overflowY = '';
31387 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31389 bodyEl.dom.style.overflowX = '';
31392 dlg.setContentSize(w, bodyEl.getHeight());
31393 if(dlg.isVisible()){
31394 dlg.fixedcenter = true;
31400 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31401 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31402 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31403 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31404 * @return {Roo.MessageBox} This message box
31406 updateProgress : function(value, text){
31408 this.updateText(text);
31410 if (pp) { // weird bug on my firefox - for some reason this is not defined
31411 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31417 * Returns true if the message box is currently displayed
31418 * @return {Boolean} True if the message box is visible, else false
31420 isVisible : function(){
31421 return dlg && dlg.isVisible();
31425 * Hides the message box if it is displayed
31428 if(this.isVisible()){
31434 * Displays a new message box, or reinitializes an existing message box, based on the config options
31435 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31436 * The following config object properties are supported:
31438 Property Type Description
31439 ---------- --------------- ------------------------------------------------------------------------------------
31440 animEl String/Element An id or Element from which the message box should animate as it opens and
31441 closes (defaults to undefined)
31442 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31443 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31444 closable Boolean False to hide the top-right close button (defaults to true). Note that
31445 progress and wait dialogs will ignore this property and always hide the
31446 close button as they can only be closed programmatically.
31447 cls String A custom CSS class to apply to the message box element
31448 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31449 displayed (defaults to 75)
31450 fn Function A callback function to execute after closing the dialog. The arguments to the
31451 function will be btn (the name of the button that was clicked, if applicable,
31452 e.g. "ok"), and text (the value of the active text field, if applicable).
31453 Progress and wait dialogs will ignore this option since they do not respond to
31454 user actions and can only be closed programmatically, so any required function
31455 should be called by the same code after it closes the dialog.
31456 icon String A CSS class that provides a background image to be used as an icon for
31457 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31458 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31459 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31460 modal Boolean False to allow user interaction with the page while the message box is
31461 displayed (defaults to true)
31462 msg String A string that will replace the existing message box body text (defaults
31463 to the XHTML-compliant non-breaking space character ' ')
31464 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31465 progress Boolean True to display a progress bar (defaults to false)
31466 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31467 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31468 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31469 title String The title text
31470 value String The string value to set into the active textbox element if displayed
31471 wait Boolean True to display a progress bar (defaults to false)
31472 width Number The width of the dialog in pixels
31479 msg: 'Please enter your address:',
31481 buttons: Roo.MessageBox.OKCANCEL,
31484 animEl: 'addAddressBtn'
31487 * @param {Object} config Configuration options
31488 * @return {Roo.MessageBox} This message box
31490 show : function(options)
31493 // this causes nightmares if you show one dialog after another
31494 // especially on callbacks..
31496 if(this.isVisible()){
31499 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31500 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31501 Roo.log("New Dialog Message:" + options.msg )
31502 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31503 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31506 var d = this.getDialog();
31508 d.setTitle(opt.title || " ");
31509 d.close.setDisplayed(opt.closable !== false);
31510 activeTextEl = textboxEl;
31511 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31516 textareaEl.setHeight(typeof opt.multiline == "number" ?
31517 opt.multiline : this.defaultTextHeight);
31518 activeTextEl = textareaEl;
31527 progressEl.setDisplayed(opt.progress === true);
31528 this.updateProgress(0);
31529 activeTextEl.dom.value = opt.value || "";
31531 dlg.setDefaultButton(activeTextEl);
31533 var bs = opt.buttons;
31536 db = buttons["ok"];
31537 }else if(bs && bs.yes){
31538 db = buttons["yes"];
31540 dlg.setDefaultButton(db);
31542 bwidth = updateButtons(opt.buttons);
31543 this.updateText(opt.msg);
31545 d.el.addClass(opt.cls);
31547 d.proxyDrag = opt.proxyDrag === true;
31548 d.modal = opt.modal !== false;
31549 d.mask = opt.modal !== false ? mask : false;
31550 if(!d.isVisible()){
31551 // force it to the end of the z-index stack so it gets a cursor in FF
31552 document.body.appendChild(dlg.el.dom);
31553 d.animateTarget = null;
31554 d.show(options.animEl);
31560 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31561 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31562 * and closing the message box when the process is complete.
31563 * @param {String} title The title bar text
31564 * @param {String} msg The message box body text
31565 * @return {Roo.MessageBox} This message box
31567 progress : function(title, msg){
31574 minWidth: this.minProgressWidth,
31581 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31582 * If a callback function is passed it will be called after the user clicks the button, and the
31583 * id of the button that was clicked will be passed as the only parameter to the callback
31584 * (could also be the top-right close button).
31585 * @param {String} title The title bar text
31586 * @param {String} msg The message box body text
31587 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31588 * @param {Object} scope (optional) The scope of the callback function
31589 * @return {Roo.MessageBox} This message box
31591 alert : function(title, msg, fn, scope){
31604 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31605 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31606 * You are responsible for closing the message box when the process is complete.
31607 * @param {String} msg The message box body text
31608 * @param {String} title (optional) The title bar text
31609 * @return {Roo.MessageBox} This message box
31611 wait : function(msg, title){
31622 waitTimer = Roo.TaskMgr.start({
31624 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31632 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31633 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31634 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
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 * @return {Roo.MessageBox} This message box
31641 confirm : function(title, msg, fn, scope){
31645 buttons: this.YESNO,
31654 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31655 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31656 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31657 * (could also be the top-right close button) and the text that was entered will be passed as the two
31658 * parameters to the callback.
31659 * @param {String} title The title bar text
31660 * @param {String} msg The message box body text
31661 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31662 * @param {Object} scope (optional) The scope of the callback function
31663 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31664 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31665 * @return {Roo.MessageBox} This message box
31667 prompt : function(title, msg, fn, scope, multiline){
31671 buttons: this.OKCANCEL,
31676 multiline: multiline,
31683 * Button config that displays a single OK button
31688 * Button config that displays Yes and No buttons
31691 YESNO : {yes:true, no:true},
31693 * Button config that displays OK and Cancel buttons
31696 OKCANCEL : {ok:true, cancel:true},
31698 * Button config that displays Yes, No and Cancel buttons
31701 YESNOCANCEL : {yes:true, no:true, cancel:true},
31704 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31707 defaultTextHeight : 75,
31709 * The maximum width in pixels of the message box (defaults to 600)
31714 * The minimum width in pixels of the message box (defaults to 100)
31719 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31720 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31723 minProgressWidth : 250,
31725 * An object containing the default button text strings that can be overriden for localized language support.
31726 * Supported properties are: ok, cancel, yes and no.
31727 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31740 * Shorthand for {@link Roo.MessageBox}
31742 Roo.Msg = Roo.MessageBox;/*
31744 * Ext JS Library 1.1.1
31745 * Copyright(c) 2006-2007, Ext JS, LLC.
31747 * Originally Released Under LGPL - original licence link has changed is not relivant.
31750 * <script type="text/javascript">
31753 * @class Roo.QuickTips
31754 * Provides attractive and customizable tooltips for any element.
31757 Roo.QuickTips = function(){
31758 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31759 var ce, bd, xy, dd;
31760 var visible = false, disabled = true, inited = false;
31761 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31763 var onOver = function(e){
31767 var t = e.getTarget();
31768 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31771 if(ce && t == ce.el){
31772 clearTimeout(hideProc);
31775 if(t && tagEls[t.id]){
31776 tagEls[t.id].el = t;
31777 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31780 var ttp, et = Roo.fly(t);
31781 var ns = cfg.namespace;
31782 if(tm.interceptTitles && t.title){
31785 t.removeAttribute("title");
31786 e.preventDefault();
31788 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31791 showProc = show.defer(tm.showDelay, tm, [{
31794 width: et.getAttributeNS(ns, cfg.width),
31795 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31796 title: et.getAttributeNS(ns, cfg.title),
31797 cls: et.getAttributeNS(ns, cfg.cls)
31802 var onOut = function(e){
31803 clearTimeout(showProc);
31804 var t = e.getTarget();
31805 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31806 hideProc = setTimeout(hide, tm.hideDelay);
31810 var onMove = function(e){
31816 if(tm.trackMouse && ce){
31821 var onDown = function(e){
31822 clearTimeout(showProc);
31823 clearTimeout(hideProc);
31825 if(tm.hideOnClick){
31828 tm.enable.defer(100, tm);
31833 var getPad = function(){
31834 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31837 var show = function(o){
31841 clearTimeout(dismissProc);
31843 if(removeCls){ // in case manually hidden
31844 el.removeClass(removeCls);
31848 el.addClass(ce.cls);
31849 removeCls = ce.cls;
31852 tipTitle.update(ce.title);
31855 tipTitle.update('');
31858 el.dom.style.width = tm.maxWidth+'px';
31859 //tipBody.dom.style.width = '';
31860 tipBodyText.update(o.text);
31861 var p = getPad(), w = ce.width;
31863 var td = tipBodyText.dom;
31864 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31865 if(aw > tm.maxWidth){
31867 }else if(aw < tm.minWidth){
31873 //tipBody.setWidth(w);
31874 el.setWidth(parseInt(w, 10) + p);
31875 if(ce.autoHide === false){
31876 close.setDisplayed(true);
31881 close.setDisplayed(false);
31887 el.avoidY = xy[1]-18;
31892 el.setStyle("visibility", "visible");
31893 el.fadeIn({callback: afterShow});
31899 var afterShow = function(){
31903 if(tm.autoDismiss && ce.autoHide !== false){
31904 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31909 var hide = function(noanim){
31910 clearTimeout(dismissProc);
31911 clearTimeout(hideProc);
31913 if(el.isVisible()){
31915 if(noanim !== true && tm.animate){
31916 el.fadeOut({callback: afterHide});
31923 var afterHide = function(){
31926 el.removeClass(removeCls);
31933 * @cfg {Number} minWidth
31934 * The minimum width of the quick tip (defaults to 40)
31938 * @cfg {Number} maxWidth
31939 * The maximum width of the quick tip (defaults to 300)
31943 * @cfg {Boolean} interceptTitles
31944 * True to automatically use the element's DOM title value if available (defaults to false)
31946 interceptTitles : false,
31948 * @cfg {Boolean} trackMouse
31949 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31951 trackMouse : false,
31953 * @cfg {Boolean} hideOnClick
31954 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31956 hideOnClick : true,
31958 * @cfg {Number} showDelay
31959 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31963 * @cfg {Number} hideDelay
31964 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31968 * @cfg {Boolean} autoHide
31969 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31970 * Used in conjunction with hideDelay.
31975 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31976 * (defaults to true). Used in conjunction with autoDismissDelay.
31978 autoDismiss : true,
31981 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31983 autoDismissDelay : 5000,
31985 * @cfg {Boolean} animate
31986 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31991 * @cfg {String} title
31992 * Title text to display (defaults to ''). This can be any valid HTML markup.
31996 * @cfg {String} text
31997 * Body text to display (defaults to ''). This can be any valid HTML markup.
32001 * @cfg {String} cls
32002 * A CSS class to apply to the base quick tip element (defaults to '').
32006 * @cfg {Number} width
32007 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32008 * minWidth or maxWidth.
32013 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32014 * or display QuickTips in a page.
32017 tm = Roo.QuickTips;
32018 cfg = tm.tagConfig;
32020 if(!Roo.isReady){ // allow calling of init() before onReady
32021 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32024 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32025 el.fxDefaults = {stopFx: true};
32026 // maximum custom styling
32027 //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>');
32028 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>');
32029 tipTitle = el.child('h3');
32030 tipTitle.enableDisplayMode("block");
32031 tipBody = el.child('div.x-tip-bd');
32032 tipBodyText = el.child('div.x-tip-bd-inner');
32033 //bdLeft = el.child('div.x-tip-bd-left');
32034 //bdRight = el.child('div.x-tip-bd-right');
32035 close = el.child('div.x-tip-close');
32036 close.enableDisplayMode("block");
32037 close.on("click", hide);
32038 var d = Roo.get(document);
32039 d.on("mousedown", onDown);
32040 d.on("mouseover", onOver);
32041 d.on("mouseout", onOut);
32042 d.on("mousemove", onMove);
32043 esc = d.addKeyListener(27, hide);
32046 dd = el.initDD("default", null, {
32047 onDrag : function(){
32051 dd.setHandleElId(tipTitle.id);
32060 * Configures a new quick tip instance and assigns it to a target element. The following config options
32063 Property Type Description
32064 ---------- --------------------- ------------------------------------------------------------------------
32065 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32067 * @param {Object} config The config object
32069 register : function(config){
32070 var cs = config instanceof Array ? config : arguments;
32071 for(var i = 0, len = cs.length; i < len; i++) {
32073 var target = c.target;
32075 if(target instanceof Array){
32076 for(var j = 0, jlen = target.length; j < jlen; j++){
32077 tagEls[target[j]] = c;
32080 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32087 * Removes this quick tip from its element and destroys it.
32088 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32090 unregister : function(el){
32091 delete tagEls[Roo.id(el)];
32095 * Enable this quick tip.
32097 enable : function(){
32098 if(inited && disabled){
32100 if(locks.length < 1){
32107 * Disable this quick tip.
32109 disable : function(){
32111 clearTimeout(showProc);
32112 clearTimeout(hideProc);
32113 clearTimeout(dismissProc);
32121 * Returns true if the quick tip is enabled, else false.
32123 isEnabled : function(){
32130 attribute : "qtip",
32140 // backwards compat
32141 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32143 * Ext JS Library 1.1.1
32144 * Copyright(c) 2006-2007, Ext JS, LLC.
32146 * Originally Released Under LGPL - original licence link has changed is not relivant.
32149 * <script type="text/javascript">
32154 * @class Roo.tree.TreePanel
32155 * @extends Roo.data.Tree
32157 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32158 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32159 * @cfg {Boolean} enableDD true to enable drag and drop
32160 * @cfg {Boolean} enableDrag true to enable just drag
32161 * @cfg {Boolean} enableDrop true to enable just drop
32162 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32163 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32164 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32165 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32166 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32167 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32168 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32169 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32170 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32171 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32172 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32173 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32174 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32175 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32176 * @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>
32177 * @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>
32180 * @param {String/HTMLElement/Element} el The container element
32181 * @param {Object} config
32183 Roo.tree.TreePanel = function(el, config){
32185 var loader = false;
32187 root = config.root;
32188 delete config.root;
32190 if (config.loader) {
32191 loader = config.loader;
32192 delete config.loader;
32195 Roo.apply(this, config);
32196 Roo.tree.TreePanel.superclass.constructor.call(this);
32197 this.el = Roo.get(el);
32198 this.el.addClass('x-tree');
32199 //console.log(root);
32201 this.setRootNode( Roo.factory(root, Roo.tree));
32204 this.loader = Roo.factory(loader, Roo.tree);
32207 * Read-only. The id of the container element becomes this TreePanel's id.
32209 this.id = this.el.id;
32212 * @event beforeload
32213 * Fires before a node is loaded, return false to cancel
32214 * @param {Node} node The node being loaded
32216 "beforeload" : true,
32219 * Fires when a node is loaded
32220 * @param {Node} node The node that was loaded
32224 * @event textchange
32225 * Fires when the text for a node is changed
32226 * @param {Node} node The node
32227 * @param {String} text The new text
32228 * @param {String} oldText The old text
32230 "textchange" : true,
32232 * @event beforeexpand
32233 * Fires before a node is expanded, return false to cancel.
32234 * @param {Node} node The node
32235 * @param {Boolean} deep
32236 * @param {Boolean} anim
32238 "beforeexpand" : true,
32240 * @event beforecollapse
32241 * Fires before a node is collapsed, return false to cancel.
32242 * @param {Node} node The node
32243 * @param {Boolean} deep
32244 * @param {Boolean} anim
32246 "beforecollapse" : true,
32249 * Fires when a node is expanded
32250 * @param {Node} node The node
32254 * @event disabledchange
32255 * Fires when the disabled status of a node changes
32256 * @param {Node} node The node
32257 * @param {Boolean} disabled
32259 "disabledchange" : true,
32262 * Fires when a node is collapsed
32263 * @param {Node} node The node
32267 * @event beforeclick
32268 * Fires before click processing on a node. Return false to cancel the default action.
32269 * @param {Node} node The node
32270 * @param {Roo.EventObject} e The event object
32272 "beforeclick":true,
32274 * @event checkchange
32275 * Fires when a node with a checkbox's checked property changes
32276 * @param {Node} this This node
32277 * @param {Boolean} checked
32279 "checkchange":true,
32282 * Fires when a node is clicked
32283 * @param {Node} node The node
32284 * @param {Roo.EventObject} e The event object
32289 * Fires when a node is double clicked
32290 * @param {Node} node The node
32291 * @param {Roo.EventObject} e The event object
32295 * @event contextmenu
32296 * Fires when a node is right clicked
32297 * @param {Node} node The node
32298 * @param {Roo.EventObject} e The event object
32300 "contextmenu":true,
32302 * @event beforechildrenrendered
32303 * Fires right before the child nodes for a node are rendered
32304 * @param {Node} node The node
32306 "beforechildrenrendered":true,
32309 * Fires when a node starts being dragged
32310 * @param {Roo.tree.TreePanel} this
32311 * @param {Roo.tree.TreeNode} node
32312 * @param {event} e The raw browser event
32314 "startdrag" : true,
32317 * Fires when a drag operation is complete
32318 * @param {Roo.tree.TreePanel} this
32319 * @param {Roo.tree.TreeNode} node
32320 * @param {event} e The raw browser event
32325 * Fires when a dragged node is dropped on a valid DD target
32326 * @param {Roo.tree.TreePanel} this
32327 * @param {Roo.tree.TreeNode} node
32328 * @param {DD} dd The dd it was dropped on
32329 * @param {event} e The raw browser event
32333 * @event beforenodedrop
32334 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32335 * passed to handlers has the following properties:<br />
32336 * <ul style="padding:5px;padding-left:16px;">
32337 * <li>tree - The TreePanel</li>
32338 * <li>target - The node being targeted for the drop</li>
32339 * <li>data - The drag data from the drag source</li>
32340 * <li>point - The point of the drop - append, above or below</li>
32341 * <li>source - The drag source</li>
32342 * <li>rawEvent - Raw mouse event</li>
32343 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32344 * to be inserted by setting them on this object.</li>
32345 * <li>cancel - Set this to true to cancel the drop.</li>
32347 * @param {Object} dropEvent
32349 "beforenodedrop" : true,
32352 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32353 * passed to handlers has the following properties:<br />
32354 * <ul style="padding:5px;padding-left:16px;">
32355 * <li>tree - The TreePanel</li>
32356 * <li>target - The node being targeted for the drop</li>
32357 * <li>data - The drag data from the drag source</li>
32358 * <li>point - The point of the drop - append, above or below</li>
32359 * <li>source - The drag source</li>
32360 * <li>rawEvent - Raw mouse event</li>
32361 * <li>dropNode - Dropped node(s).</li>
32363 * @param {Object} dropEvent
32367 * @event nodedragover
32368 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32369 * passed to handlers has the following properties:<br />
32370 * <ul style="padding:5px;padding-left:16px;">
32371 * <li>tree - The TreePanel</li>
32372 * <li>target - The node being targeted for the drop</li>
32373 * <li>data - The drag data from the drag source</li>
32374 * <li>point - The point of the drop - append, above or below</li>
32375 * <li>source - The drag source</li>
32376 * <li>rawEvent - Raw mouse event</li>
32377 * <li>dropNode - Drop node(s) provided by the source.</li>
32378 * <li>cancel - Set this to true to signal drop not allowed.</li>
32380 * @param {Object} dragOverEvent
32382 "nodedragover" : true
32385 if(this.singleExpand){
32386 this.on("beforeexpand", this.restrictExpand, this);
32389 this.editor.tree = this;
32390 this.editor = Roo.factory(this.editor, Roo.tree);
32393 if (this.selModel) {
32394 this.selModel = Roo.factory(this.selModel, Roo.tree);
32398 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32399 rootVisible : true,
32400 animate: Roo.enableFx,
32403 hlDrop : Roo.enableFx,
32407 rendererTip: false,
32409 restrictExpand : function(node){
32410 var p = node.parentNode;
32412 if(p.expandedChild && p.expandedChild.parentNode == p){
32413 p.expandedChild.collapse();
32415 p.expandedChild = node;
32419 // private override
32420 setRootNode : function(node){
32421 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32422 if(!this.rootVisible){
32423 node.ui = new Roo.tree.RootTreeNodeUI(node);
32429 * Returns the container element for this TreePanel
32431 getEl : function(){
32436 * Returns the default TreeLoader for this TreePanel
32438 getLoader : function(){
32439 return this.loader;
32445 expandAll : function(){
32446 this.root.expand(true);
32450 * Collapse all nodes
32452 collapseAll : function(){
32453 this.root.collapse(true);
32457 * Returns the selection model used by this TreePanel
32459 getSelectionModel : function(){
32460 if(!this.selModel){
32461 this.selModel = new Roo.tree.DefaultSelectionModel();
32463 return this.selModel;
32467 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32468 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32469 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32472 getChecked : function(a, startNode){
32473 startNode = startNode || this.root;
32475 var f = function(){
32476 if(this.attributes.checked){
32477 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32480 startNode.cascade(f);
32485 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32486 * @param {String} path
32487 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32488 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32489 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32491 expandPath : function(path, attr, callback){
32492 attr = attr || "id";
32493 var keys = path.split(this.pathSeparator);
32494 var curNode = this.root;
32495 if(curNode.attributes[attr] != keys[1]){ // invalid root
32497 callback(false, null);
32502 var f = function(){
32503 if(++index == keys.length){
32505 callback(true, curNode);
32509 var c = curNode.findChild(attr, keys[index]);
32512 callback(false, curNode);
32517 c.expand(false, false, f);
32519 curNode.expand(false, false, f);
32523 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32524 * @param {String} path
32525 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32526 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32527 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32529 selectPath : function(path, attr, callback){
32530 attr = attr || "id";
32531 var keys = path.split(this.pathSeparator);
32532 var v = keys.pop();
32533 if(keys.length > 0){
32534 var f = function(success, node){
32535 if(success && node){
32536 var n = node.findChild(attr, v);
32542 }else if(callback){
32543 callback(false, n);
32547 callback(false, n);
32551 this.expandPath(keys.join(this.pathSeparator), attr, f);
32553 this.root.select();
32555 callback(true, this.root);
32560 getTreeEl : function(){
32565 * Trigger rendering of this TreePanel
32567 render : function(){
32568 if (this.innerCt) {
32569 return this; // stop it rendering more than once!!
32572 this.innerCt = this.el.createChild({tag:"ul",
32573 cls:"x-tree-root-ct " +
32574 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32576 if(this.containerScroll){
32577 Roo.dd.ScrollManager.register(this.el);
32579 if((this.enableDD || this.enableDrop) && !this.dropZone){
32581 * The dropZone used by this tree if drop is enabled
32582 * @type Roo.tree.TreeDropZone
32584 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32585 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32588 if((this.enableDD || this.enableDrag) && !this.dragZone){
32590 * The dragZone used by this tree if drag is enabled
32591 * @type Roo.tree.TreeDragZone
32593 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32594 ddGroup: this.ddGroup || "TreeDD",
32595 scroll: this.ddScroll
32598 this.getSelectionModel().init(this);
32600 Roo.log("ROOT not set in tree");
32603 this.root.render();
32604 if(!this.rootVisible){
32605 this.root.renderChildren();
32611 * Ext JS Library 1.1.1
32612 * Copyright(c) 2006-2007, Ext JS, LLC.
32614 * Originally Released Under LGPL - original licence link has changed is not relivant.
32617 * <script type="text/javascript">
32622 * @class Roo.tree.DefaultSelectionModel
32623 * @extends Roo.util.Observable
32624 * The default single selection for a TreePanel.
32625 * @param {Object} cfg Configuration
32627 Roo.tree.DefaultSelectionModel = function(cfg){
32628 this.selNode = null;
32634 * @event selectionchange
32635 * Fires when the selected node changes
32636 * @param {DefaultSelectionModel} this
32637 * @param {TreeNode} node the new selection
32639 "selectionchange" : true,
32642 * @event beforeselect
32643 * Fires before the selected node changes, return false to cancel the change
32644 * @param {DefaultSelectionModel} this
32645 * @param {TreeNode} node the new selection
32646 * @param {TreeNode} node the old selection
32648 "beforeselect" : true
32651 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32654 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32655 init : function(tree){
32657 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32658 tree.on("click", this.onNodeClick, this);
32661 onNodeClick : function(node, e){
32662 if (e.ctrlKey && this.selNode == node) {
32663 this.unselect(node);
32671 * @param {TreeNode} node The node to select
32672 * @return {TreeNode} The selected node
32674 select : function(node){
32675 var last = this.selNode;
32676 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32678 last.ui.onSelectedChange(false);
32680 this.selNode = node;
32681 node.ui.onSelectedChange(true);
32682 this.fireEvent("selectionchange", this, node, last);
32689 * @param {TreeNode} node The node to unselect
32691 unselect : function(node){
32692 if(this.selNode == node){
32693 this.clearSelections();
32698 * Clear all selections
32700 clearSelections : function(){
32701 var n = this.selNode;
32703 n.ui.onSelectedChange(false);
32704 this.selNode = null;
32705 this.fireEvent("selectionchange", this, null);
32711 * Get the selected node
32712 * @return {TreeNode} The selected node
32714 getSelectedNode : function(){
32715 return this.selNode;
32719 * Returns true if the node is selected
32720 * @param {TreeNode} node The node to check
32721 * @return {Boolean}
32723 isSelected : function(node){
32724 return this.selNode == node;
32728 * Selects the node above the selected node in the tree, intelligently walking the nodes
32729 * @return TreeNode The new selection
32731 selectPrevious : function(){
32732 var s = this.selNode || this.lastSelNode;
32736 var ps = s.previousSibling;
32738 if(!ps.isExpanded() || ps.childNodes.length < 1){
32739 return this.select(ps);
32741 var lc = ps.lastChild;
32742 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32745 return this.select(lc);
32747 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32748 return this.select(s.parentNode);
32754 * Selects the node above the selected node in the tree, intelligently walking the nodes
32755 * @return TreeNode The new selection
32757 selectNext : function(){
32758 var s = this.selNode || this.lastSelNode;
32762 if(s.firstChild && s.isExpanded()){
32763 return this.select(s.firstChild);
32764 }else if(s.nextSibling){
32765 return this.select(s.nextSibling);
32766 }else if(s.parentNode){
32768 s.parentNode.bubble(function(){
32769 if(this.nextSibling){
32770 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32779 onKeyDown : function(e){
32780 var s = this.selNode || this.lastSelNode;
32781 // undesirable, but required
32786 var k = e.getKey();
32794 this.selectPrevious();
32797 e.preventDefault();
32798 if(s.hasChildNodes()){
32799 if(!s.isExpanded()){
32801 }else if(s.firstChild){
32802 this.select(s.firstChild, e);
32807 e.preventDefault();
32808 if(s.hasChildNodes() && s.isExpanded()){
32810 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32811 this.select(s.parentNode, e);
32819 * @class Roo.tree.MultiSelectionModel
32820 * @extends Roo.util.Observable
32821 * Multi selection for a TreePanel.
32822 * @param {Object} cfg Configuration
32824 Roo.tree.MultiSelectionModel = function(){
32825 this.selNodes = [];
32829 * @event selectionchange
32830 * Fires when the selected nodes change
32831 * @param {MultiSelectionModel} this
32832 * @param {Array} nodes Array of the selected nodes
32834 "selectionchange" : true
32836 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32840 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32841 init : function(tree){
32843 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32844 tree.on("click", this.onNodeClick, this);
32847 onNodeClick : function(node, e){
32848 this.select(node, e, e.ctrlKey);
32853 * @param {TreeNode} node The node to select
32854 * @param {EventObject} e (optional) An event associated with the selection
32855 * @param {Boolean} keepExisting True to retain existing selections
32856 * @return {TreeNode} The selected node
32858 select : function(node, e, keepExisting){
32859 if(keepExisting !== true){
32860 this.clearSelections(true);
32862 if(this.isSelected(node)){
32863 this.lastSelNode = node;
32866 this.selNodes.push(node);
32867 this.selMap[node.id] = node;
32868 this.lastSelNode = node;
32869 node.ui.onSelectedChange(true);
32870 this.fireEvent("selectionchange", this, this.selNodes);
32876 * @param {TreeNode} node The node to unselect
32878 unselect : function(node){
32879 if(this.selMap[node.id]){
32880 node.ui.onSelectedChange(false);
32881 var sn = this.selNodes;
32884 index = sn.indexOf(node);
32886 for(var i = 0, len = sn.length; i < len; i++){
32894 this.selNodes.splice(index, 1);
32896 delete this.selMap[node.id];
32897 this.fireEvent("selectionchange", this, this.selNodes);
32902 * Clear all selections
32904 clearSelections : function(suppressEvent){
32905 var sn = this.selNodes;
32907 for(var i = 0, len = sn.length; i < len; i++){
32908 sn[i].ui.onSelectedChange(false);
32910 this.selNodes = [];
32912 if(suppressEvent !== true){
32913 this.fireEvent("selectionchange", this, this.selNodes);
32919 * Returns true if the node is selected
32920 * @param {TreeNode} node The node to check
32921 * @return {Boolean}
32923 isSelected : function(node){
32924 return this.selMap[node.id] ? true : false;
32928 * Returns an array of the selected nodes
32931 getSelectedNodes : function(){
32932 return this.selNodes;
32935 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32937 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32939 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32942 * Ext JS Library 1.1.1
32943 * Copyright(c) 2006-2007, Ext JS, LLC.
32945 * Originally Released Under LGPL - original licence link has changed is not relivant.
32948 * <script type="text/javascript">
32952 * @class Roo.tree.TreeNode
32953 * @extends Roo.data.Node
32954 * @cfg {String} text The text for this node
32955 * @cfg {Boolean} expanded true to start the node expanded
32956 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32957 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32958 * @cfg {Boolean} disabled true to start the node disabled
32959 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32960 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32961 * @cfg {String} cls A css class to be added to the node
32962 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32963 * @cfg {String} href URL of the link used for the node (defaults to #)
32964 * @cfg {String} hrefTarget target frame for the link
32965 * @cfg {String} qtip An Ext QuickTip for the node
32966 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32967 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32968 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32969 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32970 * (defaults to undefined with no checkbox rendered)
32972 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32974 Roo.tree.TreeNode = function(attributes){
32975 attributes = attributes || {};
32976 if(typeof attributes == "string"){
32977 attributes = {text: attributes};
32979 this.childrenRendered = false;
32980 this.rendered = false;
32981 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32982 this.expanded = attributes.expanded === true;
32983 this.isTarget = attributes.isTarget !== false;
32984 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32985 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32988 * Read-only. The text for this node. To change it use setText().
32991 this.text = attributes.text;
32993 * True if this node is disabled.
32996 this.disabled = attributes.disabled === true;
33000 * @event textchange
33001 * Fires when the text for this node is changed
33002 * @param {Node} this This node
33003 * @param {String} text The new text
33004 * @param {String} oldText The old text
33006 "textchange" : true,
33008 * @event beforeexpand
33009 * Fires before this node is expanded, return false to cancel.
33010 * @param {Node} this This node
33011 * @param {Boolean} deep
33012 * @param {Boolean} anim
33014 "beforeexpand" : true,
33016 * @event beforecollapse
33017 * Fires before this node is collapsed, return false to cancel.
33018 * @param {Node} this This node
33019 * @param {Boolean} deep
33020 * @param {Boolean} anim
33022 "beforecollapse" : true,
33025 * Fires when this node is expanded
33026 * @param {Node} this This node
33030 * @event disabledchange
33031 * Fires when the disabled status of this node changes
33032 * @param {Node} this This node
33033 * @param {Boolean} disabled
33035 "disabledchange" : true,
33038 * Fires when this node is collapsed
33039 * @param {Node} this This node
33043 * @event beforeclick
33044 * Fires before click processing. Return false to cancel the default action.
33045 * @param {Node} this This node
33046 * @param {Roo.EventObject} e The event object
33048 "beforeclick":true,
33050 * @event checkchange
33051 * Fires when a node with a checkbox's checked property changes
33052 * @param {Node} this This node
33053 * @param {Boolean} checked
33055 "checkchange":true,
33058 * Fires when this node is clicked
33059 * @param {Node} this This node
33060 * @param {Roo.EventObject} e The event object
33065 * Fires when this node is double clicked
33066 * @param {Node} this This node
33067 * @param {Roo.EventObject} e The event object
33071 * @event contextmenu
33072 * Fires when this node is right clicked
33073 * @param {Node} this This node
33074 * @param {Roo.EventObject} e The event object
33076 "contextmenu":true,
33078 * @event beforechildrenrendered
33079 * Fires right before the child nodes for this node are rendered
33080 * @param {Node} this This node
33082 "beforechildrenrendered":true
33085 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33088 * Read-only. The UI for this node
33091 this.ui = new uiClass(this);
33093 // finally support items[]
33094 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33099 Roo.each(this.attributes.items, function(c) {
33100 this.appendChild(Roo.factory(c,Roo.Tree));
33102 delete this.attributes.items;
33107 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33108 preventHScroll: true,
33110 * Returns true if this node is expanded
33111 * @return {Boolean}
33113 isExpanded : function(){
33114 return this.expanded;
33118 * Returns the UI object for this node
33119 * @return {TreeNodeUI}
33121 getUI : function(){
33125 // private override
33126 setFirstChild : function(node){
33127 var of = this.firstChild;
33128 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33129 if(this.childrenRendered && of && node != of){
33130 of.renderIndent(true, true);
33133 this.renderIndent(true, true);
33137 // private override
33138 setLastChild : function(node){
33139 var ol = this.lastChild;
33140 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33141 if(this.childrenRendered && ol && node != ol){
33142 ol.renderIndent(true, true);
33145 this.renderIndent(true, true);
33149 // these methods are overridden to provide lazy rendering support
33150 // private override
33151 appendChild : function()
33153 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33154 if(node && this.childrenRendered){
33157 this.ui.updateExpandIcon();
33161 // private override
33162 removeChild : function(node){
33163 this.ownerTree.getSelectionModel().unselect(node);
33164 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33165 // if it's been rendered remove dom node
33166 if(this.childrenRendered){
33169 if(this.childNodes.length < 1){
33170 this.collapse(false, false);
33172 this.ui.updateExpandIcon();
33174 if(!this.firstChild) {
33175 this.childrenRendered = false;
33180 // private override
33181 insertBefore : function(node, refNode){
33182 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33183 if(newNode && refNode && this.childrenRendered){
33186 this.ui.updateExpandIcon();
33191 * Sets the text for this node
33192 * @param {String} text
33194 setText : function(text){
33195 var oldText = this.text;
33197 this.attributes.text = text;
33198 if(this.rendered){ // event without subscribing
33199 this.ui.onTextChange(this, text, oldText);
33201 this.fireEvent("textchange", this, text, oldText);
33205 * Triggers selection of this node
33207 select : function(){
33208 this.getOwnerTree().getSelectionModel().select(this);
33212 * Triggers deselection of this node
33214 unselect : function(){
33215 this.getOwnerTree().getSelectionModel().unselect(this);
33219 * Returns true if this node is selected
33220 * @return {Boolean}
33222 isSelected : function(){
33223 return this.getOwnerTree().getSelectionModel().isSelected(this);
33227 * Expand this node.
33228 * @param {Boolean} deep (optional) True to expand all children as well
33229 * @param {Boolean} anim (optional) false to cancel the default animation
33230 * @param {Function} callback (optional) A callback to be called when
33231 * expanding this node completes (does not wait for deep expand to complete).
33232 * Called with 1 parameter, this node.
33234 expand : function(deep, anim, callback){
33235 if(!this.expanded){
33236 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33239 if(!this.childrenRendered){
33240 this.renderChildren();
33242 this.expanded = true;
33243 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33244 this.ui.animExpand(function(){
33245 this.fireEvent("expand", this);
33246 if(typeof callback == "function"){
33250 this.expandChildNodes(true);
33252 }.createDelegate(this));
33256 this.fireEvent("expand", this);
33257 if(typeof callback == "function"){
33262 if(typeof callback == "function"){
33267 this.expandChildNodes(true);
33271 isHiddenRoot : function(){
33272 return this.isRoot && !this.getOwnerTree().rootVisible;
33276 * Collapse this node.
33277 * @param {Boolean} deep (optional) True to collapse all children as well
33278 * @param {Boolean} anim (optional) false to cancel the default animation
33280 collapse : function(deep, anim){
33281 if(this.expanded && !this.isHiddenRoot()){
33282 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33285 this.expanded = false;
33286 if((this.getOwnerTree().animate && anim !== false) || anim){
33287 this.ui.animCollapse(function(){
33288 this.fireEvent("collapse", this);
33290 this.collapseChildNodes(true);
33292 }.createDelegate(this));
33295 this.ui.collapse();
33296 this.fireEvent("collapse", this);
33300 var cs = this.childNodes;
33301 for(var i = 0, len = cs.length; i < len; i++) {
33302 cs[i].collapse(true, false);
33308 delayedExpand : function(delay){
33309 if(!this.expandProcId){
33310 this.expandProcId = this.expand.defer(delay, this);
33315 cancelExpand : function(){
33316 if(this.expandProcId){
33317 clearTimeout(this.expandProcId);
33319 this.expandProcId = false;
33323 * Toggles expanded/collapsed state of the node
33325 toggle : function(){
33334 * Ensures all parent nodes are expanded
33336 ensureVisible : function(callback){
33337 var tree = this.getOwnerTree();
33338 tree.expandPath(this.parentNode.getPath(), false, function(){
33339 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33340 Roo.callback(callback);
33341 }.createDelegate(this));
33345 * Expand all child nodes
33346 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33348 expandChildNodes : function(deep){
33349 var cs = this.childNodes;
33350 for(var i = 0, len = cs.length; i < len; i++) {
33351 cs[i].expand(deep);
33356 * Collapse all child nodes
33357 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33359 collapseChildNodes : function(deep){
33360 var cs = this.childNodes;
33361 for(var i = 0, len = cs.length; i < len; i++) {
33362 cs[i].collapse(deep);
33367 * Disables this node
33369 disable : function(){
33370 this.disabled = true;
33372 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33373 this.ui.onDisableChange(this, true);
33375 this.fireEvent("disabledchange", this, true);
33379 * Enables this node
33381 enable : function(){
33382 this.disabled = false;
33383 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33384 this.ui.onDisableChange(this, false);
33386 this.fireEvent("disabledchange", this, false);
33390 renderChildren : function(suppressEvent){
33391 if(suppressEvent !== false){
33392 this.fireEvent("beforechildrenrendered", this);
33394 var cs = this.childNodes;
33395 for(var i = 0, len = cs.length; i < len; i++){
33396 cs[i].render(true);
33398 this.childrenRendered = true;
33402 sort : function(fn, scope){
33403 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33404 if(this.childrenRendered){
33405 var cs = this.childNodes;
33406 for(var i = 0, len = cs.length; i < len; i++){
33407 cs[i].render(true);
33413 render : function(bulkRender){
33414 this.ui.render(bulkRender);
33415 if(!this.rendered){
33416 this.rendered = true;
33418 this.expanded = false;
33419 this.expand(false, false);
33425 renderIndent : function(deep, refresh){
33427 this.ui.childIndent = null;
33429 this.ui.renderIndent();
33430 if(deep === true && this.childrenRendered){
33431 var cs = this.childNodes;
33432 for(var i = 0, len = cs.length; i < len; i++){
33433 cs[i].renderIndent(true, refresh);
33439 * Ext JS Library 1.1.1
33440 * Copyright(c) 2006-2007, Ext JS, LLC.
33442 * Originally Released Under LGPL - original licence link has changed is not relivant.
33445 * <script type="text/javascript">
33449 * @class Roo.tree.AsyncTreeNode
33450 * @extends Roo.tree.TreeNode
33451 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33453 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33455 Roo.tree.AsyncTreeNode = function(config){
33456 this.loaded = false;
33457 this.loading = false;
33458 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33460 * @event beforeload
33461 * Fires before this node is loaded, return false to cancel
33462 * @param {Node} this This node
33464 this.addEvents({'beforeload':true, 'load': true});
33467 * Fires when this node is loaded
33468 * @param {Node} this This node
33471 * The loader used by this node (defaults to using the tree's defined loader)
33476 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33477 expand : function(deep, anim, callback){
33478 if(this.loading){ // if an async load is already running, waiting til it's done
33480 var f = function(){
33481 if(!this.loading){ // done loading
33482 clearInterval(timer);
33483 this.expand(deep, anim, callback);
33485 }.createDelegate(this);
33486 timer = setInterval(f, 200);
33490 if(this.fireEvent("beforeload", this) === false){
33493 this.loading = true;
33494 this.ui.beforeLoad(this);
33495 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33497 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33501 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33505 * Returns true if this node is currently loading
33506 * @return {Boolean}
33508 isLoading : function(){
33509 return this.loading;
33512 loadComplete : function(deep, anim, callback){
33513 this.loading = false;
33514 this.loaded = true;
33515 this.ui.afterLoad(this);
33516 this.fireEvent("load", this);
33517 this.expand(deep, anim, callback);
33521 * Returns true if this node has been loaded
33522 * @return {Boolean}
33524 isLoaded : function(){
33525 return this.loaded;
33528 hasChildNodes : function(){
33529 if(!this.isLeaf() && !this.loaded){
33532 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33537 * Trigger a reload for this node
33538 * @param {Function} callback
33540 reload : function(callback){
33541 this.collapse(false, false);
33542 while(this.firstChild){
33543 this.removeChild(this.firstChild);
33545 this.childrenRendered = false;
33546 this.loaded = false;
33547 if(this.isHiddenRoot()){
33548 this.expanded = false;
33550 this.expand(false, false, callback);
33554 * Ext JS Library 1.1.1
33555 * Copyright(c) 2006-2007, Ext JS, LLC.
33557 * Originally Released Under LGPL - original licence link has changed is not relivant.
33560 * <script type="text/javascript">
33564 * @class Roo.tree.TreeNodeUI
33566 * @param {Object} node The node to render
33567 * The TreeNode UI implementation is separate from the
33568 * tree implementation. Unless you are customizing the tree UI,
33569 * you should never have to use this directly.
33571 Roo.tree.TreeNodeUI = function(node){
33573 this.rendered = false;
33574 this.animating = false;
33575 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33578 Roo.tree.TreeNodeUI.prototype = {
33579 removeChild : function(node){
33581 this.ctNode.removeChild(node.ui.getEl());
33585 beforeLoad : function(){
33586 this.addClass("x-tree-node-loading");
33589 afterLoad : function(){
33590 this.removeClass("x-tree-node-loading");
33593 onTextChange : function(node, text, oldText){
33595 this.textNode.innerHTML = text;
33599 onDisableChange : function(node, state){
33600 this.disabled = state;
33602 this.addClass("x-tree-node-disabled");
33604 this.removeClass("x-tree-node-disabled");
33608 onSelectedChange : function(state){
33611 this.addClass("x-tree-selected");
33614 this.removeClass("x-tree-selected");
33618 onMove : function(tree, node, oldParent, newParent, index, refNode){
33619 this.childIndent = null;
33621 var targetNode = newParent.ui.getContainer();
33622 if(!targetNode){//target not rendered
33623 this.holder = document.createElement("div");
33624 this.holder.appendChild(this.wrap);
33627 var insertBefore = refNode ? refNode.ui.getEl() : null;
33629 targetNode.insertBefore(this.wrap, insertBefore);
33631 targetNode.appendChild(this.wrap);
33633 this.node.renderIndent(true);
33637 addClass : function(cls){
33639 Roo.fly(this.elNode).addClass(cls);
33643 removeClass : function(cls){
33645 Roo.fly(this.elNode).removeClass(cls);
33649 remove : function(){
33651 this.holder = document.createElement("div");
33652 this.holder.appendChild(this.wrap);
33656 fireEvent : function(){
33657 return this.node.fireEvent.apply(this.node, arguments);
33660 initEvents : function(){
33661 this.node.on("move", this.onMove, this);
33662 var E = Roo.EventManager;
33663 var a = this.anchor;
33665 var el = Roo.fly(a, '_treeui');
33667 if(Roo.isOpera){ // opera render bug ignores the CSS
33668 el.setStyle("text-decoration", "none");
33671 el.on("click", this.onClick, this);
33672 el.on("dblclick", this.onDblClick, this);
33675 Roo.EventManager.on(this.checkbox,
33676 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33679 el.on("contextmenu", this.onContextMenu, this);
33681 var icon = Roo.fly(this.iconNode);
33682 icon.on("click", this.onClick, this);
33683 icon.on("dblclick", this.onDblClick, this);
33684 icon.on("contextmenu", this.onContextMenu, this);
33685 E.on(this.ecNode, "click", this.ecClick, this, true);
33687 if(this.node.disabled){
33688 this.addClass("x-tree-node-disabled");
33690 if(this.node.hidden){
33691 this.addClass("x-tree-node-disabled");
33693 var ot = this.node.getOwnerTree();
33694 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33695 if(dd && (!this.node.isRoot || ot.rootVisible)){
33696 Roo.dd.Registry.register(this.elNode, {
33698 handles: this.getDDHandles(),
33704 getDDHandles : function(){
33705 return [this.iconNode, this.textNode];
33710 this.wrap.style.display = "none";
33716 this.wrap.style.display = "";
33720 onContextMenu : function(e){
33721 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33722 e.preventDefault();
33724 this.fireEvent("contextmenu", this.node, e);
33728 onClick : function(e){
33733 if(this.fireEvent("beforeclick", this.node, e) !== false){
33734 if(!this.disabled && this.node.attributes.href){
33735 this.fireEvent("click", this.node, e);
33738 e.preventDefault();
33743 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33744 this.node.toggle();
33747 this.fireEvent("click", this.node, e);
33753 onDblClick : function(e){
33754 e.preventDefault();
33759 this.toggleCheck();
33761 if(!this.animating && this.node.hasChildNodes()){
33762 this.node.toggle();
33764 this.fireEvent("dblclick", this.node, e);
33767 onCheckChange : function(){
33768 var checked = this.checkbox.checked;
33769 this.node.attributes.checked = checked;
33770 this.fireEvent('checkchange', this.node, checked);
33773 ecClick : function(e){
33774 if(!this.animating && this.node.hasChildNodes()){
33775 this.node.toggle();
33779 startDrop : function(){
33780 this.dropping = true;
33783 // delayed drop so the click event doesn't get fired on a drop
33784 endDrop : function(){
33785 setTimeout(function(){
33786 this.dropping = false;
33787 }.createDelegate(this), 50);
33790 expand : function(){
33791 this.updateExpandIcon();
33792 this.ctNode.style.display = "";
33795 focus : function(){
33796 if(!this.node.preventHScroll){
33797 try{this.anchor.focus();
33799 }else if(!Roo.isIE){
33801 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33802 var l = noscroll.scrollLeft;
33803 this.anchor.focus();
33804 noscroll.scrollLeft = l;
33809 toggleCheck : function(value){
33810 var cb = this.checkbox;
33812 cb.checked = (value === undefined ? !cb.checked : value);
33818 this.anchor.blur();
33822 animExpand : function(callback){
33823 var ct = Roo.get(this.ctNode);
33825 if(!this.node.hasChildNodes()){
33826 this.updateExpandIcon();
33827 this.ctNode.style.display = "";
33828 Roo.callback(callback);
33831 this.animating = true;
33832 this.updateExpandIcon();
33835 callback : function(){
33836 this.animating = false;
33837 Roo.callback(callback);
33840 duration: this.node.ownerTree.duration || .25
33844 highlight : function(){
33845 var tree = this.node.getOwnerTree();
33846 Roo.fly(this.wrap).highlight(
33847 tree.hlColor || "C3DAF9",
33848 {endColor: tree.hlBaseColor}
33852 collapse : function(){
33853 this.updateExpandIcon();
33854 this.ctNode.style.display = "none";
33857 animCollapse : function(callback){
33858 var ct = Roo.get(this.ctNode);
33859 ct.enableDisplayMode('block');
33862 this.animating = true;
33863 this.updateExpandIcon();
33866 callback : function(){
33867 this.animating = false;
33868 Roo.callback(callback);
33871 duration: this.node.ownerTree.duration || .25
33875 getContainer : function(){
33876 return this.ctNode;
33879 getEl : function(){
33883 appendDDGhost : function(ghostNode){
33884 ghostNode.appendChild(this.elNode.cloneNode(true));
33887 getDDRepairXY : function(){
33888 return Roo.lib.Dom.getXY(this.iconNode);
33891 onRender : function(){
33895 render : function(bulkRender){
33896 var n = this.node, a = n.attributes;
33897 var targetNode = n.parentNode ?
33898 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33900 if(!this.rendered){
33901 this.rendered = true;
33903 this.renderElements(n, a, targetNode, bulkRender);
33906 if(this.textNode.setAttributeNS){
33907 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33909 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33912 this.textNode.setAttribute("ext:qtip", a.qtip);
33914 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33917 }else if(a.qtipCfg){
33918 a.qtipCfg.target = Roo.id(this.textNode);
33919 Roo.QuickTips.register(a.qtipCfg);
33922 if(!this.node.expanded){
33923 this.updateExpandIcon();
33926 if(bulkRender === true) {
33927 targetNode.appendChild(this.wrap);
33932 renderElements : function(n, a, targetNode, bulkRender)
33934 // add some indent caching, this helps performance when rendering a large tree
33935 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33936 var t = n.getOwnerTree();
33937 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33938 if (typeof(n.attributes.html) != 'undefined') {
33939 txt = n.attributes.html;
33941 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33942 var cb = typeof a.checked == 'boolean';
33943 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33944 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33945 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33946 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33947 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33948 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33949 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33950 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33951 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33952 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33955 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33956 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33957 n.nextSibling.ui.getEl(), buf.join(""));
33959 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33962 this.elNode = this.wrap.childNodes[0];
33963 this.ctNode = this.wrap.childNodes[1];
33964 var cs = this.elNode.childNodes;
33965 this.indentNode = cs[0];
33966 this.ecNode = cs[1];
33967 this.iconNode = cs[2];
33970 this.checkbox = cs[3];
33973 this.anchor = cs[index];
33974 this.textNode = cs[index].firstChild;
33977 getAnchor : function(){
33978 return this.anchor;
33981 getTextEl : function(){
33982 return this.textNode;
33985 getIconEl : function(){
33986 return this.iconNode;
33989 isChecked : function(){
33990 return this.checkbox ? this.checkbox.checked : false;
33993 updateExpandIcon : function(){
33995 var n = this.node, c1, c2;
33996 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33997 var hasChild = n.hasChildNodes();
34001 c1 = "x-tree-node-collapsed";
34002 c2 = "x-tree-node-expanded";
34005 c1 = "x-tree-node-expanded";
34006 c2 = "x-tree-node-collapsed";
34009 this.removeClass("x-tree-node-leaf");
34010 this.wasLeaf = false;
34012 if(this.c1 != c1 || this.c2 != c2){
34013 Roo.fly(this.elNode).replaceClass(c1, c2);
34014 this.c1 = c1; this.c2 = c2;
34017 // this changes non-leafs into leafs if they have no children.
34018 // it's not very rational behaviour..
34020 if(!this.wasLeaf && this.node.leaf){
34021 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34024 this.wasLeaf = true;
34027 var ecc = "x-tree-ec-icon "+cls;
34028 if(this.ecc != ecc){
34029 this.ecNode.className = ecc;
34035 getChildIndent : function(){
34036 if(!this.childIndent){
34040 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34042 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34044 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34049 this.childIndent = buf.join("");
34051 return this.childIndent;
34054 renderIndent : function(){
34057 var p = this.node.parentNode;
34059 indent = p.ui.getChildIndent();
34061 if(this.indentMarkup != indent){ // don't rerender if not required
34062 this.indentNode.innerHTML = indent;
34063 this.indentMarkup = indent;
34065 this.updateExpandIcon();
34070 Roo.tree.RootTreeNodeUI = function(){
34071 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34073 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34074 render : function(){
34075 if(!this.rendered){
34076 var targetNode = this.node.ownerTree.innerCt.dom;
34077 this.node.expanded = true;
34078 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34079 this.wrap = this.ctNode = targetNode.firstChild;
34082 collapse : function(){
34084 expand : function(){
34088 * Ext JS Library 1.1.1
34089 * Copyright(c) 2006-2007, Ext JS, LLC.
34091 * Originally Released Under LGPL - original licence link has changed is not relivant.
34094 * <script type="text/javascript">
34097 * @class Roo.tree.TreeLoader
34098 * @extends Roo.util.Observable
34099 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34100 * nodes from a specified URL. The response must be a javascript Array definition
34101 * who's elements are node definition objects. eg:
34106 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34107 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34114 * The old style respose with just an array is still supported, but not recommended.
34117 * A server request is sent, and child nodes are loaded only when a node is expanded.
34118 * The loading node's id is passed to the server under the parameter name "node" to
34119 * enable the server to produce the correct child nodes.
34121 * To pass extra parameters, an event handler may be attached to the "beforeload"
34122 * event, and the parameters specified in the TreeLoader's baseParams property:
34124 myTreeLoader.on("beforeload", function(treeLoader, node) {
34125 this.baseParams.category = node.attributes.category;
34128 * This would pass an HTTP parameter called "category" to the server containing
34129 * the value of the Node's "category" attribute.
34131 * Creates a new Treeloader.
34132 * @param {Object} config A config object containing config properties.
34134 Roo.tree.TreeLoader = function(config){
34135 this.baseParams = {};
34136 this.requestMethod = "POST";
34137 Roo.apply(this, config);
34142 * @event beforeload
34143 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34144 * @param {Object} This TreeLoader object.
34145 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34146 * @param {Object} callback The callback function specified in the {@link #load} call.
34151 * Fires when the node has been successfuly loaded.
34152 * @param {Object} This TreeLoader object.
34153 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34154 * @param {Object} response The response object containing the data from the server.
34158 * @event loadexception
34159 * Fires if the network request failed.
34160 * @param {Object} This TreeLoader object.
34161 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34162 * @param {Object} response The response object containing the data from the server.
34164 loadexception : true,
34167 * Fires before a node is created, enabling you to return custom Node types
34168 * @param {Object} This TreeLoader object.
34169 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34174 Roo.tree.TreeLoader.superclass.constructor.call(this);
34177 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34179 * @cfg {String} dataUrl The URL from which to request a Json string which
34180 * specifies an array of node definition object representing the child nodes
34184 * @cfg {String} requestMethod either GET or POST
34185 * defaults to POST (due to BC)
34189 * @cfg {Object} baseParams (optional) An object containing properties which
34190 * specify HTTP parameters to be passed to each request for child nodes.
34193 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34194 * created by this loader. If the attributes sent by the server have an attribute in this object,
34195 * they take priority.
34198 * @cfg {Object} uiProviders (optional) An object containing properties which
34200 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34201 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34202 * <i>uiProvider</i> attribute of a returned child node is a string rather
34203 * than a reference to a TreeNodeUI implementation, this that string value
34204 * is used as a property name in the uiProviders object. You can define the provider named
34205 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34210 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34211 * child nodes before loading.
34213 clearOnLoad : true,
34216 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34217 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34218 * Grid query { data : [ .....] }
34223 * @cfg {String} queryParam (optional)
34224 * Name of the query as it will be passed on the querystring (defaults to 'node')
34225 * eg. the request will be ?node=[id]
34232 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34233 * This is called automatically when a node is expanded, but may be used to reload
34234 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34235 * @param {Roo.tree.TreeNode} node
34236 * @param {Function} callback
34238 load : function(node, callback){
34239 if(this.clearOnLoad){
34240 while(node.firstChild){
34241 node.removeChild(node.firstChild);
34244 if(node.attributes.children){ // preloaded json children
34245 var cs = node.attributes.children;
34246 for(var i = 0, len = cs.length; i < len; i++){
34247 node.appendChild(this.createNode(cs[i]));
34249 if(typeof callback == "function"){
34252 }else if(this.dataUrl){
34253 this.requestData(node, callback);
34257 getParams: function(node){
34258 var buf = [], bp = this.baseParams;
34259 for(var key in bp){
34260 if(typeof bp[key] != "function"){
34261 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34264 var n = this.queryParam === false ? 'node' : this.queryParam;
34265 buf.push(n + "=", encodeURIComponent(node.id));
34266 return buf.join("");
34269 requestData : function(node, callback){
34270 if(this.fireEvent("beforeload", this, node, callback) !== false){
34271 this.transId = Roo.Ajax.request({
34272 method:this.requestMethod,
34273 url: this.dataUrl||this.url,
34274 success: this.handleResponse,
34275 failure: this.handleFailure,
34277 argument: {callback: callback, node: node},
34278 params: this.getParams(node)
34281 // if the load is cancelled, make sure we notify
34282 // the node that we are done
34283 if(typeof callback == "function"){
34289 isLoading : function(){
34290 return this.transId ? true : false;
34293 abort : function(){
34294 if(this.isLoading()){
34295 Roo.Ajax.abort(this.transId);
34300 createNode : function(attr)
34302 // apply baseAttrs, nice idea Corey!
34303 if(this.baseAttrs){
34304 Roo.applyIf(attr, this.baseAttrs);
34306 if(this.applyLoader !== false){
34307 attr.loader = this;
34309 // uiProvider = depreciated..
34311 if(typeof(attr.uiProvider) == 'string'){
34312 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34313 /** eval:var:attr */ eval(attr.uiProvider);
34315 if(typeof(this.uiProviders['default']) != 'undefined') {
34316 attr.uiProvider = this.uiProviders['default'];
34319 this.fireEvent('create', this, attr);
34321 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34323 new Roo.tree.TreeNode(attr) :
34324 new Roo.tree.AsyncTreeNode(attr));
34327 processResponse : function(response, node, callback)
34329 var json = response.responseText;
34332 var o = Roo.decode(json);
34334 if (this.root === false && typeof(o.success) != undefined) {
34335 this.root = 'data'; // the default behaviour for list like data..
34338 if (this.root !== false && !o.success) {
34339 // it's a failure condition.
34340 var a = response.argument;
34341 this.fireEvent("loadexception", this, a.node, response);
34342 Roo.log("Load failed - should have a handler really");
34348 if (this.root !== false) {
34352 for(var i = 0, len = o.length; i < len; i++){
34353 var n = this.createNode(o[i]);
34355 node.appendChild(n);
34358 if(typeof callback == "function"){
34359 callback(this, node);
34362 this.handleFailure(response);
34366 handleResponse : function(response){
34367 this.transId = false;
34368 var a = response.argument;
34369 this.processResponse(response, a.node, a.callback);
34370 this.fireEvent("load", this, a.node, response);
34373 handleFailure : function(response)
34375 // should handle failure better..
34376 this.transId = false;
34377 var a = response.argument;
34378 this.fireEvent("loadexception", this, a.node, response);
34379 if(typeof a.callback == "function"){
34380 a.callback(this, a.node);
34385 * Ext JS Library 1.1.1
34386 * Copyright(c) 2006-2007, Ext JS, LLC.
34388 * Originally Released Under LGPL - original licence link has changed is not relivant.
34391 * <script type="text/javascript">
34395 * @class Roo.tree.TreeFilter
34396 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34397 * @param {TreePanel} tree
34398 * @param {Object} config (optional)
34400 Roo.tree.TreeFilter = function(tree, config){
34402 this.filtered = {};
34403 Roo.apply(this, config);
34406 Roo.tree.TreeFilter.prototype = {
34413 * Filter the data by a specific attribute.
34414 * @param {String/RegExp} value Either string that the attribute value
34415 * should start with or a RegExp to test against the attribute
34416 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34417 * @param {TreeNode} startNode (optional) The node to start the filter at.
34419 filter : function(value, attr, startNode){
34420 attr = attr || "text";
34422 if(typeof value == "string"){
34423 var vlen = value.length;
34424 // auto clear empty filter
34425 if(vlen == 0 && this.clearBlank){
34429 value = value.toLowerCase();
34431 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34433 }else if(value.exec){ // regex?
34435 return value.test(n.attributes[attr]);
34438 throw 'Illegal filter type, must be string or regex';
34440 this.filterBy(f, null, startNode);
34444 * Filter by a function. The passed function will be called with each
34445 * node in the tree (or from the startNode). If the function returns true, the node is kept
34446 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34447 * @param {Function} fn The filter function
34448 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34450 filterBy : function(fn, scope, startNode){
34451 startNode = startNode || this.tree.root;
34452 if(this.autoClear){
34455 var af = this.filtered, rv = this.reverse;
34456 var f = function(n){
34457 if(n == startNode){
34463 var m = fn.call(scope || n, n);
34471 startNode.cascade(f);
34474 if(typeof id != "function"){
34476 if(n && n.parentNode){
34477 n.parentNode.removeChild(n);
34485 * Clears the current filter. Note: with the "remove" option
34486 * set a filter cannot be cleared.
34488 clear : function(){
34490 var af = this.filtered;
34492 if(typeof id != "function"){
34499 this.filtered = {};
34504 * Ext JS Library 1.1.1
34505 * Copyright(c) 2006-2007, Ext JS, LLC.
34507 * Originally Released Under LGPL - original licence link has changed is not relivant.
34510 * <script type="text/javascript">
34515 * @class Roo.tree.TreeSorter
34516 * Provides sorting of nodes in a TreePanel
34518 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34519 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34520 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34521 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34522 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34523 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34525 * @param {TreePanel} tree
34526 * @param {Object} config
34528 Roo.tree.TreeSorter = function(tree, config){
34529 Roo.apply(this, config);
34530 tree.on("beforechildrenrendered", this.doSort, this);
34531 tree.on("append", this.updateSort, this);
34532 tree.on("insert", this.updateSort, this);
34534 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34535 var p = this.property || "text";
34536 var sortType = this.sortType;
34537 var fs = this.folderSort;
34538 var cs = this.caseSensitive === true;
34539 var leafAttr = this.leafAttr || 'leaf';
34541 this.sortFn = function(n1, n2){
34543 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34546 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34550 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34551 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34553 return dsc ? +1 : -1;
34555 return dsc ? -1 : +1;
34562 Roo.tree.TreeSorter.prototype = {
34563 doSort : function(node){
34564 node.sort(this.sortFn);
34567 compareNodes : function(n1, n2){
34568 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34571 updateSort : function(tree, node){
34572 if(node.childrenRendered){
34573 this.doSort.defer(1, this, [node]);
34578 * Ext JS Library 1.1.1
34579 * Copyright(c) 2006-2007, Ext JS, LLC.
34581 * Originally Released Under LGPL - original licence link has changed is not relivant.
34584 * <script type="text/javascript">
34587 if(Roo.dd.DropZone){
34589 Roo.tree.TreeDropZone = function(tree, config){
34590 this.allowParentInsert = false;
34591 this.allowContainerDrop = false;
34592 this.appendOnly = false;
34593 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34595 this.lastInsertClass = "x-tree-no-status";
34596 this.dragOverData = {};
34599 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34600 ddGroup : "TreeDD",
34603 expandDelay : 1000,
34605 expandNode : function(node){
34606 if(node.hasChildNodes() && !node.isExpanded()){
34607 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34611 queueExpand : function(node){
34612 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34615 cancelExpand : function(){
34616 if(this.expandProcId){
34617 clearTimeout(this.expandProcId);
34618 this.expandProcId = false;
34622 isValidDropPoint : function(n, pt, dd, e, data){
34623 if(!n || !data){ return false; }
34624 var targetNode = n.node;
34625 var dropNode = data.node;
34626 // default drop rules
34627 if(!(targetNode && targetNode.isTarget && pt)){
34630 if(pt == "append" && targetNode.allowChildren === false){
34633 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34636 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34639 // reuse the object
34640 var overEvent = this.dragOverData;
34641 overEvent.tree = this.tree;
34642 overEvent.target = targetNode;
34643 overEvent.data = data;
34644 overEvent.point = pt;
34645 overEvent.source = dd;
34646 overEvent.rawEvent = e;
34647 overEvent.dropNode = dropNode;
34648 overEvent.cancel = false;
34649 var result = this.tree.fireEvent("nodedragover", overEvent);
34650 return overEvent.cancel === false && result !== false;
34653 getDropPoint : function(e, n, dd)
34657 return tn.allowChildren !== false ? "append" : false; // always append for root
34659 var dragEl = n.ddel;
34660 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34661 var y = Roo.lib.Event.getPageY(e);
34662 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34664 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34665 var noAppend = tn.allowChildren === false;
34666 if(this.appendOnly || tn.parentNode.allowChildren === false){
34667 return noAppend ? false : "append";
34669 var noBelow = false;
34670 if(!this.allowParentInsert){
34671 noBelow = tn.hasChildNodes() && tn.isExpanded();
34673 var q = (b - t) / (noAppend ? 2 : 3);
34674 if(y >= t && y < (t + q)){
34676 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34683 onNodeEnter : function(n, dd, e, data)
34685 this.cancelExpand();
34688 onNodeOver : function(n, dd, e, data)
34691 var pt = this.getDropPoint(e, n, dd);
34694 // auto node expand check
34695 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34696 this.queueExpand(node);
34697 }else if(pt != "append"){
34698 this.cancelExpand();
34701 // set the insert point style on the target node
34702 var returnCls = this.dropNotAllowed;
34703 if(this.isValidDropPoint(n, pt, dd, e, data)){
34708 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34709 cls = "x-tree-drag-insert-above";
34710 }else if(pt == "below"){
34711 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34712 cls = "x-tree-drag-insert-below";
34714 returnCls = "x-tree-drop-ok-append";
34715 cls = "x-tree-drag-append";
34717 if(this.lastInsertClass != cls){
34718 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34719 this.lastInsertClass = cls;
34726 onNodeOut : function(n, dd, e, data){
34728 this.cancelExpand();
34729 this.removeDropIndicators(n);
34732 onNodeDrop : function(n, dd, e, data){
34733 var point = this.getDropPoint(e, n, dd);
34734 var targetNode = n.node;
34735 targetNode.ui.startDrop();
34736 if(!this.isValidDropPoint(n, point, dd, e, data)){
34737 targetNode.ui.endDrop();
34740 // first try to find the drop node
34741 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34744 target: targetNode,
34749 dropNode: dropNode,
34752 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34753 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34754 targetNode.ui.endDrop();
34757 // allow target changing
34758 targetNode = dropEvent.target;
34759 if(point == "append" && !targetNode.isExpanded()){
34760 targetNode.expand(false, null, function(){
34761 this.completeDrop(dropEvent);
34762 }.createDelegate(this));
34764 this.completeDrop(dropEvent);
34769 completeDrop : function(de){
34770 var ns = de.dropNode, p = de.point, t = de.target;
34771 if(!(ns instanceof Array)){
34775 for(var i = 0, len = ns.length; i < len; i++){
34778 t.parentNode.insertBefore(n, t);
34779 }else if(p == "below"){
34780 t.parentNode.insertBefore(n, t.nextSibling);
34786 if(this.tree.hlDrop){
34790 this.tree.fireEvent("nodedrop", de);
34793 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34794 if(this.tree.hlDrop){
34795 dropNode.ui.focus();
34796 dropNode.ui.highlight();
34798 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34801 getTree : function(){
34805 removeDropIndicators : function(n){
34808 Roo.fly(el).removeClass([
34809 "x-tree-drag-insert-above",
34810 "x-tree-drag-insert-below",
34811 "x-tree-drag-append"]);
34812 this.lastInsertClass = "_noclass";
34816 beforeDragDrop : function(target, e, id){
34817 this.cancelExpand();
34821 afterRepair : function(data){
34822 if(data && Roo.enableFx){
34823 data.node.ui.highlight();
34833 * Ext JS Library 1.1.1
34834 * Copyright(c) 2006-2007, Ext JS, LLC.
34836 * Originally Released Under LGPL - original licence link has changed is not relivant.
34839 * <script type="text/javascript">
34843 if(Roo.dd.DragZone){
34844 Roo.tree.TreeDragZone = function(tree, config){
34845 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34849 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34850 ddGroup : "TreeDD",
34852 onBeforeDrag : function(data, e){
34854 return n && n.draggable && !n.disabled;
34858 onInitDrag : function(e){
34859 var data = this.dragData;
34860 this.tree.getSelectionModel().select(data.node);
34861 this.proxy.update("");
34862 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34863 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34866 getRepairXY : function(e, data){
34867 return data.node.ui.getDDRepairXY();
34870 onEndDrag : function(data, e){
34871 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34876 onValidDrop : function(dd, e, id){
34877 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34881 beforeInvalidDrop : function(e, id){
34882 // this scrolls the original position back into view
34883 var sm = this.tree.getSelectionModel();
34884 sm.clearSelections();
34885 sm.select(this.dragData.node);
34890 * Ext JS Library 1.1.1
34891 * Copyright(c) 2006-2007, Ext JS, LLC.
34893 * Originally Released Under LGPL - original licence link has changed is not relivant.
34896 * <script type="text/javascript">
34899 * @class Roo.tree.TreeEditor
34900 * @extends Roo.Editor
34901 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34902 * as the editor field.
34904 * @param {Object} config (used to be the tree panel.)
34905 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34907 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34908 * @cfg {Roo.form.TextField|Object} field The field configuration
34912 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34915 if (oldconfig) { // old style..
34916 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34919 tree = config.tree;
34920 config.field = config.field || {};
34921 config.field.xtype = 'TextField';
34922 field = Roo.factory(config.field, Roo.form);
34924 config = config || {};
34929 * @event beforenodeedit
34930 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34931 * false from the handler of this event.
34932 * @param {Editor} this
34933 * @param {Roo.tree.Node} node
34935 "beforenodeedit" : true
34939 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34943 tree.on('beforeclick', this.beforeNodeClick, this);
34944 tree.getTreeEl().on('mousedown', this.hide, this);
34945 this.on('complete', this.updateNode, this);
34946 this.on('beforestartedit', this.fitToTree, this);
34947 this.on('startedit', this.bindScroll, this, {delay:10});
34948 this.on('specialkey', this.onSpecialKey, this);
34951 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34953 * @cfg {String} alignment
34954 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34960 * @cfg {Boolean} hideEl
34961 * True to hide the bound element while the editor is displayed (defaults to false)
34965 * @cfg {String} cls
34966 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34968 cls: "x-small-editor x-tree-editor",
34970 * @cfg {Boolean} shim
34971 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34977 * @cfg {Number} maxWidth
34978 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34979 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34980 * scroll and client offsets into account prior to each edit.
34987 fitToTree : function(ed, el){
34988 var td = this.tree.getTreeEl().dom, nd = el.dom;
34989 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34990 td.scrollLeft = nd.offsetLeft;
34994 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34995 this.setSize(w, '');
34997 return this.fireEvent('beforenodeedit', this, this.editNode);
35002 triggerEdit : function(node){
35003 this.completeEdit();
35004 this.editNode = node;
35005 this.startEdit(node.ui.textNode, node.text);
35009 bindScroll : function(){
35010 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35014 beforeNodeClick : function(node, e){
35015 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35016 this.lastClick = new Date();
35017 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35019 this.triggerEdit(node);
35026 updateNode : function(ed, value){
35027 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35028 this.editNode.setText(value);
35032 onHide : function(){
35033 Roo.tree.TreeEditor.superclass.onHide.call(this);
35035 this.editNode.ui.focus();
35040 onSpecialKey : function(field, e){
35041 var k = e.getKey();
35045 }else if(k == e.ENTER && !e.hasModifier()){
35047 this.completeEdit();
35050 });//<Script type="text/javascript">
35053 * Ext JS Library 1.1.1
35054 * Copyright(c) 2006-2007, Ext JS, LLC.
35056 * Originally Released Under LGPL - original licence link has changed is not relivant.
35059 * <script type="text/javascript">
35063 * Not documented??? - probably should be...
35066 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35067 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35069 renderElements : function(n, a, targetNode, bulkRender){
35070 //consel.log("renderElements?");
35071 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35073 var t = n.getOwnerTree();
35074 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35076 var cols = t.columns;
35077 var bw = t.borderWidth;
35079 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35080 var cb = typeof a.checked == "boolean";
35081 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35082 var colcls = 'x-t-' + tid + '-c0';
35084 '<li class="x-tree-node">',
35087 '<div class="x-tree-node-el ', a.cls,'">',
35089 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35092 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35093 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35094 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35095 (a.icon ? ' x-tree-node-inline-icon' : ''),
35096 (a.iconCls ? ' '+a.iconCls : ''),
35097 '" unselectable="on" />',
35098 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35099 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35101 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35102 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35103 '<span unselectable="on" qtip="' + tx + '">',
35107 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35108 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35110 for(var i = 1, len = cols.length; i < len; i++){
35112 colcls = 'x-t-' + tid + '-c' +i;
35113 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35114 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35115 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35121 '<div class="x-clear"></div></div>',
35122 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35125 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35126 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35127 n.nextSibling.ui.getEl(), buf.join(""));
35129 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35131 var el = this.wrap.firstChild;
35133 this.elNode = el.firstChild;
35134 this.ranchor = el.childNodes[1];
35135 this.ctNode = this.wrap.childNodes[1];
35136 var cs = el.firstChild.childNodes;
35137 this.indentNode = cs[0];
35138 this.ecNode = cs[1];
35139 this.iconNode = cs[2];
35142 this.checkbox = cs[3];
35145 this.anchor = cs[index];
35147 this.textNode = cs[index].firstChild;
35149 //el.on("click", this.onClick, this);
35150 //el.on("dblclick", this.onDblClick, this);
35153 // console.log(this);
35155 initEvents : function(){
35156 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35159 var a = this.ranchor;
35161 var el = Roo.get(a);
35163 if(Roo.isOpera){ // opera render bug ignores the CSS
35164 el.setStyle("text-decoration", "none");
35167 el.on("click", this.onClick, this);
35168 el.on("dblclick", this.onDblClick, this);
35169 el.on("contextmenu", this.onContextMenu, this);
35173 /*onSelectedChange : function(state){
35176 this.addClass("x-tree-selected");
35179 this.removeClass("x-tree-selected");
35182 addClass : function(cls){
35184 Roo.fly(this.elRow).addClass(cls);
35190 removeClass : function(cls){
35192 Roo.fly(this.elRow).removeClass(cls);
35198 });//<Script type="text/javascript">
35202 * Ext JS Library 1.1.1
35203 * Copyright(c) 2006-2007, Ext JS, LLC.
35205 * Originally Released Under LGPL - original licence link has changed is not relivant.
35208 * <script type="text/javascript">
35213 * @class Roo.tree.ColumnTree
35214 * @extends Roo.data.TreePanel
35215 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35216 * @cfg {int} borderWidth compined right/left border allowance
35218 * @param {String/HTMLElement/Element} el The container element
35219 * @param {Object} config
35221 Roo.tree.ColumnTree = function(el, config)
35223 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35227 * Fire this event on a container when it resizes
35228 * @param {int} w Width
35229 * @param {int} h Height
35233 this.on('resize', this.onResize, this);
35236 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35240 borderWidth: Roo.isBorderBox ? 0 : 2,
35243 render : function(){
35244 // add the header.....
35246 Roo.tree.ColumnTree.superclass.render.apply(this);
35248 this.el.addClass('x-column-tree');
35250 this.headers = this.el.createChild(
35251 {cls:'x-tree-headers'},this.innerCt.dom);
35253 var cols = this.columns, c;
35254 var totalWidth = 0;
35256 var len = cols.length;
35257 for(var i = 0; i < len; i++){
35259 totalWidth += c.width;
35260 this.headEls.push(this.headers.createChild({
35261 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35263 cls:'x-tree-hd-text',
35266 style:'width:'+(c.width-this.borderWidth)+'px;'
35269 this.headers.createChild({cls:'x-clear'});
35270 // prevent floats from wrapping when clipped
35271 this.headers.setWidth(totalWidth);
35272 //this.innerCt.setWidth(totalWidth);
35273 this.innerCt.setStyle({ overflow: 'auto' });
35274 this.onResize(this.width, this.height);
35278 onResize : function(w,h)
35283 this.innerCt.setWidth(this.width);
35284 this.innerCt.setHeight(this.height-20);
35287 var cols = this.columns, c;
35288 var totalWidth = 0;
35290 var len = cols.length;
35291 for(var i = 0; i < len; i++){
35293 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35294 // it's the expander..
35295 expEl = this.headEls[i];
35298 totalWidth += c.width;
35302 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35304 this.headers.setWidth(w-20);
35313 * Ext JS Library 1.1.1
35314 * Copyright(c) 2006-2007, Ext JS, LLC.
35316 * Originally Released Under LGPL - original licence link has changed is not relivant.
35319 * <script type="text/javascript">
35323 * @class Roo.menu.Menu
35324 * @extends Roo.util.Observable
35325 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35326 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35328 * Creates a new Menu
35329 * @param {Object} config Configuration options
35331 Roo.menu.Menu = function(config){
35332 Roo.apply(this, config);
35333 this.id = this.id || Roo.id();
35336 * @event beforeshow
35337 * Fires before this menu is displayed
35338 * @param {Roo.menu.Menu} this
35342 * @event beforehide
35343 * Fires before this menu is hidden
35344 * @param {Roo.menu.Menu} this
35349 * Fires after this menu is displayed
35350 * @param {Roo.menu.Menu} this
35355 * Fires after this menu is hidden
35356 * @param {Roo.menu.Menu} this
35361 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35362 * @param {Roo.menu.Menu} this
35363 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35364 * @param {Roo.EventObject} e
35369 * Fires when the mouse is hovering over this menu
35370 * @param {Roo.menu.Menu} this
35371 * @param {Roo.EventObject} e
35372 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35377 * Fires when the mouse exits this menu
35378 * @param {Roo.menu.Menu} this
35379 * @param {Roo.EventObject} e
35380 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35385 * Fires when a menu item contained in this menu is clicked
35386 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35387 * @param {Roo.EventObject} e
35391 if (this.registerMenu) {
35392 Roo.menu.MenuMgr.register(this);
35395 var mis = this.items;
35396 this.items = new Roo.util.MixedCollection();
35398 this.add.apply(this, mis);
35402 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35404 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35408 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35409 * for bottom-right shadow (defaults to "sides")
35413 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35414 * this menu (defaults to "tl-tr?")
35416 subMenuAlign : "tl-tr?",
35418 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35419 * relative to its element of origin (defaults to "tl-bl?")
35421 defaultAlign : "tl-bl?",
35423 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35425 allowOtherMenus : false,
35427 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35429 registerMenu : true,
35434 render : function(){
35438 var el = this.el = new Roo.Layer({
35440 shadow:this.shadow,
35442 parentEl: this.parentEl || document.body,
35446 this.keyNav = new Roo.menu.MenuNav(this);
35449 el.addClass("x-menu-plain");
35452 el.addClass(this.cls);
35454 // generic focus element
35455 this.focusEl = el.createChild({
35456 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35458 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35459 ul.on("click", this.onClick, this);
35460 ul.on("mouseover", this.onMouseOver, this);
35461 ul.on("mouseout", this.onMouseOut, this);
35462 this.items.each(function(item){
35467 var li = document.createElement("li");
35468 li.className = "x-menu-list-item";
35469 ul.dom.appendChild(li);
35470 item.render(li, this);
35477 autoWidth : function(){
35478 var el = this.el, ul = this.ul;
35482 var w = this.width;
35485 }else if(Roo.isIE){
35486 el.setWidth(this.minWidth);
35487 var t = el.dom.offsetWidth; // force recalc
35488 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35493 delayAutoWidth : function(){
35496 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35498 this.awTask.delay(20);
35503 findTargetItem : function(e){
35504 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35505 if(t && t.menuItemId){
35506 return this.items.get(t.menuItemId);
35511 onClick : function(e){
35513 if(t = this.findTargetItem(e)){
35515 this.fireEvent("click", this, t, e);
35520 setActiveItem : function(item, autoExpand){
35521 if(item != this.activeItem){
35522 if(this.activeItem){
35523 this.activeItem.deactivate();
35525 this.activeItem = item;
35526 item.activate(autoExpand);
35527 }else if(autoExpand){
35533 tryActivate : function(start, step){
35534 var items = this.items;
35535 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35536 var item = items.get(i);
35537 if(!item.disabled && item.canActivate){
35538 this.setActiveItem(item, false);
35546 onMouseOver : function(e){
35548 if(t = this.findTargetItem(e)){
35549 if(t.canActivate && !t.disabled){
35550 this.setActiveItem(t, true);
35553 this.fireEvent("mouseover", this, e, t);
35557 onMouseOut : function(e){
35559 if(t = this.findTargetItem(e)){
35560 if(t == this.activeItem && t.shouldDeactivate(e)){
35561 this.activeItem.deactivate();
35562 delete this.activeItem;
35565 this.fireEvent("mouseout", this, e, t);
35569 * Read-only. Returns true if the menu is currently displayed, else false.
35572 isVisible : function(){
35573 return this.el && !this.hidden;
35577 * Displays this menu relative to another element
35578 * @param {String/HTMLElement/Roo.Element} element The element to align to
35579 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35580 * the element (defaults to this.defaultAlign)
35581 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35583 show : function(el, pos, parentMenu){
35584 this.parentMenu = parentMenu;
35588 this.fireEvent("beforeshow", this);
35589 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35593 * Displays this menu at a specific xy position
35594 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35595 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35597 showAt : function(xy, parentMenu, /* private: */_e){
35598 this.parentMenu = parentMenu;
35603 this.fireEvent("beforeshow", this);
35604 xy = this.el.adjustForConstraints(xy);
35608 this.hidden = false;
35610 this.fireEvent("show", this);
35613 focus : function(){
35615 this.doFocus.defer(50, this);
35619 doFocus : function(){
35621 this.focusEl.focus();
35626 * Hides this menu and optionally all parent menus
35627 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35629 hide : function(deep){
35630 if(this.el && this.isVisible()){
35631 this.fireEvent("beforehide", this);
35632 if(this.activeItem){
35633 this.activeItem.deactivate();
35634 this.activeItem = null;
35637 this.hidden = true;
35638 this.fireEvent("hide", this);
35640 if(deep === true && this.parentMenu){
35641 this.parentMenu.hide(true);
35646 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35647 * Any of the following are valid:
35649 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35650 * <li>An HTMLElement object which will be converted to a menu item</li>
35651 * <li>A menu item config object that will be created as a new menu item</li>
35652 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35653 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35658 var menu = new Roo.menu.Menu();
35660 // Create a menu item to add by reference
35661 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35663 // Add a bunch of items at once using different methods.
35664 // Only the last item added will be returned.
35665 var item = menu.add(
35666 menuItem, // add existing item by ref
35667 'Dynamic Item', // new TextItem
35668 '-', // new separator
35669 { text: 'Config Item' } // new item by config
35672 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35673 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35676 var a = arguments, l = a.length, item;
35677 for(var i = 0; i < l; i++){
35679 if ((typeof(el) == "object") && el.xtype && el.xns) {
35680 el = Roo.factory(el, Roo.menu);
35683 if(el.render){ // some kind of Item
35684 item = this.addItem(el);
35685 }else if(typeof el == "string"){ // string
35686 if(el == "separator" || el == "-"){
35687 item = this.addSeparator();
35689 item = this.addText(el);
35691 }else if(el.tagName || el.el){ // element
35692 item = this.addElement(el);
35693 }else if(typeof el == "object"){ // must be menu item config?
35694 item = this.addMenuItem(el);
35701 * Returns this menu's underlying {@link Roo.Element} object
35702 * @return {Roo.Element} The element
35704 getEl : function(){
35712 * Adds a separator bar to the menu
35713 * @return {Roo.menu.Item} The menu item that was added
35715 addSeparator : function(){
35716 return this.addItem(new Roo.menu.Separator());
35720 * Adds an {@link Roo.Element} object to the menu
35721 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35722 * @return {Roo.menu.Item} The menu item that was added
35724 addElement : function(el){
35725 return this.addItem(new Roo.menu.BaseItem(el));
35729 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35730 * @param {Roo.menu.Item} item The menu item to add
35731 * @return {Roo.menu.Item} The menu item that was added
35733 addItem : function(item){
35734 this.items.add(item);
35736 var li = document.createElement("li");
35737 li.className = "x-menu-list-item";
35738 this.ul.dom.appendChild(li);
35739 item.render(li, this);
35740 this.delayAutoWidth();
35746 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35747 * @param {Object} config A MenuItem config object
35748 * @return {Roo.menu.Item} The menu item that was added
35750 addMenuItem : function(config){
35751 if(!(config instanceof Roo.menu.Item)){
35752 if(typeof config.checked == "boolean"){ // must be check menu item config?
35753 config = new Roo.menu.CheckItem(config);
35755 config = new Roo.menu.Item(config);
35758 return this.addItem(config);
35762 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35763 * @param {String} text The text to display in the menu item
35764 * @return {Roo.menu.Item} The menu item that was added
35766 addText : function(text){
35767 return this.addItem(new Roo.menu.TextItem({ text : text }));
35771 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35772 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35773 * @param {Roo.menu.Item} item The menu item to add
35774 * @return {Roo.menu.Item} The menu item that was added
35776 insert : function(index, item){
35777 this.items.insert(index, item);
35779 var li = document.createElement("li");
35780 li.className = "x-menu-list-item";
35781 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35782 item.render(li, this);
35783 this.delayAutoWidth();
35789 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35790 * @param {Roo.menu.Item} item The menu item to remove
35792 remove : function(item){
35793 this.items.removeKey(item.id);
35798 * Removes and destroys all items in the menu
35800 removeAll : function(){
35802 while(f = this.items.first()){
35808 // MenuNav is a private utility class used internally by the Menu
35809 Roo.menu.MenuNav = function(menu){
35810 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35811 this.scope = this.menu = menu;
35814 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35815 doRelay : function(e, h){
35816 var k = e.getKey();
35817 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35818 this.menu.tryActivate(0, 1);
35821 return h.call(this.scope || this, e, this.menu);
35824 up : function(e, m){
35825 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35826 m.tryActivate(m.items.length-1, -1);
35830 down : function(e, m){
35831 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35832 m.tryActivate(0, 1);
35836 right : function(e, m){
35838 m.activeItem.expandMenu(true);
35842 left : function(e, m){
35844 if(m.parentMenu && m.parentMenu.activeItem){
35845 m.parentMenu.activeItem.activate();
35849 enter : function(e, m){
35851 e.stopPropagation();
35852 m.activeItem.onClick(e);
35853 m.fireEvent("click", this, m.activeItem);
35859 * Ext JS Library 1.1.1
35860 * Copyright(c) 2006-2007, Ext JS, LLC.
35862 * Originally Released Under LGPL - original licence link has changed is not relivant.
35865 * <script type="text/javascript">
35869 * @class Roo.menu.MenuMgr
35870 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35873 Roo.menu.MenuMgr = function(){
35874 var menus, active, groups = {}, attached = false, lastShow = new Date();
35876 // private - called when first menu is created
35879 active = new Roo.util.MixedCollection();
35880 Roo.get(document).addKeyListener(27, function(){
35881 if(active.length > 0){
35888 function hideAll(){
35889 if(active && active.length > 0){
35890 var c = active.clone();
35891 c.each(function(m){
35898 function onHide(m){
35900 if(active.length < 1){
35901 Roo.get(document).un("mousedown", onMouseDown);
35907 function onShow(m){
35908 var last = active.last();
35909 lastShow = new Date();
35912 Roo.get(document).on("mousedown", onMouseDown);
35916 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35917 m.parentMenu.activeChild = m;
35918 }else if(last && last.isVisible()){
35919 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35924 function onBeforeHide(m){
35926 m.activeChild.hide();
35928 if(m.autoHideTimer){
35929 clearTimeout(m.autoHideTimer);
35930 delete m.autoHideTimer;
35935 function onBeforeShow(m){
35936 var pm = m.parentMenu;
35937 if(!pm && !m.allowOtherMenus){
35939 }else if(pm && pm.activeChild && active != m){
35940 pm.activeChild.hide();
35945 function onMouseDown(e){
35946 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35952 function onBeforeCheck(mi, state){
35954 var g = groups[mi.group];
35955 for(var i = 0, l = g.length; i < l; i++){
35957 g[i].setChecked(false);
35966 * Hides all menus that are currently visible
35968 hideAll : function(){
35973 register : function(menu){
35977 menus[menu.id] = menu;
35978 menu.on("beforehide", onBeforeHide);
35979 menu.on("hide", onHide);
35980 menu.on("beforeshow", onBeforeShow);
35981 menu.on("show", onShow);
35982 var g = menu.group;
35983 if(g && menu.events["checkchange"]){
35987 groups[g].push(menu);
35988 menu.on("checkchange", onCheck);
35993 * Returns a {@link Roo.menu.Menu} object
35994 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35995 * be used to generate and return a new Menu instance.
35997 get : function(menu){
35998 if(typeof menu == "string"){ // menu id
35999 return menus[menu];
36000 }else if(menu.events){ // menu instance
36002 }else if(typeof menu.length == 'number'){ // array of menu items?
36003 return new Roo.menu.Menu({items:menu});
36004 }else{ // otherwise, must be a config
36005 return new Roo.menu.Menu(menu);
36010 unregister : function(menu){
36011 delete menus[menu.id];
36012 menu.un("beforehide", onBeforeHide);
36013 menu.un("hide", onHide);
36014 menu.un("beforeshow", onBeforeShow);
36015 menu.un("show", onShow);
36016 var g = menu.group;
36017 if(g && menu.events["checkchange"]){
36018 groups[g].remove(menu);
36019 menu.un("checkchange", onCheck);
36024 registerCheckable : function(menuItem){
36025 var g = menuItem.group;
36030 groups[g].push(menuItem);
36031 menuItem.on("beforecheckchange", onBeforeCheck);
36036 unregisterCheckable : function(menuItem){
36037 var g = menuItem.group;
36039 groups[g].remove(menuItem);
36040 menuItem.un("beforecheckchange", onBeforeCheck);
36046 * Ext JS Library 1.1.1
36047 * Copyright(c) 2006-2007, Ext JS, LLC.
36049 * Originally Released Under LGPL - original licence link has changed is not relivant.
36052 * <script type="text/javascript">
36057 * @class Roo.menu.BaseItem
36058 * @extends Roo.Component
36059 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36060 * management and base configuration options shared by all menu components.
36062 * Creates a new BaseItem
36063 * @param {Object} config Configuration options
36065 Roo.menu.BaseItem = function(config){
36066 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36071 * Fires when this item is clicked
36072 * @param {Roo.menu.BaseItem} this
36073 * @param {Roo.EventObject} e
36078 * Fires when this item is activated
36079 * @param {Roo.menu.BaseItem} this
36083 * @event deactivate
36084 * Fires when this item is deactivated
36085 * @param {Roo.menu.BaseItem} this
36091 this.on("click", this.handler, this.scope, true);
36095 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36097 * @cfg {Function} handler
36098 * A function that will handle the click event of this menu item (defaults to undefined)
36101 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36103 canActivate : false,
36106 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36111 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36113 activeClass : "x-menu-item-active",
36115 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36117 hideOnClick : true,
36119 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36124 ctype: "Roo.menu.BaseItem",
36127 actionMode : "container",
36130 render : function(container, parentMenu){
36131 this.parentMenu = parentMenu;
36132 Roo.menu.BaseItem.superclass.render.call(this, container);
36133 this.container.menuItemId = this.id;
36137 onRender : function(container, position){
36138 this.el = Roo.get(this.el);
36139 container.dom.appendChild(this.el.dom);
36143 onClick : function(e){
36144 if(!this.disabled && this.fireEvent("click", this, e) !== false
36145 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36146 this.handleClick(e);
36153 activate : function(){
36157 var li = this.container;
36158 li.addClass(this.activeClass);
36159 this.region = li.getRegion().adjust(2, 2, -2, -2);
36160 this.fireEvent("activate", this);
36165 deactivate : function(){
36166 this.container.removeClass(this.activeClass);
36167 this.fireEvent("deactivate", this);
36171 shouldDeactivate : function(e){
36172 return !this.region || !this.region.contains(e.getPoint());
36176 handleClick : function(e){
36177 if(this.hideOnClick){
36178 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36183 expandMenu : function(autoActivate){
36188 hideMenu : function(){
36193 * Ext JS Library 1.1.1
36194 * Copyright(c) 2006-2007, Ext JS, LLC.
36196 * Originally Released Under LGPL - original licence link has changed is not relivant.
36199 * <script type="text/javascript">
36203 * @class Roo.menu.Adapter
36204 * @extends Roo.menu.BaseItem
36205 * 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.
36206 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36208 * Creates a new Adapter
36209 * @param {Object} config Configuration options
36211 Roo.menu.Adapter = function(component, config){
36212 Roo.menu.Adapter.superclass.constructor.call(this, config);
36213 this.component = component;
36215 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36217 canActivate : true,
36220 onRender : function(container, position){
36221 this.component.render(container);
36222 this.el = this.component.getEl();
36226 activate : function(){
36230 this.component.focus();
36231 this.fireEvent("activate", this);
36236 deactivate : function(){
36237 this.fireEvent("deactivate", this);
36241 disable : function(){
36242 this.component.disable();
36243 Roo.menu.Adapter.superclass.disable.call(this);
36247 enable : function(){
36248 this.component.enable();
36249 Roo.menu.Adapter.superclass.enable.call(this);
36253 * Ext JS Library 1.1.1
36254 * Copyright(c) 2006-2007, Ext JS, LLC.
36256 * Originally Released Under LGPL - original licence link has changed is not relivant.
36259 * <script type="text/javascript">
36263 * @class Roo.menu.TextItem
36264 * @extends Roo.menu.BaseItem
36265 * Adds a static text string to a menu, usually used as either a heading or group separator.
36266 * Note: old style constructor with text is still supported.
36269 * Creates a new TextItem
36270 * @param {Object} cfg Configuration
36272 Roo.menu.TextItem = function(cfg){
36273 if (typeof(cfg) == 'string') {
36276 Roo.apply(this,cfg);
36279 Roo.menu.TextItem.superclass.constructor.call(this);
36282 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36284 * @cfg {Boolean} text Text to show on item.
36289 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36291 hideOnClick : false,
36293 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36295 itemCls : "x-menu-text",
36298 onRender : function(){
36299 var s = document.createElement("span");
36300 s.className = this.itemCls;
36301 s.innerHTML = this.text;
36303 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36307 * Ext JS Library 1.1.1
36308 * Copyright(c) 2006-2007, Ext JS, LLC.
36310 * Originally Released Under LGPL - original licence link has changed is not relivant.
36313 * <script type="text/javascript">
36317 * @class Roo.menu.Separator
36318 * @extends Roo.menu.BaseItem
36319 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36320 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36322 * @param {Object} config Configuration options
36324 Roo.menu.Separator = function(config){
36325 Roo.menu.Separator.superclass.constructor.call(this, config);
36328 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36330 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36332 itemCls : "x-menu-sep",
36334 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36336 hideOnClick : false,
36339 onRender : function(li){
36340 var s = document.createElement("span");
36341 s.className = this.itemCls;
36342 s.innerHTML = " ";
36344 li.addClass("x-menu-sep-li");
36345 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36349 * Ext JS Library 1.1.1
36350 * Copyright(c) 2006-2007, Ext JS, LLC.
36352 * Originally Released Under LGPL - original licence link has changed is not relivant.
36355 * <script type="text/javascript">
36358 * @class Roo.menu.Item
36359 * @extends Roo.menu.BaseItem
36360 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36361 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36362 * activation and click handling.
36364 * Creates a new Item
36365 * @param {Object} config Configuration options
36367 Roo.menu.Item = function(config){
36368 Roo.menu.Item.superclass.constructor.call(this, config);
36370 this.menu = Roo.menu.MenuMgr.get(this.menu);
36373 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36376 * @cfg {String} text
36377 * The text to show on the menu item.
36381 * @cfg {String} HTML to render in menu
36382 * The text to show on the menu item (HTML version).
36386 * @cfg {String} icon
36387 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36391 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36393 itemCls : "x-menu-item",
36395 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36397 canActivate : true,
36399 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36402 // doc'd in BaseItem
36406 ctype: "Roo.menu.Item",
36409 onRender : function(container, position){
36410 var el = document.createElement("a");
36411 el.hideFocus = true;
36412 el.unselectable = "on";
36413 el.href = this.href || "#";
36414 if(this.hrefTarget){
36415 el.target = this.hrefTarget;
36417 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36419 var html = this.html.length ? this.html : String.format('{0}',this.text);
36421 el.innerHTML = String.format(
36422 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36423 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36425 Roo.menu.Item.superclass.onRender.call(this, container, position);
36429 * Sets the text to display in this menu item
36430 * @param {String} text The text to display
36431 * @param {Boolean} isHTML true to indicate text is pure html.
36433 setText : function(text, isHTML){
36441 var html = this.html.length ? this.html : String.format('{0}',this.text);
36443 this.el.update(String.format(
36444 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36445 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36446 this.parentMenu.autoWidth();
36451 handleClick : function(e){
36452 if(!this.href){ // if no link defined, stop the event automatically
36455 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36459 activate : function(autoExpand){
36460 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36470 shouldDeactivate : function(e){
36471 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36472 if(this.menu && this.menu.isVisible()){
36473 return !this.menu.getEl().getRegion().contains(e.getPoint());
36481 deactivate : function(){
36482 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36487 expandMenu : function(autoActivate){
36488 if(!this.disabled && this.menu){
36489 clearTimeout(this.hideTimer);
36490 delete this.hideTimer;
36491 if(!this.menu.isVisible() && !this.showTimer){
36492 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36493 }else if (this.menu.isVisible() && autoActivate){
36494 this.menu.tryActivate(0, 1);
36500 deferExpand : function(autoActivate){
36501 delete this.showTimer;
36502 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36504 this.menu.tryActivate(0, 1);
36509 hideMenu : function(){
36510 clearTimeout(this.showTimer);
36511 delete this.showTimer;
36512 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36513 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36518 deferHide : function(){
36519 delete this.hideTimer;
36524 * Ext JS Library 1.1.1
36525 * Copyright(c) 2006-2007, Ext JS, LLC.
36527 * Originally Released Under LGPL - original licence link has changed is not relivant.
36530 * <script type="text/javascript">
36534 * @class Roo.menu.CheckItem
36535 * @extends Roo.menu.Item
36536 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36538 * Creates a new CheckItem
36539 * @param {Object} config Configuration options
36541 Roo.menu.CheckItem = function(config){
36542 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36545 * @event beforecheckchange
36546 * Fires before the checked value is set, providing an opportunity to cancel if needed
36547 * @param {Roo.menu.CheckItem} this
36548 * @param {Boolean} checked The new checked value that will be set
36550 "beforecheckchange" : true,
36552 * @event checkchange
36553 * Fires after the checked value has been set
36554 * @param {Roo.menu.CheckItem} this
36555 * @param {Boolean} checked The checked value that was set
36557 "checkchange" : true
36559 if(this.checkHandler){
36560 this.on('checkchange', this.checkHandler, this.scope);
36563 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36565 * @cfg {String} group
36566 * All check items with the same group name will automatically be grouped into a single-select
36567 * radio button group (defaults to '')
36570 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36572 itemCls : "x-menu-item x-menu-check-item",
36574 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36576 groupClass : "x-menu-group-item",
36579 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36580 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36581 * initialized with checked = true will be rendered as checked.
36586 ctype: "Roo.menu.CheckItem",
36589 onRender : function(c){
36590 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36592 this.el.addClass(this.groupClass);
36594 Roo.menu.MenuMgr.registerCheckable(this);
36596 this.checked = false;
36597 this.setChecked(true, true);
36602 destroy : function(){
36604 Roo.menu.MenuMgr.unregisterCheckable(this);
36606 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36610 * Set the checked state of this item
36611 * @param {Boolean} checked The new checked value
36612 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36614 setChecked : function(state, suppressEvent){
36615 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36616 if(this.container){
36617 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36619 this.checked = state;
36620 if(suppressEvent !== true){
36621 this.fireEvent("checkchange", this, state);
36627 handleClick : function(e){
36628 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36629 this.setChecked(!this.checked);
36631 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36635 * Ext JS Library 1.1.1
36636 * Copyright(c) 2006-2007, Ext JS, LLC.
36638 * Originally Released Under LGPL - original licence link has changed is not relivant.
36641 * <script type="text/javascript">
36645 * @class Roo.menu.DateItem
36646 * @extends Roo.menu.Adapter
36647 * A menu item that wraps the {@link Roo.DatPicker} component.
36649 * Creates a new DateItem
36650 * @param {Object} config Configuration options
36652 Roo.menu.DateItem = function(config){
36653 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36654 /** The Roo.DatePicker object @type Roo.DatePicker */
36655 this.picker = this.component;
36656 this.addEvents({select: true});
36658 this.picker.on("render", function(picker){
36659 picker.getEl().swallowEvent("click");
36660 picker.container.addClass("x-menu-date-item");
36663 this.picker.on("select", this.onSelect, this);
36666 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36668 onSelect : function(picker, date){
36669 this.fireEvent("select", this, date, picker);
36670 Roo.menu.DateItem.superclass.handleClick.call(this);
36674 * Ext JS Library 1.1.1
36675 * Copyright(c) 2006-2007, Ext JS, LLC.
36677 * Originally Released Under LGPL - original licence link has changed is not relivant.
36680 * <script type="text/javascript">
36684 * @class Roo.menu.ColorItem
36685 * @extends Roo.menu.Adapter
36686 * A menu item that wraps the {@link Roo.ColorPalette} component.
36688 * Creates a new ColorItem
36689 * @param {Object} config Configuration options
36691 Roo.menu.ColorItem = function(config){
36692 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36693 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36694 this.palette = this.component;
36695 this.relayEvents(this.palette, ["select"]);
36696 if(this.selectHandler){
36697 this.on('select', this.selectHandler, this.scope);
36700 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36702 * Ext JS Library 1.1.1
36703 * Copyright(c) 2006-2007, Ext JS, LLC.
36705 * Originally Released Under LGPL - original licence link has changed is not relivant.
36708 * <script type="text/javascript">
36713 * @class Roo.menu.DateMenu
36714 * @extends Roo.menu.Menu
36715 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36717 * Creates a new DateMenu
36718 * @param {Object} config Configuration options
36720 Roo.menu.DateMenu = function(config){
36721 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36723 var di = new Roo.menu.DateItem(config);
36726 * The {@link Roo.DatePicker} instance for this DateMenu
36729 this.picker = di.picker;
36732 * @param {DatePicker} picker
36733 * @param {Date} date
36735 this.relayEvents(di, ["select"]);
36736 this.on('beforeshow', function(){
36738 this.picker.hideMonthPicker(false);
36742 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36746 * Ext JS Library 1.1.1
36747 * Copyright(c) 2006-2007, Ext JS, LLC.
36749 * Originally Released Under LGPL - original licence link has changed is not relivant.
36752 * <script type="text/javascript">
36757 * @class Roo.menu.ColorMenu
36758 * @extends Roo.menu.Menu
36759 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36761 * Creates a new ColorMenu
36762 * @param {Object} config Configuration options
36764 Roo.menu.ColorMenu = function(config){
36765 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36767 var ci = new Roo.menu.ColorItem(config);
36770 * The {@link Roo.ColorPalette} instance for this ColorMenu
36771 * @type ColorPalette
36773 this.palette = ci.palette;
36776 * @param {ColorPalette} palette
36777 * @param {String} color
36779 this.relayEvents(ci, ["select"]);
36781 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36783 * Ext JS Library 1.1.1
36784 * Copyright(c) 2006-2007, Ext JS, LLC.
36786 * Originally Released Under LGPL - original licence link has changed is not relivant.
36789 * <script type="text/javascript">
36793 * @class Roo.form.Field
36794 * @extends Roo.BoxComponent
36795 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36797 * Creates a new Field
36798 * @param {Object} config Configuration options
36800 Roo.form.Field = function(config){
36801 Roo.form.Field.superclass.constructor.call(this, config);
36804 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36806 * @cfg {String} fieldLabel Label to use when rendering a form.
36809 * @cfg {String} qtip Mouse over tip
36813 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36815 invalidClass : "x-form-invalid",
36817 * @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")
36819 invalidText : "The value in this field is invalid",
36821 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36823 focusClass : "x-form-focus",
36825 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36826 automatic validation (defaults to "keyup").
36828 validationEvent : "keyup",
36830 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36832 validateOnBlur : true,
36834 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36836 validationDelay : 250,
36838 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36839 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36841 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36843 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36845 fieldClass : "x-form-field",
36847 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36850 ----------- ----------------------------------------------------------------------
36851 qtip Display a quick tip when the user hovers over the field
36852 title Display a default browser title attribute popup
36853 under Add a block div beneath the field containing the error text
36854 side Add an error icon to the right of the field with a popup on hover
36855 [element id] Add the error text directly to the innerHTML of the specified element
36858 msgTarget : 'qtip',
36860 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36865 * @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.
36870 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36875 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36877 inputType : undefined,
36880 * @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).
36882 tabIndex : undefined,
36885 isFormField : true,
36890 * @property {Roo.Element} fieldEl
36891 * Element Containing the rendered Field (with label etc.)
36894 * @cfg {Mixed} value A value to initialize this field with.
36899 * @cfg {String} name The field's HTML name attribute.
36902 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36906 initComponent : function(){
36907 Roo.form.Field.superclass.initComponent.call(this);
36911 * Fires when this field receives input focus.
36912 * @param {Roo.form.Field} this
36917 * Fires when this field loses input focus.
36918 * @param {Roo.form.Field} this
36922 * @event specialkey
36923 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36924 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36925 * @param {Roo.form.Field} this
36926 * @param {Roo.EventObject} e The event object
36931 * Fires just before the field blurs if the field value has changed.
36932 * @param {Roo.form.Field} this
36933 * @param {Mixed} newValue The new value
36934 * @param {Mixed} oldValue The original value
36939 * Fires after the field has been marked as invalid.
36940 * @param {Roo.form.Field} this
36941 * @param {String} msg The validation message
36946 * Fires after the field has been validated with no errors.
36947 * @param {Roo.form.Field} this
36952 * Fires after the key up
36953 * @param {Roo.form.Field} this
36954 * @param {Roo.EventObject} e The event Object
36961 * Returns the name attribute of the field if available
36962 * @return {String} name The field name
36964 getName: function(){
36965 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36969 onRender : function(ct, position){
36970 Roo.form.Field.superclass.onRender.call(this, ct, position);
36972 var cfg = this.getAutoCreate();
36974 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
36976 if (!cfg.name.length) {
36979 if(this.inputType){
36980 cfg.type = this.inputType;
36982 this.el = ct.createChild(cfg, position);
36984 var type = this.el.dom.type;
36986 if(type == 'password'){
36989 this.el.addClass('x-form-'+type);
36992 this.el.dom.readOnly = true;
36994 if(this.tabIndex !== undefined){
36995 this.el.dom.setAttribute('tabIndex', this.tabIndex);
36998 this.el.addClass([this.fieldClass, this.cls]);
37003 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37004 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37005 * @return {Roo.form.Field} this
37007 applyTo : function(target){
37008 this.allowDomMove = false;
37009 this.el = Roo.get(target);
37010 this.render(this.el.dom.parentNode);
37015 initValue : function(){
37016 if(this.value !== undefined){
37017 this.setValue(this.value);
37018 }else if(this.el.dom.value.length > 0){
37019 this.setValue(this.el.dom.value);
37024 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37026 isDirty : function() {
37027 if(this.disabled) {
37030 return String(this.getValue()) !== String(this.originalValue);
37034 afterRender : function(){
37035 Roo.form.Field.superclass.afterRender.call(this);
37040 fireKey : function(e){
37041 //Roo.log('field ' + e.getKey());
37042 if(e.isNavKeyPress()){
37043 this.fireEvent("specialkey", this, e);
37048 * Resets the current field value to the originally loaded value and clears any validation messages
37050 reset : function(){
37051 this.setValue(this.resetValue);
37052 this.clearInvalid();
37056 initEvents : function(){
37057 // safari killled keypress - so keydown is now used..
37058 this.el.on("keydown" , this.fireKey, this);
37059 this.el.on("focus", this.onFocus, this);
37060 this.el.on("blur", this.onBlur, this);
37061 this.el.relayEvent('keyup', this);
37063 // reference to original value for reset
37064 this.originalValue = this.getValue();
37065 this.resetValue = this.getValue();
37069 onFocus : function(){
37070 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37071 this.el.addClass(this.focusClass);
37073 if(!this.hasFocus){
37074 this.hasFocus = true;
37075 this.startValue = this.getValue();
37076 this.fireEvent("focus", this);
37080 beforeBlur : Roo.emptyFn,
37083 onBlur : function(){
37085 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37086 this.el.removeClass(this.focusClass);
37088 this.hasFocus = false;
37089 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37092 var v = this.getValue();
37093 if(String(v) !== String(this.startValue)){
37094 this.fireEvent('change', this, v, this.startValue);
37096 this.fireEvent("blur", this);
37100 * Returns whether or not the field value is currently valid
37101 * @param {Boolean} preventMark True to disable marking the field invalid
37102 * @return {Boolean} True if the value is valid, else false
37104 isValid : function(preventMark){
37108 var restore = this.preventMark;
37109 this.preventMark = preventMark === true;
37110 var v = this.validateValue(this.processValue(this.getRawValue()));
37111 this.preventMark = restore;
37116 * Validates the field value
37117 * @return {Boolean} True if the value is valid, else false
37119 validate : function(){
37120 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37121 this.clearInvalid();
37127 processValue : function(value){
37132 // Subclasses should provide the validation implementation by overriding this
37133 validateValue : function(value){
37138 * Mark this field as invalid
37139 * @param {String} msg The validation message
37141 markInvalid : function(msg){
37142 if(!this.rendered || this.preventMark){ // not rendered
37146 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37148 obj.el.addClass(this.invalidClass);
37149 msg = msg || this.invalidText;
37150 switch(this.msgTarget){
37152 obj.el.dom.qtip = msg;
37153 obj.el.dom.qclass = 'x-form-invalid-tip';
37154 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37155 Roo.QuickTips.enable();
37159 this.el.dom.title = msg;
37163 var elp = this.el.findParent('.x-form-element', 5, true);
37164 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37165 this.errorEl.setWidth(elp.getWidth(true)-20);
37167 this.errorEl.update(msg);
37168 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37171 if(!this.errorIcon){
37172 var elp = this.el.findParent('.x-form-element', 5, true);
37173 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37175 this.alignErrorIcon();
37176 this.errorIcon.dom.qtip = msg;
37177 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37178 this.errorIcon.show();
37179 this.on('resize', this.alignErrorIcon, this);
37182 var t = Roo.getDom(this.msgTarget);
37184 t.style.display = this.msgDisplay;
37187 this.fireEvent('invalid', this, msg);
37191 alignErrorIcon : function(){
37192 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37196 * Clear any invalid styles/messages for this field
37198 clearInvalid : function(){
37199 if(!this.rendered || this.preventMark){ // not rendered
37202 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37204 obj.el.removeClass(this.invalidClass);
37205 switch(this.msgTarget){
37207 obj.el.dom.qtip = '';
37210 this.el.dom.title = '';
37214 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37218 if(this.errorIcon){
37219 this.errorIcon.dom.qtip = '';
37220 this.errorIcon.hide();
37221 this.un('resize', this.alignErrorIcon, this);
37225 var t = Roo.getDom(this.msgTarget);
37227 t.style.display = 'none';
37230 this.fireEvent('valid', this);
37234 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37235 * @return {Mixed} value The field value
37237 getRawValue : function(){
37238 var v = this.el.getValue();
37244 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37245 * @return {Mixed} value The field value
37247 getValue : function(){
37248 var v = this.el.getValue();
37254 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37255 * @param {Mixed} value The value to set
37257 setRawValue : function(v){
37258 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37262 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37263 * @param {Mixed} value The value to set
37265 setValue : function(v){
37268 this.el.dom.value = (v === null || v === undefined ? '' : v);
37273 adjustSize : function(w, h){
37274 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37275 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37279 adjustWidth : function(tag, w){
37280 tag = tag.toLowerCase();
37281 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37282 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37283 if(tag == 'input'){
37286 if(tag == 'textarea'){
37289 }else if(Roo.isOpera){
37290 if(tag == 'input'){
37293 if(tag == 'textarea'){
37303 // anything other than normal should be considered experimental
37304 Roo.form.Field.msgFx = {
37306 show: function(msgEl, f){
37307 msgEl.setDisplayed('block');
37310 hide : function(msgEl, f){
37311 msgEl.setDisplayed(false).update('');
37316 show: function(msgEl, f){
37317 msgEl.slideIn('t', {stopFx:true});
37320 hide : function(msgEl, f){
37321 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37326 show: function(msgEl, f){
37327 msgEl.fixDisplay();
37328 msgEl.alignTo(f.el, 'tl-tr');
37329 msgEl.slideIn('l', {stopFx:true});
37332 hide : function(msgEl, f){
37333 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37338 * Ext JS Library 1.1.1
37339 * Copyright(c) 2006-2007, Ext JS, LLC.
37341 * Originally Released Under LGPL - original licence link has changed is not relivant.
37344 * <script type="text/javascript">
37349 * @class Roo.form.TextField
37350 * @extends Roo.form.Field
37351 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37352 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37354 * Creates a new TextField
37355 * @param {Object} config Configuration options
37357 Roo.form.TextField = function(config){
37358 Roo.form.TextField.superclass.constructor.call(this, config);
37362 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37363 * according to the default logic, but this event provides a hook for the developer to apply additional
37364 * logic at runtime to resize the field if needed.
37365 * @param {Roo.form.Field} this This text field
37366 * @param {Number} width The new field width
37372 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37374 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37378 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37382 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37386 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37390 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37394 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37396 disableKeyFilter : false,
37398 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37402 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37406 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37408 maxLength : Number.MAX_VALUE,
37410 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37412 minLengthText : "The minimum length for this field is {0}",
37414 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37416 maxLengthText : "The maximum length for this field is {0}",
37418 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37420 selectOnFocus : false,
37422 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37424 blankText : "This field is required",
37426 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37427 * If available, this function will be called only after the basic validators all return true, and will be passed the
37428 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37432 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37433 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37434 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37438 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37442 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37448 initEvents : function()
37450 if (this.emptyText) {
37451 this.el.attr('placeholder', this.emptyText);
37454 Roo.form.TextField.superclass.initEvents.call(this);
37455 if(this.validationEvent == 'keyup'){
37456 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37457 this.el.on('keyup', this.filterValidation, this);
37459 else if(this.validationEvent !== false){
37460 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37463 if(this.selectOnFocus){
37464 this.on("focus", this.preFocus, this);
37467 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37468 this.el.on("keypress", this.filterKeys, this);
37471 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37472 this.el.on("click", this.autoSize, this);
37474 if(this.el.is('input[type=password]') && Roo.isSafari){
37475 this.el.on('keydown', this.SafariOnKeyDown, this);
37479 processValue : function(value){
37480 if(this.stripCharsRe){
37481 var newValue = value.replace(this.stripCharsRe, '');
37482 if(newValue !== value){
37483 this.setRawValue(newValue);
37490 filterValidation : function(e){
37491 if(!e.isNavKeyPress()){
37492 this.validationTask.delay(this.validationDelay);
37497 onKeyUp : function(e){
37498 if(!e.isNavKeyPress()){
37504 * Resets the current field value to the originally-loaded value and clears any validation messages.
37507 reset : function(){
37508 Roo.form.TextField.superclass.reset.call(this);
37514 preFocus : function(){
37516 if(this.selectOnFocus){
37517 this.el.dom.select();
37523 filterKeys : function(e){
37524 var k = e.getKey();
37525 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37528 var c = e.getCharCode(), cc = String.fromCharCode(c);
37529 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37532 if(!this.maskRe.test(cc)){
37537 setValue : function(v){
37539 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37545 * Validates a value according to the field's validation rules and marks the field as invalid
37546 * if the validation fails
37547 * @param {Mixed} value The value to validate
37548 * @return {Boolean} True if the value is valid, else false
37550 validateValue : function(value){
37551 if(value.length < 1) { // if it's blank
37552 if(this.allowBlank){
37553 this.clearInvalid();
37556 this.markInvalid(this.blankText);
37560 if(value.length < this.minLength){
37561 this.markInvalid(String.format(this.minLengthText, this.minLength));
37564 if(value.length > this.maxLength){
37565 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37569 var vt = Roo.form.VTypes;
37570 if(!vt[this.vtype](value, this)){
37571 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37575 if(typeof this.validator == "function"){
37576 var msg = this.validator(value);
37578 this.markInvalid(msg);
37582 if(this.regex && !this.regex.test(value)){
37583 this.markInvalid(this.regexText);
37590 * Selects text in this field
37591 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37592 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37594 selectText : function(start, end){
37595 var v = this.getRawValue();
37597 start = start === undefined ? 0 : start;
37598 end = end === undefined ? v.length : end;
37599 var d = this.el.dom;
37600 if(d.setSelectionRange){
37601 d.setSelectionRange(start, end);
37602 }else if(d.createTextRange){
37603 var range = d.createTextRange();
37604 range.moveStart("character", start);
37605 range.moveEnd("character", v.length-end);
37612 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37613 * This only takes effect if grow = true, and fires the autosize event.
37615 autoSize : function(){
37616 if(!this.grow || !this.rendered){
37620 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37623 var v = el.dom.value;
37624 var d = document.createElement('div');
37625 d.appendChild(document.createTextNode(v));
37629 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37630 this.el.setWidth(w);
37631 this.fireEvent("autosize", this, w);
37635 SafariOnKeyDown : function(event)
37637 // this is a workaround for a password hang bug on chrome/ webkit.
37639 var isSelectAll = false;
37641 if(this.el.dom.selectionEnd > 0){
37642 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37644 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37645 event.preventDefault();
37650 if(isSelectAll){ // backspace and delete key
37652 event.preventDefault();
37653 // this is very hacky as keydown always get's upper case.
37655 var cc = String.fromCharCode(event.getCharCode());
37656 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37664 * Ext JS Library 1.1.1
37665 * Copyright(c) 2006-2007, Ext JS, LLC.
37667 * Originally Released Under LGPL - original licence link has changed is not relivant.
37670 * <script type="text/javascript">
37674 * @class Roo.form.Hidden
37675 * @extends Roo.form.TextField
37676 * Simple Hidden element used on forms
37678 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37681 * Creates a new Hidden form element.
37682 * @param {Object} config Configuration options
37687 // easy hidden field...
37688 Roo.form.Hidden = function(config){
37689 Roo.form.Hidden.superclass.constructor.call(this, config);
37692 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37694 inputType: 'hidden',
37697 labelSeparator: '',
37699 itemCls : 'x-form-item-display-none'
37707 * Ext JS Library 1.1.1
37708 * Copyright(c) 2006-2007, Ext JS, LLC.
37710 * Originally Released Under LGPL - original licence link has changed is not relivant.
37713 * <script type="text/javascript">
37717 * @class Roo.form.TriggerField
37718 * @extends Roo.form.TextField
37719 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37720 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37721 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37722 * for which you can provide a custom implementation. For example:
37724 var trigger = new Roo.form.TriggerField();
37725 trigger.onTriggerClick = myTriggerFn;
37726 trigger.applyTo('my-field');
37729 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37730 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37731 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37732 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37734 * Create a new TriggerField.
37735 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37736 * to the base TextField)
37738 Roo.form.TriggerField = function(config){
37739 this.mimicing = false;
37740 Roo.form.TriggerField.superclass.constructor.call(this, config);
37743 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37745 * @cfg {String} triggerClass A CSS class to apply to the trigger
37748 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37749 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37751 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37753 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37757 /** @cfg {Boolean} grow @hide */
37758 /** @cfg {Number} growMin @hide */
37759 /** @cfg {Number} growMax @hide */
37765 autoSize: Roo.emptyFn,
37769 deferHeight : true,
37772 actionMode : 'wrap',
37774 onResize : function(w, h){
37775 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37776 if(typeof w == 'number'){
37777 var x = w - this.trigger.getWidth();
37778 this.el.setWidth(this.adjustWidth('input', x));
37779 this.trigger.setStyle('left', x+'px');
37784 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37787 getResizeEl : function(){
37792 getPositionEl : function(){
37797 alignErrorIcon : function(){
37798 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37802 onRender : function(ct, position){
37803 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37804 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37805 this.trigger = this.wrap.createChild(this.triggerConfig ||
37806 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37807 if(this.hideTrigger){
37808 this.trigger.setDisplayed(false);
37810 this.initTrigger();
37812 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37817 initTrigger : function(){
37818 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37819 this.trigger.addClassOnOver('x-form-trigger-over');
37820 this.trigger.addClassOnClick('x-form-trigger-click');
37824 onDestroy : function(){
37826 this.trigger.removeAllListeners();
37827 this.trigger.remove();
37830 this.wrap.remove();
37832 Roo.form.TriggerField.superclass.onDestroy.call(this);
37836 onFocus : function(){
37837 Roo.form.TriggerField.superclass.onFocus.call(this);
37838 if(!this.mimicing){
37839 this.wrap.addClass('x-trigger-wrap-focus');
37840 this.mimicing = true;
37841 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37842 if(this.monitorTab){
37843 this.el.on("keydown", this.checkTab, this);
37849 checkTab : function(e){
37850 if(e.getKey() == e.TAB){
37851 this.triggerBlur();
37856 onBlur : function(){
37861 mimicBlur : function(e, t){
37862 if(!this.wrap.contains(t) && this.validateBlur()){
37863 this.triggerBlur();
37868 triggerBlur : function(){
37869 this.mimicing = false;
37870 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37871 if(this.monitorTab){
37872 this.el.un("keydown", this.checkTab, this);
37874 this.wrap.removeClass('x-trigger-wrap-focus');
37875 Roo.form.TriggerField.superclass.onBlur.call(this);
37879 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37880 validateBlur : function(e, t){
37885 onDisable : function(){
37886 Roo.form.TriggerField.superclass.onDisable.call(this);
37888 this.wrap.addClass('x-item-disabled');
37893 onEnable : function(){
37894 Roo.form.TriggerField.superclass.onEnable.call(this);
37896 this.wrap.removeClass('x-item-disabled');
37901 onShow : function(){
37902 var ae = this.getActionEl();
37905 ae.dom.style.display = '';
37906 ae.dom.style.visibility = 'visible';
37912 onHide : function(){
37913 var ae = this.getActionEl();
37914 ae.dom.style.display = 'none';
37918 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37919 * by an implementing function.
37921 * @param {EventObject} e
37923 onTriggerClick : Roo.emptyFn
37926 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37927 // to be extended by an implementing class. For an example of implementing this class, see the custom
37928 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37929 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37930 initComponent : function(){
37931 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37933 this.triggerConfig = {
37934 tag:'span', cls:'x-form-twin-triggers', cn:[
37935 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37936 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37940 getTrigger : function(index){
37941 return this.triggers[index];
37944 initTrigger : function(){
37945 var ts = this.trigger.select('.x-form-trigger', true);
37946 this.wrap.setStyle('overflow', 'hidden');
37947 var triggerField = this;
37948 ts.each(function(t, all, index){
37949 t.hide = function(){
37950 var w = triggerField.wrap.getWidth();
37951 this.dom.style.display = 'none';
37952 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37954 t.show = function(){
37955 var w = triggerField.wrap.getWidth();
37956 this.dom.style.display = '';
37957 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37959 var triggerIndex = 'Trigger'+(index+1);
37961 if(this['hide'+triggerIndex]){
37962 t.dom.style.display = 'none';
37964 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37965 t.addClassOnOver('x-form-trigger-over');
37966 t.addClassOnClick('x-form-trigger-click');
37968 this.triggers = ts.elements;
37971 onTrigger1Click : Roo.emptyFn,
37972 onTrigger2Click : Roo.emptyFn
37975 * Ext JS Library 1.1.1
37976 * Copyright(c) 2006-2007, Ext JS, LLC.
37978 * Originally Released Under LGPL - original licence link has changed is not relivant.
37981 * <script type="text/javascript">
37985 * @class Roo.form.TextArea
37986 * @extends Roo.form.TextField
37987 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37988 * support for auto-sizing.
37990 * Creates a new TextArea
37991 * @param {Object} config Configuration options
37993 Roo.form.TextArea = function(config){
37994 Roo.form.TextArea.superclass.constructor.call(this, config);
37995 // these are provided exchanges for backwards compat
37996 // minHeight/maxHeight were replaced by growMin/growMax to be
37997 // compatible with TextField growing config values
37998 if(this.minHeight !== undefined){
37999 this.growMin = this.minHeight;
38001 if(this.maxHeight !== undefined){
38002 this.growMax = this.maxHeight;
38006 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38008 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38012 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38016 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38017 * in the field (equivalent to setting overflow: hidden, defaults to false)
38019 preventScrollbars: false,
38021 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38022 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38026 onRender : function(ct, position){
38028 this.defaultAutoCreate = {
38030 style:"width:300px;height:60px;",
38031 autocomplete: "off"
38034 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38036 this.textSizeEl = Roo.DomHelper.append(document.body, {
38037 tag: "pre", cls: "x-form-grow-sizer"
38039 if(this.preventScrollbars){
38040 this.el.setStyle("overflow", "hidden");
38042 this.el.setHeight(this.growMin);
38046 onDestroy : function(){
38047 if(this.textSizeEl){
38048 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38050 Roo.form.TextArea.superclass.onDestroy.call(this);
38054 onKeyUp : function(e){
38055 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38061 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38062 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38064 autoSize : function(){
38065 if(!this.grow || !this.textSizeEl){
38069 var v = el.dom.value;
38070 var ts = this.textSizeEl;
38073 ts.appendChild(document.createTextNode(v));
38076 Roo.fly(ts).setWidth(this.el.getWidth());
38078 v = "  ";
38081 v = v.replace(/\n/g, '<p> </p>');
38083 v += " \n ";
38086 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38087 if(h != this.lastHeight){
38088 this.lastHeight = h;
38089 this.el.setHeight(h);
38090 this.fireEvent("autosize", this, h);
38095 * Ext JS Library 1.1.1
38096 * Copyright(c) 2006-2007, Ext JS, LLC.
38098 * Originally Released Under LGPL - original licence link has changed is not relivant.
38101 * <script type="text/javascript">
38106 * @class Roo.form.NumberField
38107 * @extends Roo.form.TextField
38108 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38110 * Creates a new NumberField
38111 * @param {Object} config Configuration options
38113 Roo.form.NumberField = function(config){
38114 Roo.form.NumberField.superclass.constructor.call(this, config);
38117 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38119 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38121 fieldClass: "x-form-field x-form-num-field",
38123 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38125 allowDecimals : true,
38127 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38129 decimalSeparator : ".",
38131 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38133 decimalPrecision : 2,
38135 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38137 allowNegative : true,
38139 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38141 minValue : Number.NEGATIVE_INFINITY,
38143 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38145 maxValue : Number.MAX_VALUE,
38147 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38149 minText : "The minimum value for this field is {0}",
38151 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38153 maxText : "The maximum value for this field is {0}",
38155 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38156 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38158 nanText : "{0} is not a valid number",
38161 initEvents : function(){
38162 Roo.form.NumberField.superclass.initEvents.call(this);
38163 var allowed = "0123456789";
38164 if(this.allowDecimals){
38165 allowed += this.decimalSeparator;
38167 if(this.allowNegative){
38170 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38171 var keyPress = function(e){
38172 var k = e.getKey();
38173 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38176 var c = e.getCharCode();
38177 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38181 this.el.on("keypress", keyPress, this);
38185 validateValue : function(value){
38186 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38189 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38192 var num = this.parseValue(value);
38194 this.markInvalid(String.format(this.nanText, value));
38197 if(num < this.minValue){
38198 this.markInvalid(String.format(this.minText, this.minValue));
38201 if(num > this.maxValue){
38202 this.markInvalid(String.format(this.maxText, this.maxValue));
38208 getValue : function(){
38209 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38213 parseValue : function(value){
38214 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38215 return isNaN(value) ? '' : value;
38219 fixPrecision : function(value){
38220 var nan = isNaN(value);
38221 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38222 return nan ? '' : value;
38224 return parseFloat(value).toFixed(this.decimalPrecision);
38227 setValue : function(v){
38228 v = this.fixPrecision(v);
38229 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38233 decimalPrecisionFcn : function(v){
38234 return Math.floor(v);
38237 beforeBlur : function(){
38238 var v = this.parseValue(this.getRawValue());
38245 * Ext JS Library 1.1.1
38246 * Copyright(c) 2006-2007, Ext JS, LLC.
38248 * Originally Released Under LGPL - original licence link has changed is not relivant.
38251 * <script type="text/javascript">
38255 * @class Roo.form.DateField
38256 * @extends Roo.form.TriggerField
38257 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38259 * Create a new DateField
38260 * @param {Object} config
38262 Roo.form.DateField = function(config){
38263 Roo.form.DateField.superclass.constructor.call(this, config);
38269 * Fires when a date is selected
38270 * @param {Roo.form.DateField} combo This combo box
38271 * @param {Date} date The date selected
38278 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38279 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38280 this.ddMatch = null;
38281 if(this.disabledDates){
38282 var dd = this.disabledDates;
38284 for(var i = 0; i < dd.length; i++){
38286 if(i != dd.length-1) re += "|";
38288 this.ddMatch = new RegExp(re + ")");
38292 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38294 * @cfg {String} format
38295 * The default date format string which can be overriden for localization support. The format must be
38296 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38300 * @cfg {String} altFormats
38301 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38302 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38304 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38306 * @cfg {Array} disabledDays
38307 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38309 disabledDays : null,
38311 * @cfg {String} disabledDaysText
38312 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38314 disabledDaysText : "Disabled",
38316 * @cfg {Array} disabledDates
38317 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38318 * expression so they are very powerful. Some examples:
38320 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38321 * <li>["03/08", "09/16"] would disable those days for every year</li>
38322 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38323 * <li>["03/../2006"] would disable every day in March 2006</li>
38324 * <li>["^03"] would disable every day in every March</li>
38326 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38327 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38329 disabledDates : null,
38331 * @cfg {String} disabledDatesText
38332 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38334 disabledDatesText : "Disabled",
38336 * @cfg {Date/String} minValue
38337 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38338 * valid format (defaults to null).
38342 * @cfg {Date/String} maxValue
38343 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38344 * valid format (defaults to null).
38348 * @cfg {String} minText
38349 * The error text to display when the date in the cell is before minValue (defaults to
38350 * 'The date in this field must be after {minValue}').
38352 minText : "The date in this field must be equal to or after {0}",
38354 * @cfg {String} maxText
38355 * The error text to display when the date in the cell is after maxValue (defaults to
38356 * 'The date in this field must be before {maxValue}').
38358 maxText : "The date in this field must be equal to or before {0}",
38360 * @cfg {String} invalidText
38361 * The error text to display when the date in the field is invalid (defaults to
38362 * '{value} is not a valid date - it must be in the format {format}').
38364 invalidText : "{0} is not a valid date - it must be in the format {1}",
38366 * @cfg {String} triggerClass
38367 * An additional CSS class used to style the trigger button. The trigger will always get the
38368 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38369 * which displays a calendar icon).
38371 triggerClass : 'x-form-date-trigger',
38375 * @cfg {Boolean} useIso
38376 * if enabled, then the date field will use a hidden field to store the
38377 * real value as iso formated date. default (false)
38381 * @cfg {String/Object} autoCreate
38382 * A DomHelper element spec, or true for a default element spec (defaults to
38383 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38386 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38389 hiddenField: false,
38391 onRender : function(ct, position)
38393 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38395 //this.el.dom.removeAttribute('name');
38396 Roo.log("Changing name?");
38397 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38398 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38400 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38401 // prevent input submission
38402 this.hiddenName = this.name;
38409 validateValue : function(value)
38411 value = this.formatDate(value);
38412 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38413 Roo.log('super failed');
38416 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38419 var svalue = value;
38420 value = this.parseDate(value);
38422 Roo.log('parse date failed' + svalue);
38423 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38426 var time = value.getTime();
38427 if(this.minValue && time < this.minValue.getTime()){
38428 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38431 if(this.maxValue && time > this.maxValue.getTime()){
38432 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38435 if(this.disabledDays){
38436 var day = value.getDay();
38437 for(var i = 0; i < this.disabledDays.length; i++) {
38438 if(day === this.disabledDays[i]){
38439 this.markInvalid(this.disabledDaysText);
38444 var fvalue = this.formatDate(value);
38445 if(this.ddMatch && this.ddMatch.test(fvalue)){
38446 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38453 // Provides logic to override the default TriggerField.validateBlur which just returns true
38454 validateBlur : function(){
38455 return !this.menu || !this.menu.isVisible();
38458 getName: function()
38460 // returns hidden if it's set..
38461 if (!this.rendered) {return ''};
38462 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38467 * Returns the current date value of the date field.
38468 * @return {Date} The date value
38470 getValue : function(){
38472 return this.hiddenField ?
38473 this.hiddenField.value :
38474 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38478 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38479 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38480 * (the default format used is "m/d/y").
38483 //All of these calls set the same date value (May 4, 2006)
38485 //Pass a date object:
38486 var dt = new Date('5/4/06');
38487 dateField.setValue(dt);
38489 //Pass a date string (default format):
38490 dateField.setValue('5/4/06');
38492 //Pass a date string (custom format):
38493 dateField.format = 'Y-m-d';
38494 dateField.setValue('2006-5-4');
38496 * @param {String/Date} date The date or valid date string
38498 setValue : function(date){
38499 if (this.hiddenField) {
38500 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38502 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38503 // make sure the value field is always stored as a date..
38504 this.value = this.parseDate(date);
38510 parseDate : function(value){
38511 if(!value || value instanceof Date){
38514 var v = Date.parseDate(value, this.format);
38515 if (!v && this.useIso) {
38516 v = Date.parseDate(value, 'Y-m-d');
38518 if(!v && this.altFormats){
38519 if(!this.altFormatsArray){
38520 this.altFormatsArray = this.altFormats.split("|");
38522 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38523 v = Date.parseDate(value, this.altFormatsArray[i]);
38530 formatDate : function(date, fmt){
38531 return (!date || !(date instanceof Date)) ?
38532 date : date.dateFormat(fmt || this.format);
38537 select: function(m, d){
38540 this.fireEvent('select', this, d);
38542 show : function(){ // retain focus styling
38546 this.focus.defer(10, this);
38547 var ml = this.menuListeners;
38548 this.menu.un("select", ml.select, this);
38549 this.menu.un("show", ml.show, this);
38550 this.menu.un("hide", ml.hide, this);
38555 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38556 onTriggerClick : function(){
38560 if(this.menu == null){
38561 this.menu = new Roo.menu.DateMenu();
38563 Roo.apply(this.menu.picker, {
38564 showClear: this.allowBlank,
38565 minDate : this.minValue,
38566 maxDate : this.maxValue,
38567 disabledDatesRE : this.ddMatch,
38568 disabledDatesText : this.disabledDatesText,
38569 disabledDays : this.disabledDays,
38570 disabledDaysText : this.disabledDaysText,
38571 format : this.useIso ? 'Y-m-d' : this.format,
38572 minText : String.format(this.minText, this.formatDate(this.minValue)),
38573 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38575 this.menu.on(Roo.apply({}, this.menuListeners, {
38578 this.menu.picker.setValue(this.getValue() || new Date());
38579 this.menu.show(this.el, "tl-bl?");
38582 beforeBlur : function(){
38583 var v = this.parseDate(this.getRawValue());
38593 isDirty : function() {
38594 if(this.disabled) {
38598 if(typeof(this.startValue) === 'undefined'){
38602 return String(this.getValue()) !== String(this.startValue);
38607 * Ext JS Library 1.1.1
38608 * Copyright(c) 2006-2007, Ext JS, LLC.
38610 * Originally Released Under LGPL - original licence link has changed is not relivant.
38613 * <script type="text/javascript">
38617 * @class Roo.form.MonthField
38618 * @extends Roo.form.TriggerField
38619 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38621 * Create a new MonthField
38622 * @param {Object} config
38624 Roo.form.MonthField = function(config){
38626 Roo.form.MonthField.superclass.constructor.call(this, config);
38632 * Fires when a date is selected
38633 * @param {Roo.form.MonthFieeld} combo This combo box
38634 * @param {Date} date The date selected
38641 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38642 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38643 this.ddMatch = null;
38644 if(this.disabledDates){
38645 var dd = this.disabledDates;
38647 for(var i = 0; i < dd.length; i++){
38649 if(i != dd.length-1) re += "|";
38651 this.ddMatch = new RegExp(re + ")");
38655 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38657 * @cfg {String} format
38658 * The default date format string which can be overriden for localization support. The format must be
38659 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38663 * @cfg {String} altFormats
38664 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38665 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38667 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38669 * @cfg {Array} disabledDays
38670 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38672 disabledDays : [0,1,2,3,4,5,6],
38674 * @cfg {String} disabledDaysText
38675 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38677 disabledDaysText : "Disabled",
38679 * @cfg {Array} disabledDates
38680 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38681 * expression so they are very powerful. Some examples:
38683 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38684 * <li>["03/08", "09/16"] would disable those days for every year</li>
38685 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38686 * <li>["03/../2006"] would disable every day in March 2006</li>
38687 * <li>["^03"] would disable every day in every March</li>
38689 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38690 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38692 disabledDates : null,
38694 * @cfg {String} disabledDatesText
38695 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38697 disabledDatesText : "Disabled",
38699 * @cfg {Date/String} minValue
38700 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38701 * valid format (defaults to null).
38705 * @cfg {Date/String} maxValue
38706 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38707 * valid format (defaults to null).
38711 * @cfg {String} minText
38712 * The error text to display when the date in the cell is before minValue (defaults to
38713 * 'The date in this field must be after {minValue}').
38715 minText : "The date in this field must be equal to or after {0}",
38717 * @cfg {String} maxTextf
38718 * The error text to display when the date in the cell is after maxValue (defaults to
38719 * 'The date in this field must be before {maxValue}').
38721 maxText : "The date in this field must be equal to or before {0}",
38723 * @cfg {String} invalidText
38724 * The error text to display when the date in the field is invalid (defaults to
38725 * '{value} is not a valid date - it must be in the format {format}').
38727 invalidText : "{0} is not a valid date - it must be in the format {1}",
38729 * @cfg {String} triggerClass
38730 * An additional CSS class used to style the trigger button. The trigger will always get the
38731 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38732 * which displays a calendar icon).
38734 triggerClass : 'x-form-date-trigger',
38738 * @cfg {Boolean} useIso
38739 * if enabled, then the date field will use a hidden field to store the
38740 * real value as iso formated date. default (true)
38744 * @cfg {String/Object} autoCreate
38745 * A DomHelper element spec, or true for a default element spec (defaults to
38746 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38749 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38752 hiddenField: false,
38754 hideMonthPicker : false,
38756 onRender : function(ct, position)
38758 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38760 this.el.dom.removeAttribute('name');
38761 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38763 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38764 // prevent input submission
38765 this.hiddenName = this.name;
38772 validateValue : function(value)
38774 value = this.formatDate(value);
38775 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38778 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38781 var svalue = value;
38782 value = this.parseDate(value);
38784 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38787 var time = value.getTime();
38788 if(this.minValue && time < this.minValue.getTime()){
38789 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38792 if(this.maxValue && time > this.maxValue.getTime()){
38793 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38796 /*if(this.disabledDays){
38797 var day = value.getDay();
38798 for(var i = 0; i < this.disabledDays.length; i++) {
38799 if(day === this.disabledDays[i]){
38800 this.markInvalid(this.disabledDaysText);
38806 var fvalue = this.formatDate(value);
38807 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38808 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38816 // Provides logic to override the default TriggerField.validateBlur which just returns true
38817 validateBlur : function(){
38818 return !this.menu || !this.menu.isVisible();
38822 * Returns the current date value of the date field.
38823 * @return {Date} The date value
38825 getValue : function(){
38829 return this.hiddenField ?
38830 this.hiddenField.value :
38831 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38835 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38836 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38837 * (the default format used is "m/d/y").
38840 //All of these calls set the same date value (May 4, 2006)
38842 //Pass a date object:
38843 var dt = new Date('5/4/06');
38844 monthField.setValue(dt);
38846 //Pass a date string (default format):
38847 monthField.setValue('5/4/06');
38849 //Pass a date string (custom format):
38850 monthField.format = 'Y-m-d';
38851 monthField.setValue('2006-5-4');
38853 * @param {String/Date} date The date or valid date string
38855 setValue : function(date){
38856 Roo.log('month setValue' + date);
38857 // can only be first of month..
38859 var val = this.parseDate(date);
38861 if (this.hiddenField) {
38862 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38864 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38865 this.value = this.parseDate(date);
38869 parseDate : function(value){
38870 if(!value || value instanceof Date){
38871 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38874 var v = Date.parseDate(value, this.format);
38875 if (!v && this.useIso) {
38876 v = Date.parseDate(value, 'Y-m-d');
38880 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38884 if(!v && this.altFormats){
38885 if(!this.altFormatsArray){
38886 this.altFormatsArray = this.altFormats.split("|");
38888 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38889 v = Date.parseDate(value, this.altFormatsArray[i]);
38896 formatDate : function(date, fmt){
38897 return (!date || !(date instanceof Date)) ?
38898 date : date.dateFormat(fmt || this.format);
38903 select: function(m, d){
38905 this.fireEvent('select', this, d);
38907 show : function(){ // retain focus styling
38911 this.focus.defer(10, this);
38912 var ml = this.menuListeners;
38913 this.menu.un("select", ml.select, this);
38914 this.menu.un("show", ml.show, this);
38915 this.menu.un("hide", ml.hide, this);
38919 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38920 onTriggerClick : function(){
38924 if(this.menu == null){
38925 this.menu = new Roo.menu.DateMenu();
38929 Roo.apply(this.menu.picker, {
38931 showClear: this.allowBlank,
38932 minDate : this.minValue,
38933 maxDate : this.maxValue,
38934 disabledDatesRE : this.ddMatch,
38935 disabledDatesText : this.disabledDatesText,
38937 format : this.useIso ? 'Y-m-d' : this.format,
38938 minText : String.format(this.minText, this.formatDate(this.minValue)),
38939 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38942 this.menu.on(Roo.apply({}, this.menuListeners, {
38950 // hide month picker get's called when we called by 'before hide';
38952 var ignorehide = true;
38953 p.hideMonthPicker = function(disableAnim){
38957 if(this.monthPicker){
38958 Roo.log("hideMonthPicker called");
38959 if(disableAnim === true){
38960 this.monthPicker.hide();
38962 this.monthPicker.slideOut('t', {duration:.2});
38963 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38964 p.fireEvent("select", this, this.value);
38970 Roo.log('picker set value');
38971 Roo.log(this.getValue());
38972 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
38973 m.show(this.el, 'tl-bl?');
38974 ignorehide = false;
38975 // this will trigger hideMonthPicker..
38978 // hidden the day picker
38979 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
38985 p.showMonthPicker.defer(100, p);
38991 beforeBlur : function(){
38992 var v = this.parseDate(this.getRawValue());
38998 /** @cfg {Boolean} grow @hide */
38999 /** @cfg {Number} growMin @hide */
39000 /** @cfg {Number} growMax @hide */
39007 * Ext JS Library 1.1.1
39008 * Copyright(c) 2006-2007, Ext JS, LLC.
39010 * Originally Released Under LGPL - original licence link has changed is not relivant.
39013 * <script type="text/javascript">
39018 * @class Roo.form.ComboBox
39019 * @extends Roo.form.TriggerField
39020 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39022 * Create a new ComboBox.
39023 * @param {Object} config Configuration options
39025 Roo.form.ComboBox = function(config){
39026 Roo.form.ComboBox.superclass.constructor.call(this, config);
39030 * Fires when the dropdown list is expanded
39031 * @param {Roo.form.ComboBox} combo This combo box
39036 * Fires when the dropdown list is collapsed
39037 * @param {Roo.form.ComboBox} combo This combo box
39041 * @event beforeselect
39042 * Fires before a list item is selected. Return false to cancel the selection.
39043 * @param {Roo.form.ComboBox} combo This combo box
39044 * @param {Roo.data.Record} record The data record returned from the underlying store
39045 * @param {Number} index The index of the selected item in the dropdown list
39047 'beforeselect' : true,
39050 * Fires when a list item is selected
39051 * @param {Roo.form.ComboBox} combo This combo box
39052 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39053 * @param {Number} index The index of the selected item in the dropdown list
39057 * @event beforequery
39058 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39059 * The event object passed has these properties:
39060 * @param {Roo.form.ComboBox} combo This combo box
39061 * @param {String} query The query
39062 * @param {Boolean} forceAll true to force "all" query
39063 * @param {Boolean} cancel true to cancel the query
39064 * @param {Object} e The query event object
39066 'beforequery': true,
39069 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39070 * @param {Roo.form.ComboBox} combo This combo box
39075 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39076 * @param {Roo.form.ComboBox} combo This combo box
39077 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39083 if(this.transform){
39084 this.allowDomMove = false;
39085 var s = Roo.getDom(this.transform);
39086 if(!this.hiddenName){
39087 this.hiddenName = s.name;
39090 this.mode = 'local';
39091 var d = [], opts = s.options;
39092 for(var i = 0, len = opts.length;i < len; i++){
39094 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39096 this.value = value;
39098 d.push([value, o.text]);
39100 this.store = new Roo.data.SimpleStore({
39102 fields: ['value', 'text'],
39105 this.valueField = 'value';
39106 this.displayField = 'text';
39108 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39109 if(!this.lazyRender){
39110 this.target = true;
39111 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39112 s.parentNode.removeChild(s); // remove it
39113 this.render(this.el.parentNode);
39115 s.parentNode.removeChild(s); // remove it
39120 this.store = Roo.factory(this.store, Roo.data);
39123 this.selectedIndex = -1;
39124 if(this.mode == 'local'){
39125 if(config.queryDelay === undefined){
39126 this.queryDelay = 10;
39128 if(config.minChars === undefined){
39134 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39136 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39139 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39140 * rendering into an Roo.Editor, defaults to false)
39143 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39144 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39147 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39150 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39151 * the dropdown list (defaults to undefined, with no header element)
39155 * @cfg {String/Roo.Template} tpl The template to use to render the output
39159 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39161 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39163 listWidth: undefined,
39165 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39166 * mode = 'remote' or 'text' if mode = 'local')
39168 displayField: undefined,
39170 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39171 * mode = 'remote' or 'value' if mode = 'local').
39172 * Note: use of a valueField requires the user make a selection
39173 * in order for a value to be mapped.
39175 valueField: undefined,
39179 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39180 * field's data value (defaults to the underlying DOM element's name)
39182 hiddenName: undefined,
39184 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39188 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39190 selectedClass: 'x-combo-selected',
39192 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39193 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39194 * which displays a downward arrow icon).
39196 triggerClass : 'x-form-arrow-trigger',
39198 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39202 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39203 * anchor positions (defaults to 'tl-bl')
39205 listAlign: 'tl-bl?',
39207 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39211 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39212 * query specified by the allQuery config option (defaults to 'query')
39214 triggerAction: 'query',
39216 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39217 * (defaults to 4, does not apply if editable = false)
39221 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39222 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39226 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39227 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39231 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39232 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39236 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39237 * when editable = true (defaults to false)
39239 selectOnFocus:false,
39241 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39243 queryParam: 'query',
39245 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39246 * when mode = 'remote' (defaults to 'Loading...')
39248 loadingText: 'Loading...',
39250 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39254 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39258 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39259 * traditional select (defaults to true)
39263 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39267 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39271 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39272 * listWidth has a higher value)
39276 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39277 * allow the user to set arbitrary text into the field (defaults to false)
39279 forceSelection:false,
39281 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39282 * if typeAhead = true (defaults to 250)
39284 typeAheadDelay : 250,
39286 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39287 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39289 valueNotFoundText : undefined,
39291 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39293 blockFocus : false,
39296 * @cfg {Boolean} disableClear Disable showing of clear button.
39298 disableClear : false,
39300 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39302 alwaysQuery : false,
39308 // element that contains real text value.. (when hidden is used..)
39311 onRender : function(ct, position){
39312 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39313 if(this.hiddenName){
39314 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39316 this.hiddenField.value =
39317 this.hiddenValue !== undefined ? this.hiddenValue :
39318 this.value !== undefined ? this.value : '';
39320 // prevent input submission
39321 this.el.dom.removeAttribute('name');
39326 this.el.dom.setAttribute('autocomplete', 'off');
39329 var cls = 'x-combo-list';
39331 this.list = new Roo.Layer({
39332 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39335 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39336 this.list.setWidth(lw);
39337 this.list.swallowEvent('mousewheel');
39338 this.assetHeight = 0;
39341 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39342 this.assetHeight += this.header.getHeight();
39345 this.innerList = this.list.createChild({cls:cls+'-inner'});
39346 this.innerList.on('mouseover', this.onViewOver, this);
39347 this.innerList.on('mousemove', this.onViewMove, this);
39348 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39350 if(this.allowBlank && !this.pageSize && !this.disableClear){
39351 this.footer = this.list.createChild({cls:cls+'-ft'});
39352 this.pageTb = new Roo.Toolbar(this.footer);
39356 this.footer = this.list.createChild({cls:cls+'-ft'});
39357 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39358 {pageSize: this.pageSize});
39362 if (this.pageTb && this.allowBlank && !this.disableClear) {
39364 this.pageTb.add(new Roo.Toolbar.Fill(), {
39365 cls: 'x-btn-icon x-btn-clear',
39367 handler: function()
39370 _this.clearValue();
39371 _this.onSelect(false, -1);
39376 this.assetHeight += this.footer.getHeight();
39381 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39384 this.view = new Roo.View(this.innerList, this.tpl, {
39385 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39388 this.view.on('click', this.onViewClick, this);
39390 this.store.on('beforeload', this.onBeforeLoad, this);
39391 this.store.on('load', this.onLoad, this);
39392 this.store.on('loadexception', this.onLoadException, this);
39394 if(this.resizable){
39395 this.resizer = new Roo.Resizable(this.list, {
39396 pinned:true, handles:'se'
39398 this.resizer.on('resize', function(r, w, h){
39399 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39400 this.listWidth = w;
39401 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39402 this.restrictHeight();
39404 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39406 if(!this.editable){
39407 this.editable = true;
39408 this.setEditable(false);
39412 if (typeof(this.events.add.listeners) != 'undefined') {
39414 this.addicon = this.wrap.createChild(
39415 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39417 this.addicon.on('click', function(e) {
39418 this.fireEvent('add', this);
39421 if (typeof(this.events.edit.listeners) != 'undefined') {
39423 this.editicon = this.wrap.createChild(
39424 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39425 if (this.addicon) {
39426 this.editicon.setStyle('margin-left', '40px');
39428 this.editicon.on('click', function(e) {
39430 // we fire even if inothing is selected..
39431 this.fireEvent('edit', this, this.lastData );
39441 initEvents : function(){
39442 Roo.form.ComboBox.superclass.initEvents.call(this);
39444 this.keyNav = new Roo.KeyNav(this.el, {
39445 "up" : function(e){
39446 this.inKeyMode = true;
39450 "down" : function(e){
39451 if(!this.isExpanded()){
39452 this.onTriggerClick();
39454 this.inKeyMode = true;
39459 "enter" : function(e){
39460 this.onViewClick();
39464 "esc" : function(e){
39468 "tab" : function(e){
39469 this.onViewClick(false);
39470 this.fireEvent("specialkey", this, e);
39476 doRelay : function(foo, bar, hname){
39477 if(hname == 'down' || this.scope.isExpanded()){
39478 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39485 this.queryDelay = Math.max(this.queryDelay || 10,
39486 this.mode == 'local' ? 10 : 250);
39487 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39488 if(this.typeAhead){
39489 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39491 if(this.editable !== false){
39492 this.el.on("keyup", this.onKeyUp, this);
39494 if(this.forceSelection){
39495 this.on('blur', this.doForce, this);
39499 onDestroy : function(){
39501 this.view.setStore(null);
39502 this.view.el.removeAllListeners();
39503 this.view.el.remove();
39504 this.view.purgeListeners();
39507 this.list.destroy();
39510 this.store.un('beforeload', this.onBeforeLoad, this);
39511 this.store.un('load', this.onLoad, this);
39512 this.store.un('loadexception', this.onLoadException, this);
39514 Roo.form.ComboBox.superclass.onDestroy.call(this);
39518 fireKey : function(e){
39519 if(e.isNavKeyPress() && !this.list.isVisible()){
39520 this.fireEvent("specialkey", this, e);
39525 onResize: function(w, h){
39526 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39528 if(typeof w != 'number'){
39529 // we do not handle it!?!?
39532 var tw = this.trigger.getWidth();
39533 tw += this.addicon ? this.addicon.getWidth() : 0;
39534 tw += this.editicon ? this.editicon.getWidth() : 0;
39536 this.el.setWidth( this.adjustWidth('input', x));
39538 this.trigger.setStyle('left', x+'px');
39540 if(this.list && this.listWidth === undefined){
39541 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39542 this.list.setWidth(lw);
39543 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39551 * Allow or prevent the user from directly editing the field text. If false is passed,
39552 * the user will only be able to select from the items defined in the dropdown list. This method
39553 * is the runtime equivalent of setting the 'editable' config option at config time.
39554 * @param {Boolean} value True to allow the user to directly edit the field text
39556 setEditable : function(value){
39557 if(value == this.editable){
39560 this.editable = value;
39562 this.el.dom.setAttribute('readOnly', true);
39563 this.el.on('mousedown', this.onTriggerClick, this);
39564 this.el.addClass('x-combo-noedit');
39566 this.el.dom.setAttribute('readOnly', false);
39567 this.el.un('mousedown', this.onTriggerClick, this);
39568 this.el.removeClass('x-combo-noedit');
39573 onBeforeLoad : function(){
39574 if(!this.hasFocus){
39577 this.innerList.update(this.loadingText ?
39578 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39579 this.restrictHeight();
39580 this.selectedIndex = -1;
39584 onLoad : function(){
39585 if(!this.hasFocus){
39588 if(this.store.getCount() > 0){
39590 this.restrictHeight();
39591 if(this.lastQuery == this.allQuery){
39593 this.el.dom.select();
39595 if(!this.selectByValue(this.value, true)){
39596 this.select(0, true);
39600 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39601 this.taTask.delay(this.typeAheadDelay);
39605 this.onEmptyResults();
39610 onLoadException : function()
39613 Roo.log(this.store.reader.jsonData);
39614 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39615 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39621 onTypeAhead : function(){
39622 if(this.store.getCount() > 0){
39623 var r = this.store.getAt(0);
39624 var newValue = r.data[this.displayField];
39625 var len = newValue.length;
39626 var selStart = this.getRawValue().length;
39627 if(selStart != len){
39628 this.setRawValue(newValue);
39629 this.selectText(selStart, newValue.length);
39635 onSelect : function(record, index){
39636 if(this.fireEvent('beforeselect', this, record, index) !== false){
39637 this.setFromData(index > -1 ? record.data : false);
39639 this.fireEvent('select', this, record, index);
39644 * Returns the currently selected field value or empty string if no value is set.
39645 * @return {String} value The selected value
39647 getValue : function(){
39648 if(this.valueField){
39649 return typeof this.value != 'undefined' ? this.value : '';
39651 return Roo.form.ComboBox.superclass.getValue.call(this);
39656 * Clears any text/value currently set in the field
39658 clearValue : function(){
39659 if(this.hiddenField){
39660 this.hiddenField.value = '';
39663 this.setRawValue('');
39664 this.lastSelectionText = '';
39669 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39670 * will be displayed in the field. If the value does not match the data value of an existing item,
39671 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39672 * Otherwise the field will be blank (although the value will still be set).
39673 * @param {String} value The value to match
39675 setValue : function(v){
39677 if(this.valueField){
39678 var r = this.findRecord(this.valueField, v);
39680 text = r.data[this.displayField];
39681 }else if(this.valueNotFoundText !== undefined){
39682 text = this.valueNotFoundText;
39685 this.lastSelectionText = text;
39686 if(this.hiddenField){
39687 this.hiddenField.value = v;
39689 Roo.form.ComboBox.superclass.setValue.call(this, text);
39693 * @property {Object} the last set data for the element
39698 * Sets the value of the field based on a object which is related to the record format for the store.
39699 * @param {Object} value the value to set as. or false on reset?
39701 setFromData : function(o){
39702 var dv = ''; // display value
39703 var vv = ''; // value value..
39705 if (this.displayField) {
39706 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39708 // this is an error condition!!!
39709 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39712 if(this.valueField){
39713 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39715 if(this.hiddenField){
39716 this.hiddenField.value = vv;
39718 this.lastSelectionText = dv;
39719 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39723 // no hidden field.. - we store the value in 'value', but still display
39724 // display field!!!!
39725 this.lastSelectionText = dv;
39726 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39732 reset : function(){
39733 // overridden so that last data is reset..
39734 this.setValue(this.resetValue);
39735 this.clearInvalid();
39736 this.lastData = false;
39738 this.view.clearSelections();
39742 findRecord : function(prop, value){
39744 if(this.store.getCount() > 0){
39745 this.store.each(function(r){
39746 if(r.data[prop] == value){
39756 getName: function()
39758 // returns hidden if it's set..
39759 if (!this.rendered) {return ''};
39760 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39764 onViewMove : function(e, t){
39765 this.inKeyMode = false;
39769 onViewOver : function(e, t){
39770 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39773 var item = this.view.findItemFromChild(t);
39775 var index = this.view.indexOf(item);
39776 this.select(index, false);
39781 onViewClick : function(doFocus)
39783 var index = this.view.getSelectedIndexes()[0];
39784 var r = this.store.getAt(index);
39786 this.onSelect(r, index);
39788 if(doFocus !== false && !this.blockFocus){
39794 restrictHeight : function(){
39795 this.innerList.dom.style.height = '';
39796 var inner = this.innerList.dom;
39797 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39798 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39799 this.list.beginUpdate();
39800 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39801 this.list.alignTo(this.el, this.listAlign);
39802 this.list.endUpdate();
39806 onEmptyResults : function(){
39811 * Returns true if the dropdown list is expanded, else false.
39813 isExpanded : function(){
39814 return this.list.isVisible();
39818 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39819 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39820 * @param {String} value The data value of the item to select
39821 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39822 * selected item if it is not currently in view (defaults to true)
39823 * @return {Boolean} True if the value matched an item in the list, else false
39825 selectByValue : function(v, scrollIntoView){
39826 if(v !== undefined && v !== null){
39827 var r = this.findRecord(this.valueField || this.displayField, v);
39829 this.select(this.store.indexOf(r), scrollIntoView);
39837 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39838 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39839 * @param {Number} index The zero-based index of the list item to select
39840 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39841 * selected item if it is not currently in view (defaults to true)
39843 select : function(index, scrollIntoView){
39844 this.selectedIndex = index;
39845 this.view.select(index);
39846 if(scrollIntoView !== false){
39847 var el = this.view.getNode(index);
39849 this.innerList.scrollChildIntoView(el, false);
39855 selectNext : function(){
39856 var ct = this.store.getCount();
39858 if(this.selectedIndex == -1){
39860 }else if(this.selectedIndex < ct-1){
39861 this.select(this.selectedIndex+1);
39867 selectPrev : function(){
39868 var ct = this.store.getCount();
39870 if(this.selectedIndex == -1){
39872 }else if(this.selectedIndex != 0){
39873 this.select(this.selectedIndex-1);
39879 onKeyUp : function(e){
39880 if(this.editable !== false && !e.isSpecialKey()){
39881 this.lastKey = e.getKey();
39882 this.dqTask.delay(this.queryDelay);
39887 validateBlur : function(){
39888 return !this.list || !this.list.isVisible();
39892 initQuery : function(){
39893 this.doQuery(this.getRawValue());
39897 doForce : function(){
39898 if(this.el.dom.value.length > 0){
39899 this.el.dom.value =
39900 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39906 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39907 * query allowing the query action to be canceled if needed.
39908 * @param {String} query The SQL query to execute
39909 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39910 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39911 * saved in the current store (defaults to false)
39913 doQuery : function(q, forceAll){
39914 if(q === undefined || q === null){
39919 forceAll: forceAll,
39923 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39927 forceAll = qe.forceAll;
39928 if(forceAll === true || (q.length >= this.minChars)){
39929 if(this.lastQuery != q || this.alwaysQuery){
39930 this.lastQuery = q;
39931 if(this.mode == 'local'){
39932 this.selectedIndex = -1;
39934 this.store.clearFilter();
39936 this.store.filter(this.displayField, q);
39940 this.store.baseParams[this.queryParam] = q;
39942 params: this.getParams(q)
39947 this.selectedIndex = -1;
39954 getParams : function(q){
39956 //p[this.queryParam] = q;
39959 p.limit = this.pageSize;
39965 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39967 collapse : function(){
39968 if(!this.isExpanded()){
39972 Roo.get(document).un('mousedown', this.collapseIf, this);
39973 Roo.get(document).un('mousewheel', this.collapseIf, this);
39974 if (!this.editable) {
39975 Roo.get(document).un('keydown', this.listKeyPress, this);
39977 this.fireEvent('collapse', this);
39981 collapseIf : function(e){
39982 if(!e.within(this.wrap) && !e.within(this.list)){
39988 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39990 expand : function(){
39991 if(this.isExpanded() || !this.hasFocus){
39994 this.list.alignTo(this.el, this.listAlign);
39996 Roo.get(document).on('mousedown', this.collapseIf, this);
39997 Roo.get(document).on('mousewheel', this.collapseIf, this);
39998 if (!this.editable) {
39999 Roo.get(document).on('keydown', this.listKeyPress, this);
40002 this.fireEvent('expand', this);
40006 // Implements the default empty TriggerField.onTriggerClick function
40007 onTriggerClick : function(){
40011 if(this.isExpanded()){
40013 if (!this.blockFocus) {
40018 this.hasFocus = true;
40019 if(this.triggerAction == 'all') {
40020 this.doQuery(this.allQuery, true);
40022 this.doQuery(this.getRawValue());
40024 if (!this.blockFocus) {
40029 listKeyPress : function(e)
40031 //Roo.log('listkeypress');
40032 // scroll to first matching element based on key pres..
40033 if (e.isSpecialKey()) {
40036 var k = String.fromCharCode(e.getKey()).toUpperCase();
40039 var csel = this.view.getSelectedNodes();
40040 var cselitem = false;
40042 var ix = this.view.indexOf(csel[0]);
40043 cselitem = this.store.getAt(ix);
40044 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40050 this.store.each(function(v) {
40052 // start at existing selection.
40053 if (cselitem.id == v.id) {
40059 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40060 match = this.store.indexOf(v);
40065 if (match === false) {
40066 return true; // no more action?
40069 this.view.select(match);
40070 var sn = Roo.get(this.view.getSelectedNodes()[0])
40071 sn.scrollIntoView(sn.dom.parentNode, false);
40075 * @cfg {Boolean} grow
40079 * @cfg {Number} growMin
40083 * @cfg {Number} growMax
40091 * Copyright(c) 2010-2012, Roo J Solutions Limited
40098 * @class Roo.form.ComboBoxArray
40099 * @extends Roo.form.TextField
40100 * A facebook style adder... for lists of email / people / countries etc...
40101 * pick multiple items from a combo box, and shows each one.
40103 * Fred [x] Brian [x] [Pick another |v]
40106 * For this to work: it needs various extra information
40107 * - normal combo problay has
40109 * + displayField, valueField
40111 * For our purpose...
40114 * If we change from 'extends' to wrapping...
40121 * Create a new ComboBoxArray.
40122 * @param {Object} config Configuration options
40126 Roo.form.ComboBoxArray = function(config)
40129 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40131 this.items = new Roo.util.MixedCollection(false);
40133 // construct the child combo...
40143 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40146 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40151 // behavies liek a hiddne field
40152 inputType: 'hidden',
40154 * @cfg {Number} width The width of the box that displays the selected element
40161 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40165 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40167 hiddenName : false,
40170 // private the array of items that are displayed..
40172 // private - the hidden field el.
40174 // private - the filed el..
40177 //validateValue : function() { return true; }, // all values are ok!
40178 //onAddClick: function() { },
40180 onRender : function(ct, position)
40183 // create the standard hidden element
40184 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40187 // give fake names to child combo;
40188 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40189 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40191 this.combo = Roo.factory(this.combo, Roo.form);
40192 this.combo.onRender(ct, position);
40193 if (typeof(this.combo.width) != 'undefined') {
40194 this.combo.onResize(this.combo.width,0);
40197 this.combo.initEvents();
40199 // assigned so form know we need to do this..
40200 this.store = this.combo.store;
40201 this.valueField = this.combo.valueField;
40202 this.displayField = this.combo.displayField ;
40205 this.combo.wrap.addClass('x-cbarray-grp');
40207 var cbwrap = this.combo.wrap.createChild(
40208 {tag: 'div', cls: 'x-cbarray-cb'},
40213 this.hiddenEl = this.combo.wrap.createChild({
40214 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40216 this.el = this.combo.wrap.createChild({
40217 tag: 'input', type:'hidden' , name: this.name, value : ''
40219 // this.el.dom.removeAttribute("name");
40222 this.outerWrap = this.combo.wrap;
40223 this.wrap = cbwrap;
40225 this.outerWrap.setWidth(this.width);
40226 this.outerWrap.dom.removeChild(this.el.dom);
40228 this.wrap.dom.appendChild(this.el.dom);
40229 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40230 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40232 this.combo.trigger.setStyle('position','relative');
40233 this.combo.trigger.setStyle('left', '0px');
40234 this.combo.trigger.setStyle('top', '2px');
40236 this.combo.el.setStyle('vertical-align', 'text-bottom');
40238 //this.trigger.setStyle('vertical-align', 'top');
40240 // this should use the code from combo really... on('add' ....)
40244 this.adder = this.outerWrap.createChild(
40245 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40247 this.adder.on('click', function(e) {
40248 _t.fireEvent('adderclick', this, e);
40252 //this.adder.on('click', this.onAddClick, _t);
40255 this.combo.on('select', function(cb, rec, ix) {
40256 this.addItem(rec.data);
40259 cb.el.dom.value = '';
40260 //cb.lastData = rec.data;
40269 getName: function()
40271 // returns hidden if it's set..
40272 if (!this.rendered) {return ''};
40273 return this.hiddenName ? this.hiddenName : this.name;
40278 onResize: function(w, h){
40281 // not sure if this is needed..
40282 //this.combo.onResize(w,h);
40284 if(typeof w != 'number'){
40285 // we do not handle it!?!?
40288 var tw = this.combo.trigger.getWidth();
40289 tw += this.addicon ? this.addicon.getWidth() : 0;
40290 tw += this.editicon ? this.editicon.getWidth() : 0;
40292 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40294 this.combo.trigger.setStyle('left', '0px');
40296 if(this.list && this.listWidth === undefined){
40297 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40298 this.list.setWidth(lw);
40299 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40306 addItem: function(rec)
40308 var valueField = this.combo.valueField;
40309 var displayField = this.combo.displayField;
40310 if (this.items.indexOfKey(rec[valueField]) > -1) {
40311 //console.log("GOT " + rec.data.id);
40315 var x = new Roo.form.ComboBoxArray.Item({
40316 //id : rec[this.idField],
40318 displayField : displayField ,
40319 tipField : displayField ,
40323 this.items.add(rec[valueField],x);
40324 // add it before the element..
40325 this.updateHiddenEl();
40326 x.render(this.outerWrap, this.wrap.dom);
40327 // add the image handler..
40330 updateHiddenEl : function()
40333 if (!this.hiddenEl) {
40337 var idField = this.combo.valueField;
40339 this.items.each(function(f) {
40340 ar.push(f.data[idField]);
40343 this.hiddenEl.dom.value = ar.join(',');
40349 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40350 this.items.each(function(f) {
40353 this.el.dom.value = '';
40354 if (this.hiddenEl) {
40355 this.hiddenEl.dom.value = '';
40359 getValue: function()
40361 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40363 setValue: function(v) // not a valid action - must use addItems..
40370 if (this.store.isLocal && (typeof(v) == 'string')) {
40371 // then we can use the store to find the values..
40372 // comma seperated at present.. this needs to allow JSON based encoding..
40373 this.hiddenEl.value = v;
40375 Roo.each(v.split(','), function(k) {
40376 Roo.log("CHECK " + this.valueField + ',' + k);
40377 var li = this.store.query(this.valueField, k);
40382 add[this.valueField] = k;
40383 add[this.displayField] = li.item(0).data[this.displayField];
40389 if (typeof(v) == 'object') {
40390 // then let's assume it's an array of objects..
40391 Roo.each(v, function(l) {
40399 setFromData: function(v)
40401 // this recieves an object, if setValues is called.
40403 this.el.dom.value = v[this.displayField];
40404 this.hiddenEl.dom.value = v[this.valueField];
40405 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40408 var kv = v[this.valueField];
40409 var dv = v[this.displayField];
40410 kv = typeof(kv) != 'string' ? '' : kv;
40411 dv = typeof(dv) != 'string' ? '' : dv;
40414 var keys = kv.split(',');
40415 var display = dv.split(',');
40416 for (var i = 0 ; i < keys.length; i++) {
40419 add[this.valueField] = keys[i];
40420 add[this.displayField] = display[i];
40428 * Validates the combox array value
40429 * @return {Boolean} True if the value is valid, else false
40431 validate : function(){
40432 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40433 this.clearInvalid();
40439 validateValue : function(value){
40440 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40448 isDirty : function() {
40449 if(this.disabled) {
40454 var d = Roo.decode(String(this.originalValue));
40456 return String(this.getValue()) !== String(this.originalValue);
40459 var originalValue = [];
40461 for (var i = 0; i < d.length; i++){
40462 originalValue.push(d[i][this.valueField]);
40465 return String(this.getValue()) !== String(originalValue.join(','));
40474 * @class Roo.form.ComboBoxArray.Item
40475 * @extends Roo.BoxComponent
40476 * A selected item in the list
40477 * Fred [x] Brian [x] [Pick another |v]
40480 * Create a new item.
40481 * @param {Object} config Configuration options
40484 Roo.form.ComboBoxArray.Item = function(config) {
40485 config.id = Roo.id();
40486 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40489 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40492 displayField : false,
40496 defaultAutoCreate : {
40498 cls: 'x-cbarray-item',
40505 src : Roo.BLANK_IMAGE_URL ,
40513 onRender : function(ct, position)
40515 Roo.form.Field.superclass.onRender.call(this, ct, position);
40518 var cfg = this.getAutoCreate();
40519 this.el = ct.createChild(cfg, position);
40522 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40524 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40525 this.cb.renderer(this.data) :
40526 String.format('{0}',this.data[this.displayField]);
40529 this.el.child('div').dom.setAttribute('qtip',
40530 String.format('{0}',this.data[this.tipField])
40533 this.el.child('img').on('click', this.remove, this);
40537 remove : function()
40540 this.cb.items.remove(this);
40541 this.el.child('img').un('click', this.remove, this);
40543 this.cb.updateHiddenEl();
40547 * Ext JS Library 1.1.1
40548 * Copyright(c) 2006-2007, Ext JS, LLC.
40550 * Originally Released Under LGPL - original licence link has changed is not relivant.
40553 * <script type="text/javascript">
40556 * @class Roo.form.Checkbox
40557 * @extends Roo.form.Field
40558 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40560 * Creates a new Checkbox
40561 * @param {Object} config Configuration options
40563 Roo.form.Checkbox = function(config){
40564 Roo.form.Checkbox.superclass.constructor.call(this, config);
40568 * Fires when the checkbox is checked or unchecked.
40569 * @param {Roo.form.Checkbox} this This checkbox
40570 * @param {Boolean} checked The new checked value
40576 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40578 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40580 focusClass : undefined,
40582 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40584 fieldClass: "x-form-field",
40586 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40590 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40591 * {tag: "input", type: "checkbox", autocomplete: "off"})
40593 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40595 * @cfg {String} boxLabel The text that appears beside the checkbox
40599 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40603 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40605 valueOff: '0', // value when not checked..
40607 actionMode : 'viewEl',
40610 itemCls : 'x-menu-check-item x-form-item',
40611 groupClass : 'x-menu-group-item',
40612 inputType : 'hidden',
40615 inSetChecked: false, // check that we are not calling self...
40617 inputElement: false, // real input element?
40618 basedOn: false, // ????
40620 isFormField: true, // not sure where this is needed!!!!
40622 onResize : function(){
40623 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40624 if(!this.boxLabel){
40625 this.el.alignTo(this.wrap, 'c-c');
40629 initEvents : function(){
40630 Roo.form.Checkbox.superclass.initEvents.call(this);
40631 this.el.on("click", this.onClick, this);
40632 this.el.on("change", this.onClick, this);
40636 getResizeEl : function(){
40640 getPositionEl : function(){
40645 onRender : function(ct, position){
40646 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40648 if(this.inputValue !== undefined){
40649 this.el.dom.value = this.inputValue;
40652 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40653 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40654 var viewEl = this.wrap.createChild({
40655 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40656 this.viewEl = viewEl;
40657 this.wrap.on('click', this.onClick, this);
40659 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40660 this.el.on('propertychange', this.setFromHidden, this); //ie
40665 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40666 // viewEl.on('click', this.onClick, this);
40668 //if(this.checked){
40669 this.setChecked(this.checked);
40671 //this.checked = this.el.dom;
40677 initValue : Roo.emptyFn,
40680 * Returns the checked state of the checkbox.
40681 * @return {Boolean} True if checked, else false
40683 getValue : function(){
40685 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40687 return this.valueOff;
40692 onClick : function(){
40693 this.setChecked(!this.checked);
40695 //if(this.el.dom.checked != this.checked){
40696 // this.setValue(this.el.dom.checked);
40701 * Sets the checked state of the checkbox.
40702 * On is always based on a string comparison between inputValue and the param.
40703 * @param {Boolean/String} value - the value to set
40704 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40706 setValue : function(v,suppressEvent){
40709 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40710 //if(this.el && this.el.dom){
40711 // this.el.dom.checked = this.checked;
40712 // this.el.dom.defaultChecked = this.checked;
40714 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40715 //this.fireEvent("check", this, this.checked);
40718 setChecked : function(state,suppressEvent)
40720 if (this.inSetChecked) {
40721 this.checked = state;
40727 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40729 this.checked = state;
40730 if(suppressEvent !== true){
40731 this.fireEvent('check', this, state);
40733 this.inSetChecked = true;
40734 this.el.dom.value = state ? this.inputValue : this.valueOff;
40735 this.inSetChecked = false;
40738 // handle setting of hidden value by some other method!!?!?
40739 setFromHidden: function()
40744 //console.log("SET FROM HIDDEN");
40745 //alert('setFrom hidden');
40746 this.setValue(this.el.dom.value);
40749 onDestroy : function()
40752 Roo.get(this.viewEl).remove();
40755 Roo.form.Checkbox.superclass.onDestroy.call(this);
40760 * Ext JS Library 1.1.1
40761 * Copyright(c) 2006-2007, Ext JS, LLC.
40763 * Originally Released Under LGPL - original licence link has changed is not relivant.
40766 * <script type="text/javascript">
40770 * @class Roo.form.Radio
40771 * @extends Roo.form.Checkbox
40772 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40773 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40775 * Creates a new Radio
40776 * @param {Object} config Configuration options
40778 Roo.form.Radio = function(){
40779 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40781 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40782 inputType: 'radio',
40785 * If this radio is part of a group, it will return the selected value
40788 getGroupValue : function(){
40789 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40793 onRender : function(ct, position){
40794 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40796 if(this.inputValue !== undefined){
40797 this.el.dom.value = this.inputValue;
40800 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40801 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40802 //var viewEl = this.wrap.createChild({
40803 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40804 //this.viewEl = viewEl;
40805 //this.wrap.on('click', this.onClick, this);
40807 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40808 //this.el.on('propertychange', this.setFromHidden, this); //ie
40813 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40814 // viewEl.on('click', this.onClick, this);
40817 this.el.dom.checked = 'checked' ;
40823 });//<script type="text/javascript">
40826 * Ext JS Library 1.1.1
40827 * Copyright(c) 2006-2007, Ext JS, LLC.
40828 * licensing@extjs.com
40830 * http://www.extjs.com/license
40836 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
40837 * - IE ? - no idea how much works there.
40845 * @class Ext.form.HtmlEditor
40846 * @extends Ext.form.Field
40847 * Provides a lightweight HTML Editor component.
40849 * This has been tested on Fireforx / Chrome.. IE may not be so great..
40851 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
40852 * supported by this editor.</b><br/><br/>
40853 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
40854 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40856 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
40858 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
40862 * @cfg {String} createLinkText The default text for the create link prompt
40864 createLinkText : 'Please enter the URL for the link:',
40866 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
40868 defaultLinkValue : 'http:/'+'/',
40871 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40876 * @cfg {Number} height (in pixels)
40880 * @cfg {Number} width (in pixels)
40885 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40888 stylesheets: false,
40893 // private properties
40894 validationEvent : false,
40896 initialized : false,
40898 sourceEditMode : false,
40899 onFocus : Roo.emptyFn,
40901 hideMode:'offsets',
40903 defaultAutoCreate : { // modified by initCompnoent..
40905 style:"width:500px;height:300px;",
40906 autocomplete: "off"
40910 initComponent : function(){
40913 * @event initialize
40914 * Fires when the editor is fully initialized (including the iframe)
40915 * @param {HtmlEditor} this
40920 * Fires when the editor is first receives the focus. Any insertion must wait
40921 * until after this event.
40922 * @param {HtmlEditor} this
40926 * @event beforesync
40927 * Fires before the textarea is updated with content from the editor iframe. Return false
40928 * to cancel the sync.
40929 * @param {HtmlEditor} this
40930 * @param {String} html
40934 * @event beforepush
40935 * Fires before the iframe editor is updated with content from the textarea. Return false
40936 * to cancel the push.
40937 * @param {HtmlEditor} this
40938 * @param {String} html
40943 * Fires when the textarea is updated with content from the editor iframe.
40944 * @param {HtmlEditor} this
40945 * @param {String} html
40950 * Fires when the iframe editor is updated with content from the textarea.
40951 * @param {HtmlEditor} this
40952 * @param {String} html
40956 * @event editmodechange
40957 * Fires when the editor switches edit modes
40958 * @param {HtmlEditor} this
40959 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
40961 editmodechange: true,
40963 * @event editorevent
40964 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40965 * @param {HtmlEditor} this
40969 this.defaultAutoCreate = {
40971 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
40972 autocomplete: "off"
40977 * Protected method that will not generally be called directly. It
40978 * is called when the editor creates its toolbar. Override this method if you need to
40979 * add custom toolbar buttons.
40980 * @param {HtmlEditor} editor
40982 createToolbar : function(editor){
40983 if (!editor.toolbars || !editor.toolbars.length) {
40984 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
40987 for (var i =0 ; i < editor.toolbars.length;i++) {
40988 editor.toolbars[i] = Roo.factory(
40989 typeof(editor.toolbars[i]) == 'string' ?
40990 { xtype: editor.toolbars[i]} : editor.toolbars[i],
40991 Roo.form.HtmlEditor);
40992 editor.toolbars[i].init(editor);
40999 * Protected method that will not generally be called directly. It
41000 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41001 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41003 getDocMarkup : function(){
41006 if (this.stylesheets === false) {
41008 Roo.get(document.head).select('style').each(function(node) {
41009 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41012 Roo.get(document.head).select('link').each(function(node) {
41013 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41016 } else if (!this.stylesheets.length) {
41018 st = '<style type="text/css">' +
41019 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41022 Roo.log('this.stylesheets');
41023 Roo.log(this.stylesheet);
41024 Roo.each(this.stylesheets, function(s) {
41025 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41030 st += '<style type="text/css">' +
41031 'IMG { cursor: pointer } ' +
41035 return '<html><head>' + st +
41036 //<style type="text/css">' +
41037 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41039 ' </head><body class="roo-htmleditor-body"></body></html>';
41043 onRender : function(ct, position)
41046 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
41047 this.el.dom.style.border = '0 none';
41048 this.el.dom.setAttribute('tabIndex', -1);
41049 this.el.addClass('x-hidden');
41050 if(Roo.isIE){ // fix IE 1px bogus margin
41051 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41053 this.wrap = this.el.wrap({
41054 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
41057 if (this.resizable) {
41058 this.resizeEl = new Roo.Resizable(this.wrap, {
41062 minHeight : this.height,
41063 height: this.height,
41064 handles : this.resizable,
41067 resize : function(r, w, h) {
41068 _t.onResize(w,h); // -something
41075 this.frameId = Roo.id();
41077 this.createToolbar(this);
41081 var iframe = this.wrap.createChild({
41084 name: this.frameId,
41085 frameBorder : 'no',
41086 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41090 // console.log(iframe);
41091 //this.wrap.dom.appendChild(iframe);
41093 this.iframe = iframe.dom;
41095 this.assignDocWin();
41097 this.doc.designMode = 'on';
41100 this.doc.write(this.getDocMarkup());
41104 var task = { // must defer to wait for browser to be ready
41106 //console.log("run task?" + this.doc.readyState);
41107 this.assignDocWin();
41108 if(this.doc.body || this.doc.readyState == 'complete'){
41110 this.doc.designMode="on";
41114 Roo.TaskMgr.stop(task);
41115 this.initEditor.defer(10, this);
41122 Roo.TaskMgr.start(task);
41125 this.setSize(this.wrap.getSize());
41127 if (this.resizeEl) {
41128 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
41129 // should trigger onReize..
41134 onResize : function(w, h)
41136 //Roo.log('resize: ' +w + ',' + h );
41137 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
41138 if(this.el && this.iframe){
41139 if(typeof w == 'number'){
41140 var aw = w - this.wrap.getFrameWidth('lr');
41141 this.el.setWidth(this.adjustWidth('textarea', aw));
41142 this.iframe.style.width = aw + 'px';
41144 if(typeof h == 'number'){
41146 for (var i =0; i < this.toolbars.length;i++) {
41147 // fixme - ask toolbars for heights?
41148 tbh += this.toolbars[i].tb.el.getHeight();
41149 if (this.toolbars[i].footer) {
41150 tbh += this.toolbars[i].footer.el.getHeight();
41157 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
41158 ah -= 5; // knock a few pixes off for look..
41159 this.el.setHeight(this.adjustWidth('textarea', ah));
41160 this.iframe.style.height = ah + 'px';
41162 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
41169 * Toggles the editor between standard and source edit mode.
41170 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41172 toggleSourceEdit : function(sourceEditMode){
41174 this.sourceEditMode = sourceEditMode === true;
41176 if(this.sourceEditMode){
41178 // Roo.log(this.syncValue());
41180 this.iframe.className = 'x-hidden';
41181 this.el.removeClass('x-hidden');
41182 this.el.dom.removeAttribute('tabIndex');
41186 // Roo.log(this.pushValue());
41188 this.iframe.className = '';
41189 this.el.addClass('x-hidden');
41190 this.el.dom.setAttribute('tabIndex', -1);
41193 this.setSize(this.wrap.getSize());
41194 this.fireEvent('editmodechange', this, this.sourceEditMode);
41197 // private used internally
41198 createLink : function(){
41199 var url = prompt(this.createLinkText, this.defaultLinkValue);
41200 if(url && url != 'http:/'+'/'){
41201 this.relayCmd('createlink', url);
41205 // private (for BoxComponent)
41206 adjustSize : Roo.BoxComponent.prototype.adjustSize,
41208 // private (for BoxComponent)
41209 getResizeEl : function(){
41213 // private (for BoxComponent)
41214 getPositionEl : function(){
41219 initEvents : function(){
41220 this.originalValue = this.getValue();
41224 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
41227 markInvalid : Roo.emptyFn,
41229 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
41232 clearInvalid : Roo.emptyFn,
41234 setValue : function(v){
41235 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
41240 * Protected method that will not generally be called directly. If you need/want
41241 * custom HTML cleanup, this is the method you should override.
41242 * @param {String} html The HTML to be cleaned
41243 * return {String} The cleaned HTML
41245 cleanHtml : function(html){
41246 html = String(html);
41247 if(html.length > 5){
41248 if(Roo.isSafari){ // strip safari nonsense
41249 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41252 if(html == ' '){
41259 * Protected method that will not generally be called directly. Syncs the contents
41260 * of the editor iframe with the textarea.
41262 syncValue : function(){
41263 if(this.initialized){
41264 var bd = (this.doc.body || this.doc.documentElement);
41265 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41266 var html = bd.innerHTML;
41268 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41269 var m = bs.match(/text-align:(.*?);/i);
41271 html = '<div style="'+m[0]+'">' + html + '</div>';
41274 html = this.cleanHtml(html);
41275 // fix up the special chars.. normaly like back quotes in word...
41276 // however we do not want to do this with chinese..
41277 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41278 var cc = b.charCodeAt();
41280 (cc >= 0x4E00 && cc < 0xA000 ) ||
41281 (cc >= 0x3400 && cc < 0x4E00 ) ||
41282 (cc >= 0xf900 && cc < 0xfb00 )
41288 if(this.fireEvent('beforesync', this, html) !== false){
41289 this.el.dom.value = html;
41290 this.fireEvent('sync', this, html);
41296 * Protected method that will not generally be called directly. Pushes the value of the textarea
41297 * into the iframe editor.
41299 pushValue : function(){
41300 if(this.initialized){
41301 var v = this.el.dom.value;
41307 if(this.fireEvent('beforepush', this, v) !== false){
41308 var d = (this.doc.body || this.doc.documentElement);
41310 this.cleanUpPaste();
41311 this.el.dom.value = d.innerHTML;
41312 this.fireEvent('push', this, v);
41318 deferFocus : function(){
41319 this.focus.defer(10, this);
41323 focus : function(){
41324 if(this.win && !this.sourceEditMode){
41331 assignDocWin: function()
41333 var iframe = this.iframe;
41336 this.doc = iframe.contentWindow.document;
41337 this.win = iframe.contentWindow;
41339 if (!Roo.get(this.frameId)) {
41342 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41343 this.win = Roo.get(this.frameId).dom.contentWindow;
41348 initEditor : function(){
41349 //console.log("INIT EDITOR");
41350 this.assignDocWin();
41354 this.doc.designMode="on";
41356 this.doc.write(this.getDocMarkup());
41359 var dbody = (this.doc.body || this.doc.documentElement);
41360 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41361 // this copies styles from the containing element into thsi one..
41362 // not sure why we need all of this..
41363 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41364 ss['background-attachment'] = 'fixed'; // w3c
41365 dbody.bgProperties = 'fixed'; // ie
41366 Roo.DomHelper.applyStyles(dbody, ss);
41367 Roo.EventManager.on(this.doc, {
41368 //'mousedown': this.onEditorEvent,
41369 'mouseup': this.onEditorEvent,
41370 'dblclick': this.onEditorEvent,
41371 'click': this.onEditorEvent,
41372 'keyup': this.onEditorEvent,
41377 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41379 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41380 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41382 this.initialized = true;
41384 this.fireEvent('initialize', this);
41389 onDestroy : function(){
41395 for (var i =0; i < this.toolbars.length;i++) {
41396 // fixme - ask toolbars for heights?
41397 this.toolbars[i].onDestroy();
41400 this.wrap.dom.innerHTML = '';
41401 this.wrap.remove();
41406 onFirstFocus : function(){
41408 this.assignDocWin();
41411 this.activated = true;
41412 for (var i =0; i < this.toolbars.length;i++) {
41413 this.toolbars[i].onFirstFocus();
41416 if(Roo.isGecko){ // prevent silly gecko errors
41418 var s = this.win.getSelection();
41419 if(!s.focusNode || s.focusNode.nodeType != 3){
41420 var r = s.getRangeAt(0);
41421 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41426 this.execCmd('useCSS', true);
41427 this.execCmd('styleWithCSS', false);
41430 this.fireEvent('activate', this);
41434 adjustFont: function(btn){
41435 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41436 //if(Roo.isSafari){ // safari
41439 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41440 if(Roo.isSafari){ // safari
41441 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41442 v = (v < 10) ? 10 : v;
41443 v = (v > 48) ? 48 : v;
41444 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41449 v = Math.max(1, v+adjust);
41451 this.execCmd('FontSize', v );
41454 onEditorEvent : function(e){
41455 this.fireEvent('editorevent', this, e);
41456 // this.updateToolbar();
41457 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41460 insertTag : function(tg)
41462 // could be a bit smarter... -> wrap the current selected tRoo..
41463 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41465 range = this.createRange(this.getSelection());
41466 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41467 wrappingNode.appendChild(range.extractContents());
41468 range.insertNode(wrappingNode);
41475 this.execCmd("formatblock", tg);
41479 insertText : function(txt)
41483 var range = this.createRange();
41484 range.deleteContents();
41485 //alert(Sender.getAttribute('label'));
41487 range.insertNode(this.doc.createTextNode(txt));
41491 relayBtnCmd : function(btn){
41492 this.relayCmd(btn.cmd);
41496 * Executes a Midas editor command on the editor document and performs necessary focus and
41497 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41498 * @param {String} cmd The Midas command
41499 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41501 relayCmd : function(cmd, value){
41503 this.execCmd(cmd, value);
41504 this.fireEvent('editorevent', this);
41505 //this.updateToolbar();
41510 * Executes a Midas editor command directly on the editor document.
41511 * For visual commands, you should use {@link #relayCmd} instead.
41512 * <b>This should only be called after the editor is initialized.</b>
41513 * @param {String} cmd The Midas command
41514 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41516 execCmd : function(cmd, value){
41517 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41524 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41526 * @param {String} text | dom node..
41528 insertAtCursor : function(text)
41533 if(!this.activated){
41539 var r = this.doc.selection.createRange();
41550 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41554 // from jquery ui (MIT licenced)
41556 var win = this.win;
41558 if (win.getSelection && win.getSelection().getRangeAt) {
41559 range = win.getSelection().getRangeAt(0);
41560 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41561 range.insertNode(node);
41562 } else if (win.document.selection && win.document.selection.createRange) {
41563 // no firefox support
41564 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41565 win.document.selection.createRange().pasteHTML(txt);
41567 // no firefox support
41568 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41569 this.execCmd('InsertHTML', txt);
41578 mozKeyPress : function(e){
41580 var c = e.getCharCode(), cmd;
41583 c = String.fromCharCode(c).toLowerCase();
41597 this.cleanUpPaste.defer(100, this);
41605 e.preventDefault();
41613 fixKeys : function(){ // load time branching for fastest keydown performance
41615 return function(e){
41616 var k = e.getKey(), r;
41619 r = this.doc.selection.createRange();
41622 r.pasteHTML('    ');
41629 r = this.doc.selection.createRange();
41631 var target = r.parentElement();
41632 if(!target || target.tagName.toLowerCase() != 'li'){
41634 r.pasteHTML('<br />');
41640 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41641 this.cleanUpPaste.defer(100, this);
41647 }else if(Roo.isOpera){
41648 return function(e){
41649 var k = e.getKey();
41653 this.execCmd('InsertHTML','    ');
41656 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41657 this.cleanUpPaste.defer(100, this);
41662 }else if(Roo.isSafari){
41663 return function(e){
41664 var k = e.getKey();
41668 this.execCmd('InsertText','\t');
41672 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41673 this.cleanUpPaste.defer(100, this);
41681 getAllAncestors: function()
41683 var p = this.getSelectedNode();
41686 a.push(p); // push blank onto stack..
41687 p = this.getParentElement();
41691 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41695 a.push(this.doc.body);
41699 lastSelNode : false,
41702 getSelection : function()
41704 this.assignDocWin();
41705 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41708 getSelectedNode: function()
41710 // this may only work on Gecko!!!
41712 // should we cache this!!!!
41717 var range = this.createRange(this.getSelection()).cloneRange();
41720 var parent = range.parentElement();
41722 var testRange = range.duplicate();
41723 testRange.moveToElementText(parent);
41724 if (testRange.inRange(range)) {
41727 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41730 parent = parent.parentElement;
41735 // is ancestor a text element.
41736 var ac = range.commonAncestorContainer;
41737 if (ac.nodeType == 3) {
41738 ac = ac.parentNode;
41741 var ar = ac.childNodes;
41744 var other_nodes = [];
41745 var has_other_nodes = false;
41746 for (var i=0;i<ar.length;i++) {
41747 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41750 // fullly contained node.
41752 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41757 // probably selected..
41758 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41759 other_nodes.push(ar[i]);
41763 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41768 has_other_nodes = true;
41770 if (!nodes.length && other_nodes.length) {
41771 nodes= other_nodes;
41773 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41779 createRange: function(sel)
41781 // this has strange effects when using with
41782 // top toolbar - not sure if it's a great idea.
41783 //this.editor.contentWindow.focus();
41784 if (typeof sel != "undefined") {
41786 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41788 return this.doc.createRange();
41791 return this.doc.createRange();
41794 getParentElement: function()
41797 this.assignDocWin();
41798 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41800 var range = this.createRange(sel);
41803 var p = range.commonAncestorContainer;
41804 while (p.nodeType == 3) { // text node
41815 * Range intersection.. the hard stuff...
41819 * [ -- selected range --- ]
41823 * if end is before start or hits it. fail.
41824 * if start is after end or hits it fail.
41826 * if either hits (but other is outside. - then it's not
41832 // @see http://www.thismuchiknow.co.uk/?p=64.
41833 rangeIntersectsNode : function(range, node)
41835 var nodeRange = node.ownerDocument.createRange();
41837 nodeRange.selectNode(node);
41839 nodeRange.selectNodeContents(node);
41842 var rangeStartRange = range.cloneRange();
41843 rangeStartRange.collapse(true);
41845 var rangeEndRange = range.cloneRange();
41846 rangeEndRange.collapse(false);
41848 var nodeStartRange = nodeRange.cloneRange();
41849 nodeStartRange.collapse(true);
41851 var nodeEndRange = nodeRange.cloneRange();
41852 nodeEndRange.collapse(false);
41854 return rangeStartRange.compareBoundaryPoints(
41855 Range.START_TO_START, nodeEndRange) == -1 &&
41856 rangeEndRange.compareBoundaryPoints(
41857 Range.START_TO_START, nodeStartRange) == 1;
41861 rangeCompareNode : function(range, node)
41863 var nodeRange = node.ownerDocument.createRange();
41865 nodeRange.selectNode(node);
41867 nodeRange.selectNodeContents(node);
41871 range.collapse(true);
41873 nodeRange.collapse(true);
41875 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41876 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41878 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41880 var nodeIsBefore = ss == 1;
41881 var nodeIsAfter = ee == -1;
41883 if (nodeIsBefore && nodeIsAfter)
41885 if (!nodeIsBefore && nodeIsAfter)
41886 return 1; //right trailed.
41888 if (nodeIsBefore && !nodeIsAfter)
41889 return 2; // left trailed.
41894 // private? - in a new class?
41895 cleanUpPaste : function()
41897 // cleans up the whole document..
41898 Roo.log('cleanuppaste');
41899 this.cleanUpChildren(this.doc.body);
41900 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41901 if (clean != this.doc.body.innerHTML) {
41902 this.doc.body.innerHTML = clean;
41907 cleanWordChars : function(input) {// change the chars to hex code
41908 var he = Roo.form.HtmlEditor;
41910 var output = input;
41911 Roo.each(he.swapCodes, function(sw) {
41912 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41914 output = output.replace(swapper, sw[1]);
41921 cleanUpChildren : function (n)
41923 if (!n.childNodes.length) {
41926 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41927 this.cleanUpChild(n.childNodes[i]);
41934 cleanUpChild : function (node)
41937 //console.log(node);
41938 if (node.nodeName == "#text") {
41939 // clean up silly Windows -- stuff?
41942 if (node.nodeName == "#comment") {
41943 node.parentNode.removeChild(node);
41944 // clean up silly Windows -- stuff?
41948 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
41950 node.parentNode.removeChild(node);
41955 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
41957 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41958 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41960 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41961 // remove_keep_children = true;
41964 if (remove_keep_children) {
41965 this.cleanUpChildren(node);
41966 // inserts everything just before this node...
41967 while (node.childNodes.length) {
41968 var cn = node.childNodes[0];
41969 node.removeChild(cn);
41970 node.parentNode.insertBefore(cn, node);
41972 node.parentNode.removeChild(node);
41976 if (!node.attributes || !node.attributes.length) {
41977 this.cleanUpChildren(node);
41981 function cleanAttr(n,v)
41984 if (v.match(/^\./) || v.match(/^\//)) {
41987 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41990 if (v.match(/^#/)) {
41993 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41994 node.removeAttribute(n);
41998 function cleanStyle(n,v)
42000 if (v.match(/expression/)) { //XSS?? should we even bother..
42001 node.removeAttribute(n);
42004 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.form.HtmlEditor.cwhite : ed.cwhite;
42005 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.form.HtmlEditor.cblack : ed.cblack;
42008 var parts = v.split(/;/);
42011 Roo.each(parts, function(p) {
42012 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42016 var l = p.split(':').shift().replace(/\s+/g,'');
42017 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42020 if ( cblack.indexOf(l) > -1) {
42021 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42022 //node.removeAttribute(n);
42026 // only allow 'c whitelisted system attributes'
42027 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42028 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42029 //node.removeAttribute(n);
42039 if (clean.length) {
42040 node.setAttribute(n, clean.join(';'));
42042 node.removeAttribute(n);
42048 for (var i = node.attributes.length-1; i > -1 ; i--) {
42049 var a = node.attributes[i];
42052 if (a.name.toLowerCase().substr(0,2)=='on') {
42053 node.removeAttribute(a.name);
42056 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
42057 node.removeAttribute(a.name);
42060 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
42061 cleanAttr(a.name,a.value); // fixme..
42064 if (a.name == 'style') {
42065 cleanStyle(a.name,a.value);
42068 /// clean up MS crap..
42069 // tecnically this should be a list of valid class'es..
42072 if (a.name == 'class') {
42073 if (a.value.match(/^Mso/)) {
42074 node.className = '';
42077 if (a.value.match(/body/)) {
42078 node.className = '';
42089 this.cleanUpChildren(node);
42095 // hide stuff that is not compatible
42109 * @event specialkey
42113 * @cfg {String} fieldClass @hide
42116 * @cfg {String} focusClass @hide
42119 * @cfg {String} autoCreate @hide
42122 * @cfg {String} inputType @hide
42125 * @cfg {String} invalidClass @hide
42128 * @cfg {String} invalidText @hide
42131 * @cfg {String} msgFx @hide
42134 * @cfg {String} validateOnBlur @hide
42138 Roo.form.HtmlEditor.white = [
42139 'area', 'br', 'img', 'input', 'hr', 'wbr',
42141 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42142 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42143 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42144 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42145 'table', 'ul', 'xmp',
42147 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42150 'dir', 'menu', 'ol', 'ul', 'dl',
42156 Roo.form.HtmlEditor.black = [
42157 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42159 'base', 'basefont', 'bgsound', 'blink', 'body',
42160 'frame', 'frameset', 'head', 'html', 'ilayer',
42161 'iframe', 'layer', 'link', 'meta', 'object',
42162 'script', 'style' ,'title', 'xml' // clean later..
42164 Roo.form.HtmlEditor.clean = [
42165 'script', 'style', 'title', 'xml'
42167 Roo.form.HtmlEditor.remove = [
42172 Roo.form.HtmlEditor.ablack = [
42176 Roo.form.HtmlEditor.aclean = [
42177 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42181 Roo.form.HtmlEditor.pwhite= [
42182 'http', 'https', 'mailto'
42185 // white listed style attributes.
42186 Roo.form.HtmlEditor.cwhite= [
42187 // 'text-align', /// default is to allow most things..
42193 // black listed style attributes.
42194 Roo.form.HtmlEditor.cblack= [
42195 // 'font-size' -- this can be set by the project
42199 Roo.form.HtmlEditor.swapCodes =[
42210 // <script type="text/javascript">
42213 * Ext JS Library 1.1.1
42214 * Copyright(c) 2006-2007, Ext JS, LLC.
42220 * @class Roo.form.HtmlEditorToolbar1
42225 new Roo.form.HtmlEditor({
42228 new Roo.form.HtmlEditorToolbar1({
42229 disable : { fonts: 1 , format: 1, ..., ... , ...],
42235 * @cfg {Object} disable List of elements to disable..
42236 * @cfg {Array} btns List of additional buttons.
42240 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42243 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42246 Roo.apply(this, config);
42248 // default disabled, based on 'good practice'..
42249 this.disable = this.disable || {};
42250 Roo.applyIf(this.disable, {
42253 specialElements : true
42257 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42258 // dont call parent... till later.
42261 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42269 * @cfg {Object} disable List of toolbar elements to disable
42274 * @cfg {Array} fontFamilies An array of available font families
42292 // "á" , ?? a acute?
42297 "°" // , // degrees
42299 // "é" , // e ecute
42300 // "ú" , // u ecute?
42303 specialElements : [
42305 text: "Insert Table",
42308 ihtml : '<table><tr><td>Cell</td></tr></table>'
42312 text: "Insert Image",
42315 ihtml : '<img src="about:blank"/>'
42324 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42325 "input:submit", "input:button", "select", "textarea", "label" ],
42328 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42330 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42338 * @cfg {String} defaultFont default font to use.
42340 defaultFont: 'tahoma',
42342 fontSelect : false,
42345 formatCombo : false,
42347 init : function(editor)
42349 this.editor = editor;
42352 var fid = editor.frameId;
42354 function btn(id, toggle, handler){
42355 var xid = fid + '-'+ id ;
42359 cls : 'x-btn-icon x-edit-'+id,
42360 enableToggle:toggle !== false,
42361 scope: editor, // was editor...
42362 handler:handler||editor.relayBtnCmd,
42363 clickEvent:'mousedown',
42364 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42371 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
42373 // stop form submits
42374 tb.el.on('click', function(e){
42375 e.preventDefault(); // what does this do?
42378 if(!this.disable.font) { // && !Roo.isSafari){
42379 /* why no safari for fonts
42380 editor.fontSelect = tb.el.createChild({
42383 cls:'x-font-select',
42384 html: this.createFontOptions()
42387 editor.fontSelect.on('change', function(){
42388 var font = editor.fontSelect.dom.value;
42389 editor.relayCmd('fontname', font);
42390 editor.deferFocus();
42394 editor.fontSelect.dom,
42400 if(!this.disable.formats){
42401 this.formatCombo = new Roo.form.ComboBox({
42402 store: new Roo.data.SimpleStore({
42405 data : this.formats // from states.js
42409 //autoCreate : {tag: "div", size: "20"},
42410 displayField:'tag',
42414 triggerAction: 'all',
42415 emptyText:'Add tag',
42416 selectOnFocus:true,
42419 'select': function(c, r, i) {
42420 editor.insertTag(r.get('tag'));
42426 tb.addField(this.formatCombo);
42430 if(!this.disable.format){
42437 if(!this.disable.fontSize){
42442 btn('increasefontsize', false, editor.adjustFont),
42443 btn('decreasefontsize', false, editor.adjustFont)
42448 if(!this.disable.colors){
42451 id:editor.frameId +'-forecolor',
42452 cls:'x-btn-icon x-edit-forecolor',
42453 clickEvent:'mousedown',
42454 tooltip: this.buttonTips['forecolor'] || undefined,
42456 menu : new Roo.menu.ColorMenu({
42457 allowReselect: true,
42458 focus: Roo.emptyFn,
42461 selectHandler: function(cp, color){
42462 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
42463 editor.deferFocus();
42466 clickEvent:'mousedown'
42469 id:editor.frameId +'backcolor',
42470 cls:'x-btn-icon x-edit-backcolor',
42471 clickEvent:'mousedown',
42472 tooltip: this.buttonTips['backcolor'] || undefined,
42474 menu : new Roo.menu.ColorMenu({
42475 focus: Roo.emptyFn,
42478 allowReselect: true,
42479 selectHandler: function(cp, color){
42481 editor.execCmd('useCSS', false);
42482 editor.execCmd('hilitecolor', color);
42483 editor.execCmd('useCSS', true);
42484 editor.deferFocus();
42486 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
42487 Roo.isSafari || Roo.isIE ? '#'+color : color);
42488 editor.deferFocus();
42492 clickEvent:'mousedown'
42497 // now add all the items...
42500 if(!this.disable.alignments){
42503 btn('justifyleft'),
42504 btn('justifycenter'),
42505 btn('justifyright')
42509 //if(!Roo.isSafari){
42510 if(!this.disable.links){
42513 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
42517 if(!this.disable.lists){
42520 btn('insertorderedlist'),
42521 btn('insertunorderedlist')
42524 if(!this.disable.sourceEdit){
42527 btn('sourceedit', true, function(btn){
42528 this.toggleSourceEdit(btn.pressed);
42535 // special menu.. - needs to be tidied up..
42536 if (!this.disable.special) {
42539 cls: 'x-edit-none',
42545 for (var i =0; i < this.specialChars.length; i++) {
42546 smenu.menu.items.push({
42548 html: this.specialChars[i],
42549 handler: function(a,b) {
42550 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
42551 //editor.insertAtCursor(a.html);
42565 if (!this.disable.cleanStyles) {
42567 cls: 'x-btn-icon x-btn-clear',
42573 for (var i =0; i < this.cleanStyles.length; i++) {
42574 cmenu.menu.items.push({
42575 actiontype : this.cleanStyles[i],
42576 html: 'Remove ' + this.cleanStyles[i],
42577 handler: function(a,b) {
42580 var c = Roo.get(editor.doc.body);
42581 c.select('[style]').each(function(s) {
42582 s.dom.style.removeProperty(a.actiontype);
42593 if (!this.disable.specialElements) {
42596 cls: 'x-edit-none',
42601 for (var i =0; i < this.specialElements.length; i++) {
42602 semenu.menu.items.push(
42604 handler: function(a,b) {
42605 editor.insertAtCursor(this.ihtml);
42607 }, this.specialElements[i])
42619 for(var i =0; i< this.btns.length;i++) {
42620 var b = Roo.factory(this.btns[i],Roo.form);
42621 b.cls = 'x-edit-none';
42630 // disable everything...
42632 this.tb.items.each(function(item){
42633 if(item.id != editor.frameId+ '-sourceedit'){
42637 this.rendered = true;
42639 // the all the btns;
42640 editor.on('editorevent', this.updateToolbar, this);
42641 // other toolbars need to implement this..
42642 //editor.on('editmodechange', this.updateToolbar, this);
42648 * Protected method that will not generally be called directly. It triggers
42649 * a toolbar update by reading the markup state of the current selection in the editor.
42651 updateToolbar: function(){
42653 if(!this.editor.activated){
42654 this.editor.onFirstFocus();
42658 var btns = this.tb.items.map,
42659 doc = this.editor.doc,
42660 frameId = this.editor.frameId;
42662 if(!this.disable.font && !Roo.isSafari){
42664 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
42665 if(name != this.fontSelect.dom.value){
42666 this.fontSelect.dom.value = name;
42670 if(!this.disable.format){
42671 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
42672 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
42673 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
42675 if(!this.disable.alignments){
42676 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
42677 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
42678 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
42680 if(!Roo.isSafari && !this.disable.lists){
42681 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
42682 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
42685 var ans = this.editor.getAllAncestors();
42686 if (this.formatCombo) {
42689 var store = this.formatCombo.store;
42690 this.formatCombo.setValue("");
42691 for (var i =0; i < ans.length;i++) {
42692 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
42694 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
42702 // hides menus... - so this cant be on a menu...
42703 Roo.menu.MenuMgr.hideAll();
42705 //this.editorsyncValue();
42709 createFontOptions : function(){
42710 var buf = [], fs = this.fontFamilies, ff, lc;
42714 for(var i = 0, len = fs.length; i< len; i++){
42716 lc = ff.toLowerCase();
42718 '<option value="',lc,'" style="font-family:',ff,';"',
42719 (this.defaultFont == lc ? ' selected="true">' : '>'),
42724 return buf.join('');
42727 toggleSourceEdit : function(sourceEditMode){
42728 if(sourceEditMode === undefined){
42729 sourceEditMode = !this.sourceEditMode;
42731 this.sourceEditMode = sourceEditMode === true;
42732 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
42733 // just toggle the button?
42734 if(btn.pressed !== this.editor.sourceEditMode){
42735 btn.toggle(this.editor.sourceEditMode);
42739 if(this.sourceEditMode){
42740 this.tb.items.each(function(item){
42741 if(item.cmd != 'sourceedit'){
42747 if(this.initialized){
42748 this.tb.items.each(function(item){
42754 // tell the editor that it's been pressed..
42755 this.editor.toggleSourceEdit(sourceEditMode);
42759 * Object collection of toolbar tooltips for the buttons in the editor. The key
42760 * is the command id associated with that button and the value is a valid QuickTips object.
42765 title: 'Bold (Ctrl+B)',
42766 text: 'Make the selected text bold.',
42767 cls: 'x-html-editor-tip'
42770 title: 'Italic (Ctrl+I)',
42771 text: 'Make the selected text italic.',
42772 cls: 'x-html-editor-tip'
42780 title: 'Bold (Ctrl+B)',
42781 text: 'Make the selected text bold.',
42782 cls: 'x-html-editor-tip'
42785 title: 'Italic (Ctrl+I)',
42786 text: 'Make the selected text italic.',
42787 cls: 'x-html-editor-tip'
42790 title: 'Underline (Ctrl+U)',
42791 text: 'Underline the selected text.',
42792 cls: 'x-html-editor-tip'
42794 increasefontsize : {
42795 title: 'Grow Text',
42796 text: 'Increase the font size.',
42797 cls: 'x-html-editor-tip'
42799 decreasefontsize : {
42800 title: 'Shrink Text',
42801 text: 'Decrease the font size.',
42802 cls: 'x-html-editor-tip'
42805 title: 'Text Highlight Color',
42806 text: 'Change the background color of the selected text.',
42807 cls: 'x-html-editor-tip'
42810 title: 'Font Color',
42811 text: 'Change the color of the selected text.',
42812 cls: 'x-html-editor-tip'
42815 title: 'Align Text Left',
42816 text: 'Align text to the left.',
42817 cls: 'x-html-editor-tip'
42820 title: 'Center Text',
42821 text: 'Center text in the editor.',
42822 cls: 'x-html-editor-tip'
42825 title: 'Align Text Right',
42826 text: 'Align text to the right.',
42827 cls: 'x-html-editor-tip'
42829 insertunorderedlist : {
42830 title: 'Bullet List',
42831 text: 'Start a bulleted list.',
42832 cls: 'x-html-editor-tip'
42834 insertorderedlist : {
42835 title: 'Numbered List',
42836 text: 'Start a numbered list.',
42837 cls: 'x-html-editor-tip'
42840 title: 'Hyperlink',
42841 text: 'Make the selected text a hyperlink.',
42842 cls: 'x-html-editor-tip'
42845 title: 'Source Edit',
42846 text: 'Switch to source editing mode.',
42847 cls: 'x-html-editor-tip'
42851 onDestroy : function(){
42854 this.tb.items.each(function(item){
42856 item.menu.removeAll();
42858 item.menu.el.destroy();
42866 onFirstFocus: function() {
42867 this.tb.items.each(function(item){
42876 // <script type="text/javascript">
42879 * Ext JS Library 1.1.1
42880 * Copyright(c) 2006-2007, Ext JS, LLC.
42887 * @class Roo.form.HtmlEditor.ToolbarContext
42892 new Roo.form.HtmlEditor({
42895 { xtype: 'ToolbarStandard', styles : {} }
42896 { xtype: 'ToolbarContext', disable : {} }
42902 * @config : {Object} disable List of elements to disable.. (not done yet.)
42903 * @config : {Object} styles Map of styles available.
42907 Roo.form.HtmlEditor.ToolbarContext = function(config)
42910 Roo.apply(this, config);
42911 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42912 // dont call parent... till later.
42913 this.styles = this.styles || {};
42918 Roo.form.HtmlEditor.ToolbarContext.types = {
42930 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42996 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43001 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43011 style : 'fontFamily',
43012 displayField: 'display',
43013 optname : 'font-family',
43062 // should we really allow this??
43063 // should this just be
43074 style : 'fontFamily',
43075 displayField: 'display',
43076 optname : 'font-family',
43083 style : 'fontFamily',
43084 displayField: 'display',
43085 optname : 'font-family',
43092 style : 'fontFamily',
43093 displayField: 'display',
43094 optname : 'font-family',
43105 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43106 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43108 Roo.form.HtmlEditor.ToolbarContext.options = {
43110 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43111 [ 'Courier New', 'Courier New'],
43112 [ 'Tahoma', 'Tahoma'],
43113 [ 'Times New Roman,serif', 'Times'],
43114 [ 'Verdana','Verdana' ]
43118 // fixme - these need to be configurable..
43121 Roo.form.HtmlEditor.ToolbarContext.types
43124 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43132 * @cfg {Object} disable List of toolbar elements to disable
43137 * @cfg {Object} styles List of styles
43138 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43140 * These must be defined in the page, so they get rendered correctly..
43151 init : function(editor)
43153 this.editor = editor;
43156 var fid = editor.frameId;
43158 function btn(id, toggle, handler){
43159 var xid = fid + '-'+ id ;
43163 cls : 'x-btn-icon x-edit-'+id,
43164 enableToggle:toggle !== false,
43165 scope: editor, // was editor...
43166 handler:handler||editor.relayBtnCmd,
43167 clickEvent:'mousedown',
43168 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43172 // create a new element.
43173 var wdiv = editor.wrap.createChild({
43175 }, editor.wrap.dom.firstChild.nextSibling, true);
43177 // can we do this more than once??
43179 // stop form submits
43182 // disable everything...
43183 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43184 this.toolbars = {};
43186 for (var i in ty) {
43188 this.toolbars[i] = this.buildToolbar(ty[i],i);
43190 this.tb = this.toolbars.BODY;
43192 this.buildFooter();
43193 this.footer.show();
43194 editor.on('hide', function( ) { this.footer.hide() }, this);
43195 editor.on('show', function( ) { this.footer.show() }, this);
43198 this.rendered = true;
43200 // the all the btns;
43201 editor.on('editorevent', this.updateToolbar, this);
43202 // other toolbars need to implement this..
43203 //editor.on('editmodechange', this.updateToolbar, this);
43209 * Protected method that will not generally be called directly. It triggers
43210 * a toolbar update by reading the markup state of the current selection in the editor.
43212 updateToolbar: function(editor,ev,sel){
43215 // capture mouse up - this is handy for selecting images..
43216 // perhaps should go somewhere else...
43217 if(!this.editor.activated){
43218 this.editor.onFirstFocus();
43222 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43223 // selectNode - might want to handle IE?
43225 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43226 ev.target && ev.target.tagName == 'IMG') {
43227 // they have click on an image...
43228 // let's see if we can change the selection...
43231 var nodeRange = sel.ownerDocument.createRange();
43233 nodeRange.selectNode(sel);
43235 nodeRange.selectNodeContents(sel);
43237 //nodeRange.collapse(true);
43238 var s = editor.win.getSelection();
43239 s.removeAllRanges();
43240 s.addRange(nodeRange);
43244 var updateFooter = sel ? false : true;
43247 var ans = this.editor.getAllAncestors();
43250 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43253 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
43254 sel = sel ? sel : this.editor.doc.body;
43255 sel = sel.tagName.length ? sel : this.editor.doc.body;
43258 // pick a menu that exists..
43259 var tn = sel.tagName.toUpperCase();
43260 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43262 tn = sel.tagName.toUpperCase();
43264 var lastSel = this.tb.selectedNode
43266 this.tb.selectedNode = sel;
43268 // if current menu does not match..
43269 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43272 ///console.log("show: " + tn);
43273 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43276 this.tb.items.first().el.innerHTML = tn + ': ';
43279 // update attributes
43280 if (this.tb.fields) {
43281 this.tb.fields.each(function(e) {
43283 e.setValue(sel.style[e.stylename]);
43286 e.setValue(sel.getAttribute(e.attrname));
43290 var hasStyles = false;
43291 for(var i in this.styles) {
43298 var st = this.tb.fields.item(0);
43300 st.store.removeAll();
43303 var cn = sel.className.split(/\s+/);
43306 if (this.styles['*']) {
43308 Roo.each(this.styles['*'], function(v) {
43309 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43312 if (this.styles[tn]) {
43313 Roo.each(this.styles[tn], function(v) {
43314 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43318 st.store.loadData(avs);
43322 // flag our selected Node.
43323 this.tb.selectedNode = sel;
43326 Roo.menu.MenuMgr.hideAll();
43330 if (!updateFooter) {
43331 //this.footDisp.dom.innerHTML = '';
43334 // update the footer
43338 this.footerEls = ans.reverse();
43339 Roo.each(this.footerEls, function(a,i) {
43340 if (!a) { return; }
43341 html += html.length ? ' > ' : '';
43343 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
43348 var sz = this.footDisp.up('td').getSize();
43349 this.footDisp.dom.style.width = (sz.width -10) + 'px';
43350 this.footDisp.dom.style.marginLeft = '5px';
43352 this.footDisp.dom.style.overflow = 'hidden';
43354 this.footDisp.dom.innerHTML = html;
43356 //this.editorsyncValue();
43363 onDestroy : function(){
43366 this.tb.items.each(function(item){
43368 item.menu.removeAll();
43370 item.menu.el.destroy();
43378 onFirstFocus: function() {
43379 // need to do this for all the toolbars..
43380 this.tb.items.each(function(item){
43384 buildToolbar: function(tlist, nm)
43386 var editor = this.editor;
43387 // create a new element.
43388 var wdiv = editor.wrap.createChild({
43390 }, editor.wrap.dom.firstChild.nextSibling, true);
43393 var tb = new Roo.Toolbar(wdiv);
43396 tb.add(nm+ ": ");
43399 for(var i in this.styles) {
43404 if (styles && styles.length) {
43406 // this needs a multi-select checkbox...
43407 tb.addField( new Roo.form.ComboBox({
43408 store: new Roo.data.SimpleStore({
43410 fields: ['val', 'selected'],
43413 name : '-roo-edit-className',
43414 attrname : 'className',
43415 displayField: 'val',
43419 triggerAction: 'all',
43420 emptyText:'Select Style',
43421 selectOnFocus:true,
43424 'select': function(c, r, i) {
43425 // initial support only for on class per el..
43426 tb.selectedNode.className = r ? r.get('val') : '';
43427 editor.syncValue();
43434 var tbc = Roo.form.HtmlEditor.ToolbarContext;
43435 var tbops = tbc.options;
43437 for (var i in tlist) {
43439 var item = tlist[i];
43440 tb.add(item.title + ": ");
43443 //optname == used so you can configure the options available..
43444 var opts = item.opts ? item.opts : false;
43445 if (item.optname) {
43446 opts = tbops[item.optname];
43451 // opts == pulldown..
43452 tb.addField( new Roo.form.ComboBox({
43453 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
43455 fields: ['val', 'display'],
43458 name : '-roo-edit-' + i,
43460 stylename : item.style ? item.style : false,
43461 displayField: item.displayField ? item.displayField : 'val',
43462 valueField : 'val',
43464 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
43466 triggerAction: 'all',
43467 emptyText:'Select',
43468 selectOnFocus:true,
43469 width: item.width ? item.width : 130,
43471 'select': function(c, r, i) {
43473 tb.selectedNode.style[c.stylename] = r.get('val');
43476 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
43485 tb.addField( new Roo.form.TextField({
43488 //allowBlank:false,
43493 tb.addField( new Roo.form.TextField({
43494 name: '-roo-edit-' + i,
43501 'change' : function(f, nv, ov) {
43502 tb.selectedNode.setAttribute(f.attrname, nv);
43511 text: 'Remove Tag',
43514 click : function ()
43517 // undo does not work.
43519 var sn = tb.selectedNode;
43521 var pn = sn.parentNode;
43523 var stn = sn.childNodes[0];
43524 var en = sn.childNodes[sn.childNodes.length - 1 ];
43525 while (sn.childNodes.length) {
43526 var node = sn.childNodes[0];
43527 sn.removeChild(node);
43529 pn.insertBefore(node, sn);
43532 pn.removeChild(sn);
43533 var range = editor.createRange();
43535 range.setStart(stn,0);
43536 range.setEnd(en,0); //????
43537 //range.selectNode(sel);
43540 var selection = editor.getSelection();
43541 selection.removeAllRanges();
43542 selection.addRange(range);
43546 //_this.updateToolbar(null, null, pn);
43547 _this.updateToolbar(null, null, null);
43548 _this.footDisp.dom.innerHTML = '';
43558 tb.el.on('click', function(e){
43559 e.preventDefault(); // what does this do?
43561 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
43564 // dont need to disable them... as they will get hidden
43569 buildFooter : function()
43572 var fel = this.editor.wrap.createChild();
43573 this.footer = new Roo.Toolbar(fel);
43574 // toolbar has scrolly on left / right?
43575 var footDisp= new Roo.Toolbar.Fill();
43581 handler : function() {
43582 _t.footDisp.scrollTo('left',0,true)
43586 this.footer.add( footDisp );
43591 handler : function() {
43593 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
43597 var fel = Roo.get(footDisp.el);
43598 fel.addClass('x-editor-context');
43599 this.footDispWrap = fel;
43600 this.footDispWrap.overflow = 'hidden';
43602 this.footDisp = fel.createChild();
43603 this.footDispWrap.on('click', this.onContextClick, this)
43607 onContextClick : function (ev,dom)
43609 ev.preventDefault();
43610 var cn = dom.className;
43612 if (!cn.match(/x-ed-loc-/)) {
43615 var n = cn.split('-').pop();
43616 var ans = this.footerEls;
43620 var range = this.editor.createRange();
43622 range.selectNodeContents(sel);
43623 //range.selectNode(sel);
43626 var selection = this.editor.getSelection();
43627 selection.removeAllRanges();
43628 selection.addRange(range);
43632 this.updateToolbar(null, null, sel);
43649 * Ext JS Library 1.1.1
43650 * Copyright(c) 2006-2007, Ext JS, LLC.
43652 * Originally Released Under LGPL - original licence link has changed is not relivant.
43655 * <script type="text/javascript">
43659 * @class Roo.form.BasicForm
43660 * @extends Roo.util.Observable
43661 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
43663 * @param {String/HTMLElement/Roo.Element} el The form element or its id
43664 * @param {Object} config Configuration options
43666 Roo.form.BasicForm = function(el, config){
43667 this.allItems = [];
43668 this.childForms = [];
43669 Roo.apply(this, config);
43671 * The Roo.form.Field items in this form.
43672 * @type MixedCollection
43676 this.items = new Roo.util.MixedCollection(false, function(o){
43677 return o.id || (o.id = Roo.id());
43681 * @event beforeaction
43682 * Fires before any action is performed. Return false to cancel the action.
43683 * @param {Form} this
43684 * @param {Action} action The action to be performed
43686 beforeaction: true,
43688 * @event actionfailed
43689 * Fires when an action fails.
43690 * @param {Form} this
43691 * @param {Action} action The action that failed
43693 actionfailed : true,
43695 * @event actioncomplete
43696 * Fires when an action is completed.
43697 * @param {Form} this
43698 * @param {Action} action The action that completed
43700 actioncomplete : true
43705 Roo.form.BasicForm.superclass.constructor.call(this);
43708 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
43710 * @cfg {String} method
43711 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
43714 * @cfg {DataReader} reader
43715 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
43716 * This is optional as there is built-in support for processing JSON.
43719 * @cfg {DataReader} errorReader
43720 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
43721 * This is completely optional as there is built-in support for processing JSON.
43724 * @cfg {String} url
43725 * The URL to use for form actions if one isn't supplied in the action options.
43728 * @cfg {Boolean} fileUpload
43729 * Set to true if this form is a file upload.
43733 * @cfg {Object} baseParams
43734 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
43739 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
43744 activeAction : null,
43747 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
43748 * or setValues() data instead of when the form was first created.
43750 trackResetOnLoad : false,
43754 * childForms - used for multi-tab forms
43757 childForms : false,
43760 * allItems - full list of fields.
43766 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
43767 * element by passing it or its id or mask the form itself by passing in true.
43770 waitMsgTarget : false,
43773 initEl : function(el){
43774 this.el = Roo.get(el);
43775 this.id = this.el.id || Roo.id();
43776 this.el.on('submit', this.onSubmit, this);
43777 this.el.addClass('x-form');
43781 onSubmit : function(e){
43786 * Returns true if client-side validation on the form is successful.
43789 isValid : function(){
43791 this.items.each(function(f){
43800 * Returns true if any fields in this form have changed since their original load.
43803 isDirty : function(){
43805 this.items.each(function(f){
43815 * Performs a predefined action (submit or load) or custom actions you define on this form.
43816 * @param {String} actionName The name of the action type
43817 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
43818 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
43819 * accept other config options):
43821 Property Type Description
43822 ---------------- --------------- ----------------------------------------------------------------------------------
43823 url String The url for the action (defaults to the form's url)
43824 method String The form method to use (defaults to the form's method, or POST if not defined)
43825 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
43826 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
43827 validate the form on the client (defaults to false)
43829 * @return {BasicForm} this
43831 doAction : function(action, options){
43832 if(typeof action == 'string'){
43833 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
43835 if(this.fireEvent('beforeaction', this, action) !== false){
43836 this.beforeAction(action);
43837 action.run.defer(100, action);
43843 * Shortcut to do a submit action.
43844 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43845 * @return {BasicForm} this
43847 submit : function(options){
43848 this.doAction('submit', options);
43853 * Shortcut to do a load action.
43854 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43855 * @return {BasicForm} this
43857 load : function(options){
43858 this.doAction('load', options);
43863 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
43864 * @param {Record} record The record to edit
43865 * @return {BasicForm} this
43867 updateRecord : function(record){
43868 record.beginEdit();
43869 var fs = record.fields;
43870 fs.each(function(f){
43871 var field = this.findField(f.name);
43873 record.set(f.name, field.getValue());
43881 * Loads an Roo.data.Record into this form.
43882 * @param {Record} record The record to load
43883 * @return {BasicForm} this
43885 loadRecord : function(record){
43886 this.setValues(record.data);
43891 beforeAction : function(action){
43892 var o = action.options;
43895 if(this.waitMsgTarget === true){
43896 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
43897 }else if(this.waitMsgTarget){
43898 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
43899 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
43901 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
43907 afterAction : function(action, success){
43908 this.activeAction = null;
43909 var o = action.options;
43911 if(this.waitMsgTarget === true){
43913 }else if(this.waitMsgTarget){
43914 this.waitMsgTarget.unmask();
43916 Roo.MessageBox.updateProgress(1);
43917 Roo.MessageBox.hide();
43924 Roo.callback(o.success, o.scope, [this, action]);
43925 this.fireEvent('actioncomplete', this, action);
43929 // failure condition..
43930 // we have a scenario where updates need confirming.
43931 // eg. if a locking scenario exists..
43932 // we look for { errors : { needs_confirm : true }} in the response.
43934 (typeof(action.result) != 'undefined') &&
43935 (typeof(action.result.errors) != 'undefined') &&
43936 (typeof(action.result.errors.needs_confirm) != 'undefined')
43939 Roo.MessageBox.confirm(
43940 "Change requires confirmation",
43941 action.result.errorMsg,
43946 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
43956 Roo.callback(o.failure, o.scope, [this, action]);
43957 // show an error message if no failed handler is set..
43958 if (!this.hasListener('actionfailed')) {
43959 Roo.MessageBox.alert("Error",
43960 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
43961 action.result.errorMsg :
43962 "Saving Failed, please check your entries or try again"
43966 this.fireEvent('actionfailed', this, action);
43972 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
43973 * @param {String} id The value to search for
43976 findField : function(id){
43977 var field = this.items.get(id);
43979 this.items.each(function(f){
43980 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
43986 return field || null;
43990 * Add a secondary form to this one,
43991 * Used to provide tabbed forms. One form is primary, with hidden values
43992 * which mirror the elements from the other forms.
43994 * @param {Roo.form.Form} form to add.
43997 addForm : function(form)
44000 if (this.childForms.indexOf(form) > -1) {
44004 this.childForms.push(form);
44006 Roo.each(form.allItems, function (fe) {
44008 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44009 if (this.findField(n)) { // already added..
44012 var add = new Roo.form.Hidden({
44015 add.render(this.el);
44022 * Mark fields in this form invalid in bulk.
44023 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44024 * @return {BasicForm} this
44026 markInvalid : function(errors){
44027 if(errors instanceof Array){
44028 for(var i = 0, len = errors.length; i < len; i++){
44029 var fieldError = errors[i];
44030 var f = this.findField(fieldError.id);
44032 f.markInvalid(fieldError.msg);
44038 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44039 field.markInvalid(errors[id]);
44043 Roo.each(this.childForms || [], function (f) {
44044 f.markInvalid(errors);
44051 * Set values for fields in this form in bulk.
44052 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44053 * @return {BasicForm} this
44055 setValues : function(values){
44056 if(values instanceof Array){ // array of objects
44057 for(var i = 0, len = values.length; i < len; i++){
44059 var f = this.findField(v.id);
44061 f.setValue(v.value);
44062 if(this.trackResetOnLoad){
44063 f.originalValue = f.getValue();
44067 }else{ // object hash
44070 if(typeof values[id] != 'function' && (field = this.findField(id))){
44072 if (field.setFromData &&
44073 field.valueField &&
44074 field.displayField &&
44075 // combos' with local stores can
44076 // be queried via setValue()
44077 // to set their value..
44078 (field.store && !field.store.isLocal)
44082 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44083 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44084 field.setFromData(sd);
44087 field.setValue(values[id]);
44091 if(this.trackResetOnLoad){
44092 field.originalValue = field.getValue();
44098 Roo.each(this.childForms || [], function (f) {
44099 f.setValues(values);
44106 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44107 * they are returned as an array.
44108 * @param {Boolean} asString
44111 getValues : function(asString){
44112 if (this.childForms) {
44113 // copy values from the child forms
44114 Roo.each(this.childForms, function (f) {
44115 this.setValues(f.getValues());
44121 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44122 if(asString === true){
44125 return Roo.urlDecode(fs);
44129 * Returns the fields in this form as an object with key/value pairs.
44130 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44133 getFieldValues : function(with_hidden)
44135 if (this.childForms) {
44136 // copy values from the child forms
44137 // should this call getFieldValues - probably not as we do not currently copy
44138 // hidden fields when we generate..
44139 Roo.each(this.childForms, function (f) {
44140 this.setValues(f.getValues());
44145 this.items.each(function(f){
44146 if (!f.getName()) {
44149 var v = f.getValue();
44150 if (f.inputType =='radio') {
44151 if (typeof(ret[f.getName()]) == 'undefined') {
44152 ret[f.getName()] = ''; // empty..
44155 if (!f.el.dom.checked) {
44159 v = f.el.dom.value;
44163 // not sure if this supported any more..
44164 if ((typeof(v) == 'object') && f.getRawValue) {
44165 v = f.getRawValue() ; // dates..
44167 // combo boxes where name != hiddenName...
44168 if (f.name != f.getName()) {
44169 ret[f.name] = f.getRawValue();
44171 ret[f.getName()] = v;
44178 * Clears all invalid messages in this form.
44179 * @return {BasicForm} this
44181 clearInvalid : function(){
44182 this.items.each(function(f){
44186 Roo.each(this.childForms || [], function (f) {
44195 * Resets this form.
44196 * @return {BasicForm} this
44198 reset : function(){
44199 this.items.each(function(f){
44203 Roo.each(this.childForms || [], function (f) {
44212 * Add Roo.form components to this form.
44213 * @param {Field} field1
44214 * @param {Field} field2 (optional)
44215 * @param {Field} etc (optional)
44216 * @return {BasicForm} this
44219 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44225 * Removes a field from the items collection (does NOT remove its markup).
44226 * @param {Field} field
44227 * @return {BasicForm} this
44229 remove : function(field){
44230 this.items.remove(field);
44235 * Looks at the fields in this form, checks them for an id attribute,
44236 * and calls applyTo on the existing dom element with that id.
44237 * @return {BasicForm} this
44239 render : function(){
44240 this.items.each(function(f){
44241 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44249 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44250 * @param {Object} values
44251 * @return {BasicForm} this
44253 applyToFields : function(o){
44254 this.items.each(function(f){
44261 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44262 * @param {Object} values
44263 * @return {BasicForm} this
44265 applyIfToFields : function(o){
44266 this.items.each(function(f){
44274 Roo.BasicForm = Roo.form.BasicForm;/*
44276 * Ext JS Library 1.1.1
44277 * Copyright(c) 2006-2007, Ext JS, LLC.
44279 * Originally Released Under LGPL - original licence link has changed is not relivant.
44282 * <script type="text/javascript">
44286 * @class Roo.form.Form
44287 * @extends Roo.form.BasicForm
44288 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44290 * @param {Object} config Configuration options
44292 Roo.form.Form = function(config){
44294 if (config.items) {
44295 xitems = config.items;
44296 delete config.items;
44300 Roo.form.Form.superclass.constructor.call(this, null, config);
44301 this.url = this.url || this.action;
44303 this.root = new Roo.form.Layout(Roo.applyIf({
44307 this.active = this.root;
44309 * Array of all the buttons that have been added to this form via {@link addButton}
44313 this.allItems = [];
44316 * @event clientvalidation
44317 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
44318 * @param {Form} this
44319 * @param {Boolean} valid true if the form has passed client-side validation
44321 clientvalidation: true,
44324 * Fires when the form is rendered
44325 * @param {Roo.form.Form} form
44330 if (this.progressUrl) {
44331 // push a hidden field onto the list of fields..
44335 name : 'UPLOAD_IDENTIFIER'
44340 Roo.each(xitems, this.addxtype, this);
44346 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
44348 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
44351 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
44354 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
44356 buttonAlign:'center',
44359 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
44364 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
44365 * This property cascades to child containers if not set.
44370 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
44371 * fires a looping event with that state. This is required to bind buttons to the valid
44372 * state using the config value formBind:true on the button.
44374 monitorValid : false,
44377 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
44382 * @cfg {String} progressUrl - Url to return progress data
44385 progressUrl : false,
44388 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
44389 * fields are added and the column is closed. If no fields are passed the column remains open
44390 * until end() is called.
44391 * @param {Object} config The config to pass to the column
44392 * @param {Field} field1 (optional)
44393 * @param {Field} field2 (optional)
44394 * @param {Field} etc (optional)
44395 * @return Column The column container object
44397 column : function(c){
44398 var col = new Roo.form.Column(c);
44400 if(arguments.length > 1){ // duplicate code required because of Opera
44401 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44408 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
44409 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
44410 * until end() is called.
44411 * @param {Object} config The config to pass to the fieldset
44412 * @param {Field} field1 (optional)
44413 * @param {Field} field2 (optional)
44414 * @param {Field} etc (optional)
44415 * @return FieldSet The fieldset container object
44417 fieldset : function(c){
44418 var fs = new Roo.form.FieldSet(c);
44420 if(arguments.length > 1){ // duplicate code required because of Opera
44421 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44428 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
44429 * fields are added and the container is closed. If no fields are passed the container remains open
44430 * until end() is called.
44431 * @param {Object} config The config to pass to the Layout
44432 * @param {Field} field1 (optional)
44433 * @param {Field} field2 (optional)
44434 * @param {Field} etc (optional)
44435 * @return Layout The container object
44437 container : function(c){
44438 var l = new Roo.form.Layout(c);
44440 if(arguments.length > 1){ // duplicate code required because of Opera
44441 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44448 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
44449 * @param {Object} container A Roo.form.Layout or subclass of Layout
44450 * @return {Form} this
44452 start : function(c){
44453 // cascade label info
44454 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
44455 this.active.stack.push(c);
44456 c.ownerCt = this.active;
44462 * Closes the current open container
44463 * @return {Form} this
44466 if(this.active == this.root){
44469 this.active = this.active.ownerCt;
44474 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
44475 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
44476 * as the label of the field.
44477 * @param {Field} field1
44478 * @param {Field} field2 (optional)
44479 * @param {Field} etc. (optional)
44480 * @return {Form} this
44483 this.active.stack.push.apply(this.active.stack, arguments);
44484 this.allItems.push.apply(this.allItems,arguments);
44486 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
44487 if(a[i].isFormField){
44492 Roo.form.Form.superclass.add.apply(this, r);
44502 * Find any element that has been added to a form, using it's ID or name
44503 * This can include framesets, columns etc. along with regular fields..
44504 * @param {String} id - id or name to find.
44506 * @return {Element} e - or false if nothing found.
44508 findbyId : function(id)
44514 Roo.each(this.allItems, function(f){
44515 if (f.id == id || f.name == id ){
44526 * Render this form into the passed container. This should only be called once!
44527 * @param {String/HTMLElement/Element} container The element this component should be rendered into
44528 * @return {Form} this
44530 render : function(ct)
44536 var o = this.autoCreate || {
44538 method : this.method || 'POST',
44539 id : this.id || Roo.id()
44541 this.initEl(ct.createChild(o));
44543 this.root.render(this.el);
44547 this.items.each(function(f){
44548 f.render('x-form-el-'+f.id);
44551 if(this.buttons.length > 0){
44552 // tables are required to maintain order and for correct IE layout
44553 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
44554 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
44555 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
44557 var tr = tb.getElementsByTagName('tr')[0];
44558 for(var i = 0, len = this.buttons.length; i < len; i++) {
44559 var b = this.buttons[i];
44560 var td = document.createElement('td');
44561 td.className = 'x-form-btn-td';
44562 b.render(tr.appendChild(td));
44565 if(this.monitorValid){ // initialize after render
44566 this.startMonitoring();
44568 this.fireEvent('rendered', this);
44573 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
44574 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
44575 * object or a valid Roo.DomHelper element config
44576 * @param {Function} handler The function called when the button is clicked
44577 * @param {Object} scope (optional) The scope of the handler function
44578 * @return {Roo.Button}
44580 addButton : function(config, handler, scope){
44584 minWidth: this.minButtonWidth,
44587 if(typeof config == "string"){
44590 Roo.apply(bc, config);
44592 var btn = new Roo.Button(null, bc);
44593 this.buttons.push(btn);
44598 * Adds a series of form elements (using the xtype property as the factory method.
44599 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
44600 * @param {Object} config
44603 addxtype : function()
44605 var ar = Array.prototype.slice.call(arguments, 0);
44607 for(var i = 0; i < ar.length; i++) {
44609 continue; // skip -- if this happends something invalid got sent, we
44610 // should ignore it, as basically that interface element will not show up
44611 // and that should be pretty obvious!!
44614 if (Roo.form[ar[i].xtype]) {
44616 var fe = Roo.factory(ar[i], Roo.form);
44622 fe.store.form = this;
44627 this.allItems.push(fe);
44628 if (fe.items && fe.addxtype) {
44629 fe.addxtype.apply(fe, fe.items);
44639 // console.log('adding ' + ar[i].xtype);
44641 if (ar[i].xtype == 'Button') {
44642 //console.log('adding button');
44643 //console.log(ar[i]);
44644 this.addButton(ar[i]);
44645 this.allItems.push(fe);
44649 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
44650 alert('end is not supported on xtype any more, use items');
44652 // //console.log('adding end');
44660 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
44661 * option "monitorValid"
44663 startMonitoring : function(){
44666 Roo.TaskMgr.start({
44667 run : this.bindHandler,
44668 interval : this.monitorPoll || 200,
44675 * Stops monitoring of the valid state of this form
44677 stopMonitoring : function(){
44678 this.bound = false;
44682 bindHandler : function(){
44684 return false; // stops binding
44687 this.items.each(function(f){
44688 if(!f.isValid(true)){
44693 for(var i = 0, len = this.buttons.length; i < len; i++){
44694 var btn = this.buttons[i];
44695 if(btn.formBind === true && btn.disabled === valid){
44696 btn.setDisabled(!valid);
44699 this.fireEvent('clientvalidation', this, valid);
44713 Roo.Form = Roo.form.Form;
44716 * Ext JS Library 1.1.1
44717 * Copyright(c) 2006-2007, Ext JS, LLC.
44719 * Originally Released Under LGPL - original licence link has changed is not relivant.
44722 * <script type="text/javascript">
44725 // as we use this in bootstrap.
44726 Roo.namespace('Roo.form');
44728 * @class Roo.form.Action
44729 * Internal Class used to handle form actions
44731 * @param {Roo.form.BasicForm} el The form element or its id
44732 * @param {Object} config Configuration options
44737 // define the action interface
44738 Roo.form.Action = function(form, options){
44740 this.options = options || {};
44743 * Client Validation Failed
44746 Roo.form.Action.CLIENT_INVALID = 'client';
44748 * Server Validation Failed
44751 Roo.form.Action.SERVER_INVALID = 'server';
44753 * Connect to Server Failed
44756 Roo.form.Action.CONNECT_FAILURE = 'connect';
44758 * Reading Data from Server Failed
44761 Roo.form.Action.LOAD_FAILURE = 'load';
44763 Roo.form.Action.prototype = {
44765 failureType : undefined,
44766 response : undefined,
44767 result : undefined,
44769 // interface method
44770 run : function(options){
44774 // interface method
44775 success : function(response){
44779 // interface method
44780 handleResponse : function(response){
44784 // default connection failure
44785 failure : function(response){
44787 this.response = response;
44788 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44789 this.form.afterAction(this, false);
44792 processResponse : function(response){
44793 this.response = response;
44794 if(!response.responseText){
44797 this.result = this.handleResponse(response);
44798 return this.result;
44801 // utility functions used internally
44802 getUrl : function(appendParams){
44803 var url = this.options.url || this.form.url || this.form.el.dom.action;
44805 var p = this.getParams();
44807 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
44813 getMethod : function(){
44814 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
44817 getParams : function(){
44818 var bp = this.form.baseParams;
44819 var p = this.options.params;
44821 if(typeof p == "object"){
44822 p = Roo.urlEncode(Roo.applyIf(p, bp));
44823 }else if(typeof p == 'string' && bp){
44824 p += '&' + Roo.urlEncode(bp);
44827 p = Roo.urlEncode(bp);
44832 createCallback : function(){
44834 success: this.success,
44835 failure: this.failure,
44837 timeout: (this.form.timeout*1000),
44838 upload: this.form.fileUpload ? this.success : undefined
44843 Roo.form.Action.Submit = function(form, options){
44844 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
44847 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
44850 haveProgress : false,
44851 uploadComplete : false,
44853 // uploadProgress indicator.
44854 uploadProgress : function()
44856 if (!this.form.progressUrl) {
44860 if (!this.haveProgress) {
44861 Roo.MessageBox.progress("Uploading", "Uploading");
44863 if (this.uploadComplete) {
44864 Roo.MessageBox.hide();
44868 this.haveProgress = true;
44870 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
44872 var c = new Roo.data.Connection();
44874 url : this.form.progressUrl,
44879 success : function(req){
44880 //console.log(data);
44884 rdata = Roo.decode(req.responseText)
44886 Roo.log("Invalid data from server..");
44890 if (!rdata || !rdata.success) {
44892 Roo.MessageBox.alert(Roo.encode(rdata));
44895 var data = rdata.data;
44897 if (this.uploadComplete) {
44898 Roo.MessageBox.hide();
44903 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
44904 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
44907 this.uploadProgress.defer(2000,this);
44910 failure: function(data) {
44911 Roo.log('progress url failed ');
44922 // run get Values on the form, so it syncs any secondary forms.
44923 this.form.getValues();
44925 var o = this.options;
44926 var method = this.getMethod();
44927 var isPost = method == 'POST';
44928 if(o.clientValidation === false || this.form.isValid()){
44930 if (this.form.progressUrl) {
44931 this.form.findField('UPLOAD_IDENTIFIER').setValue(
44932 (new Date() * 1) + '' + Math.random());
44937 Roo.Ajax.request(Roo.apply(this.createCallback(), {
44938 form:this.form.el.dom,
44939 url:this.getUrl(!isPost),
44941 params:isPost ? this.getParams() : null,
44942 isUpload: this.form.fileUpload
44945 this.uploadProgress();
44947 }else if (o.clientValidation !== false){ // client validation failed
44948 this.failureType = Roo.form.Action.CLIENT_INVALID;
44949 this.form.afterAction(this, false);
44953 success : function(response)
44955 this.uploadComplete= true;
44956 if (this.haveProgress) {
44957 Roo.MessageBox.hide();
44961 var result = this.processResponse(response);
44962 if(result === true || result.success){
44963 this.form.afterAction(this, true);
44967 this.form.markInvalid(result.errors);
44968 this.failureType = Roo.form.Action.SERVER_INVALID;
44970 this.form.afterAction(this, false);
44972 failure : function(response)
44974 this.uploadComplete= true;
44975 if (this.haveProgress) {
44976 Roo.MessageBox.hide();
44979 this.response = response;
44980 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44981 this.form.afterAction(this, false);
44984 handleResponse : function(response){
44985 if(this.form.errorReader){
44986 var rs = this.form.errorReader.read(response);
44989 for(var i = 0, len = rs.records.length; i < len; i++) {
44990 var r = rs.records[i];
44991 errors[i] = r.data;
44994 if(errors.length < 1){
44998 success : rs.success,
45004 ret = Roo.decode(response.responseText);
45008 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45018 Roo.form.Action.Load = function(form, options){
45019 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45020 this.reader = this.form.reader;
45023 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45028 Roo.Ajax.request(Roo.apply(
45029 this.createCallback(), {
45030 method:this.getMethod(),
45031 url:this.getUrl(false),
45032 params:this.getParams()
45036 success : function(response){
45038 var result = this.processResponse(response);
45039 if(result === true || !result.success || !result.data){
45040 this.failureType = Roo.form.Action.LOAD_FAILURE;
45041 this.form.afterAction(this, false);
45044 this.form.clearInvalid();
45045 this.form.setValues(result.data);
45046 this.form.afterAction(this, true);
45049 handleResponse : function(response){
45050 if(this.form.reader){
45051 var rs = this.form.reader.read(response);
45052 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45054 success : rs.success,
45058 return Roo.decode(response.responseText);
45062 Roo.form.Action.ACTION_TYPES = {
45063 'load' : Roo.form.Action.Load,
45064 'submit' : Roo.form.Action.Submit
45067 * Ext JS Library 1.1.1
45068 * Copyright(c) 2006-2007, Ext JS, LLC.
45070 * Originally Released Under LGPL - original licence link has changed is not relivant.
45073 * <script type="text/javascript">
45077 * @class Roo.form.Layout
45078 * @extends Roo.Component
45079 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45081 * @param {Object} config Configuration options
45083 Roo.form.Layout = function(config){
45085 if (config.items) {
45086 xitems = config.items;
45087 delete config.items;
45089 Roo.form.Layout.superclass.constructor.call(this, config);
45091 Roo.each(xitems, this.addxtype, this);
45095 Roo.extend(Roo.form.Layout, Roo.Component, {
45097 * @cfg {String/Object} autoCreate
45098 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45101 * @cfg {String/Object/Function} style
45102 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45103 * a function which returns such a specification.
45106 * @cfg {String} labelAlign
45107 * Valid values are "left," "top" and "right" (defaults to "left")
45110 * @cfg {Number} labelWidth
45111 * Fixed width in pixels of all field labels (defaults to undefined)
45114 * @cfg {Boolean} clear
45115 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45119 * @cfg {String} labelSeparator
45120 * The separator to use after field labels (defaults to ':')
45122 labelSeparator : ':',
45124 * @cfg {Boolean} hideLabels
45125 * True to suppress the display of field labels in this layout (defaults to false)
45127 hideLabels : false,
45130 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45135 onRender : function(ct, position){
45136 if(this.el){ // from markup
45137 this.el = Roo.get(this.el);
45138 }else { // generate
45139 var cfg = this.getAutoCreate();
45140 this.el = ct.createChild(cfg, position);
45143 this.el.applyStyles(this.style);
45145 if(this.labelAlign){
45146 this.el.addClass('x-form-label-'+this.labelAlign);
45148 if(this.hideLabels){
45149 this.labelStyle = "display:none";
45150 this.elementStyle = "padding-left:0;";
45152 if(typeof this.labelWidth == 'number'){
45153 this.labelStyle = "width:"+this.labelWidth+"px;";
45154 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45156 if(this.labelAlign == 'top'){
45157 this.labelStyle = "width:auto;";
45158 this.elementStyle = "padding-left:0;";
45161 var stack = this.stack;
45162 var slen = stack.length;
45164 if(!this.fieldTpl){
45165 var t = new Roo.Template(
45166 '<div class="x-form-item {5}">',
45167 '<label for="{0}" style="{2}">{1}{4}</label>',
45168 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45170 '</div><div class="x-form-clear-left"></div>'
45172 t.disableFormats = true;
45174 Roo.form.Layout.prototype.fieldTpl = t;
45176 for(var i = 0; i < slen; i++) {
45177 if(stack[i].isFormField){
45178 this.renderField(stack[i]);
45180 this.renderComponent(stack[i]);
45185 this.el.createChild({cls:'x-form-clear'});
45190 renderField : function(f){
45191 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45194 f.labelStyle||this.labelStyle||'', //2
45195 this.elementStyle||'', //3
45196 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45197 f.itemCls||this.itemCls||'' //5
45198 ], true).getPrevSibling());
45202 renderComponent : function(c){
45203 c.render(c.isLayout ? this.el : this.el.createChild());
45206 * Adds a object form elements (using the xtype property as the factory method.)
45207 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45208 * @param {Object} config
45210 addxtype : function(o)
45212 // create the lement.
45213 o.form = this.form;
45214 var fe = Roo.factory(o, Roo.form);
45215 this.form.allItems.push(fe);
45216 this.stack.push(fe);
45218 if (fe.isFormField) {
45219 this.form.items.add(fe);
45227 * @class Roo.form.Column
45228 * @extends Roo.form.Layout
45229 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45231 * @param {Object} config Configuration options
45233 Roo.form.Column = function(config){
45234 Roo.form.Column.superclass.constructor.call(this, config);
45237 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45239 * @cfg {Number/String} width
45240 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45243 * @cfg {String/Object} autoCreate
45244 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45248 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45251 onRender : function(ct, position){
45252 Roo.form.Column.superclass.onRender.call(this, ct, position);
45254 this.el.setWidth(this.width);
45261 * @class Roo.form.Row
45262 * @extends Roo.form.Layout
45263 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45265 * @param {Object} config Configuration options
45269 Roo.form.Row = function(config){
45270 Roo.form.Row.superclass.constructor.call(this, config);
45273 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45275 * @cfg {Number/String} width
45276 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45279 * @cfg {Number/String} height
45280 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45282 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45286 onRender : function(ct, position){
45287 //console.log('row render');
45289 var t = new Roo.Template(
45290 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45291 '<label for="{0}" style="{2}">{1}{4}</label>',
45292 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45296 t.disableFormats = true;
45298 Roo.form.Layout.prototype.rowTpl = t;
45300 this.fieldTpl = this.rowTpl;
45302 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
45303 var labelWidth = 100;
45305 if ((this.labelAlign != 'top')) {
45306 if (typeof this.labelWidth == 'number') {
45307 labelWidth = this.labelWidth
45309 this.padWidth = 20 + labelWidth;
45313 Roo.form.Column.superclass.onRender.call(this, ct, position);
45315 this.el.setWidth(this.width);
45318 this.el.setHeight(this.height);
45323 renderField : function(f){
45324 f.fieldEl = this.fieldTpl.append(this.el, [
45325 f.id, f.fieldLabel,
45326 f.labelStyle||this.labelStyle||'',
45327 this.elementStyle||'',
45328 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
45329 f.itemCls||this.itemCls||'',
45330 f.width ? f.width + this.padWidth : 160 + this.padWidth
45337 * @class Roo.form.FieldSet
45338 * @extends Roo.form.Layout
45339 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
45341 * @param {Object} config Configuration options
45343 Roo.form.FieldSet = function(config){
45344 Roo.form.FieldSet.superclass.constructor.call(this, config);
45347 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
45349 * @cfg {String} legend
45350 * The text to display as the legend for the FieldSet (defaults to '')
45353 * @cfg {String/Object} autoCreate
45354 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
45358 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
45361 onRender : function(ct, position){
45362 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
45364 this.setLegend(this.legend);
45369 setLegend : function(text){
45371 this.el.child('legend').update(text);
45376 * Ext JS Library 1.1.1
45377 * Copyright(c) 2006-2007, Ext JS, LLC.
45379 * Originally Released Under LGPL - original licence link has changed is not relivant.
45382 * <script type="text/javascript">
45385 * @class Roo.form.VTypes
45386 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
45389 Roo.form.VTypes = function(){
45390 // closure these in so they are only created once.
45391 var alpha = /^[a-zA-Z_]+$/;
45392 var alphanum = /^[a-zA-Z0-9_]+$/;
45393 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
45394 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
45396 // All these messages and functions are configurable
45399 * The function used to validate email addresses
45400 * @param {String} value The email address
45402 'email' : function(v){
45403 return email.test(v);
45406 * The error text to display when the email validation function returns false
45409 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
45411 * The keystroke filter mask to be applied on email input
45414 'emailMask' : /[a-z0-9_\.\-@]/i,
45417 * The function used to validate URLs
45418 * @param {String} value The URL
45420 'url' : function(v){
45421 return url.test(v);
45424 * The error text to display when the url validation function returns false
45427 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
45430 * The function used to validate alpha values
45431 * @param {String} value The value
45433 'alpha' : function(v){
45434 return alpha.test(v);
45437 * The error text to display when the alpha validation function returns false
45440 'alphaText' : 'This field should only contain letters and _',
45442 * The keystroke filter mask to be applied on alpha input
45445 'alphaMask' : /[a-z_]/i,
45448 * The function used to validate alphanumeric values
45449 * @param {String} value The value
45451 'alphanum' : function(v){
45452 return alphanum.test(v);
45455 * The error text to display when the alphanumeric validation function returns false
45458 'alphanumText' : 'This field should only contain letters, numbers and _',
45460 * The keystroke filter mask to be applied on alphanumeric input
45463 'alphanumMask' : /[a-z0-9_]/i
45465 }();//<script type="text/javascript">
45468 * @class Roo.form.FCKeditor
45469 * @extends Roo.form.TextArea
45470 * Wrapper around the FCKEditor http://www.fckeditor.net
45472 * Creates a new FCKeditor
45473 * @param {Object} config Configuration options
45475 Roo.form.FCKeditor = function(config){
45476 Roo.form.FCKeditor.superclass.constructor.call(this, config);
45479 * @event editorinit
45480 * Fired when the editor is initialized - you can add extra handlers here..
45481 * @param {FCKeditor} this
45482 * @param {Object} the FCK object.
45489 Roo.form.FCKeditor.editors = { };
45490 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
45492 //defaultAutoCreate : {
45493 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
45497 * @cfg {Object} fck options - see fck manual for details.
45502 * @cfg {Object} fck toolbar set (Basic or Default)
45504 toolbarSet : 'Basic',
45506 * @cfg {Object} fck BasePath
45508 basePath : '/fckeditor/',
45516 onRender : function(ct, position)
45519 this.defaultAutoCreate = {
45521 style:"width:300px;height:60px;",
45522 autocomplete: "off"
45525 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
45528 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
45529 if(this.preventScrollbars){
45530 this.el.setStyle("overflow", "hidden");
45532 this.el.setHeight(this.growMin);
45535 //console.log('onrender' + this.getId() );
45536 Roo.form.FCKeditor.editors[this.getId()] = this;
45539 this.replaceTextarea() ;
45543 getEditor : function() {
45544 return this.fckEditor;
45547 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
45548 * @param {Mixed} value The value to set
45552 setValue : function(value)
45554 //console.log('setValue: ' + value);
45556 if(typeof(value) == 'undefined') { // not sure why this is happending...
45559 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45561 //if(!this.el || !this.getEditor()) {
45562 // this.value = value;
45563 //this.setValue.defer(100,this,[value]);
45567 if(!this.getEditor()) {
45571 this.getEditor().SetData(value);
45578 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
45579 * @return {Mixed} value The field value
45581 getValue : function()
45584 if (this.frame && this.frame.dom.style.display == 'none') {
45585 return Roo.form.FCKeditor.superclass.getValue.call(this);
45588 if(!this.el || !this.getEditor()) {
45590 // this.getValue.defer(100,this);
45595 var value=this.getEditor().GetData();
45596 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45597 return Roo.form.FCKeditor.superclass.getValue.call(this);
45603 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
45604 * @return {Mixed} value The field value
45606 getRawValue : function()
45608 if (this.frame && this.frame.dom.style.display == 'none') {
45609 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45612 if(!this.el || !this.getEditor()) {
45613 //this.getRawValue.defer(100,this);
45620 var value=this.getEditor().GetData();
45621 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
45622 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45626 setSize : function(w,h) {
45630 //if (this.frame && this.frame.dom.style.display == 'none') {
45631 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45634 //if(!this.el || !this.getEditor()) {
45635 // this.setSize.defer(100,this, [w,h]);
45641 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45643 this.frame.dom.setAttribute('width', w);
45644 this.frame.dom.setAttribute('height', h);
45645 this.frame.setSize(w,h);
45649 toggleSourceEdit : function(value) {
45653 this.el.dom.style.display = value ? '' : 'none';
45654 this.frame.dom.style.display = value ? 'none' : '';
45659 focus: function(tag)
45661 if (this.frame.dom.style.display == 'none') {
45662 return Roo.form.FCKeditor.superclass.focus.call(this);
45664 if(!this.el || !this.getEditor()) {
45665 this.focus.defer(100,this, [tag]);
45672 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
45673 this.getEditor().Focus();
45675 if (!this.getEditor().Selection.GetSelection()) {
45676 this.focus.defer(100,this, [tag]);
45681 var r = this.getEditor().EditorDocument.createRange();
45682 r.setStart(tgs[0],0);
45683 r.setEnd(tgs[0],0);
45684 this.getEditor().Selection.GetSelection().removeAllRanges();
45685 this.getEditor().Selection.GetSelection().addRange(r);
45686 this.getEditor().Focus();
45693 replaceTextarea : function()
45695 if ( document.getElementById( this.getId() + '___Frame' ) )
45697 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
45699 // We must check the elements firstly using the Id and then the name.
45700 var oTextarea = document.getElementById( this.getId() );
45702 var colElementsByName = document.getElementsByName( this.getId() ) ;
45704 oTextarea.style.display = 'none' ;
45706 if ( oTextarea.tabIndex ) {
45707 this.TabIndex = oTextarea.tabIndex ;
45710 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
45711 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
45712 this.frame = Roo.get(this.getId() + '___Frame')
45715 _getConfigHtml : function()
45719 for ( var o in this.fckconfig ) {
45720 sConfig += sConfig.length > 0 ? '&' : '';
45721 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
45724 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
45728 _getIFrameHtml : function()
45730 var sFile = 'fckeditor.html' ;
45731 /* no idea what this is about..
45734 if ( (/fcksource=true/i).test( window.top.location.search ) )
45735 sFile = 'fckeditor.original.html' ;
45740 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
45741 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
45744 var html = '<iframe id="' + this.getId() +
45745 '___Frame" src="' + sLink +
45746 '" width="' + this.width +
45747 '" height="' + this.height + '"' +
45748 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
45749 ' frameborder="0" scrolling="no"></iframe>' ;
45754 _insertHtmlBefore : function( html, element )
45756 if ( element.insertAdjacentHTML ) {
45758 element.insertAdjacentHTML( 'beforeBegin', html ) ;
45760 var oRange = document.createRange() ;
45761 oRange.setStartBefore( element ) ;
45762 var oFragment = oRange.createContextualFragment( html );
45763 element.parentNode.insertBefore( oFragment, element ) ;
45776 //Roo.reg('fckeditor', Roo.form.FCKeditor);
45778 function FCKeditor_OnComplete(editorInstance){
45779 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
45780 f.fckEditor = editorInstance;
45781 //console.log("loaded");
45782 f.fireEvent('editorinit', f, editorInstance);
45802 //<script type="text/javascript">
45804 * @class Roo.form.GridField
45805 * @extends Roo.form.Field
45806 * Embed a grid (or editable grid into a form)
45809 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
45811 * xgrid.store = Roo.data.Store
45812 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
45813 * xgrid.store.reader = Roo.data.JsonReader
45817 * Creates a new GridField
45818 * @param {Object} config Configuration options
45820 Roo.form.GridField = function(config){
45821 Roo.form.GridField.superclass.constructor.call(this, config);
45825 Roo.extend(Roo.form.GridField, Roo.form.Field, {
45827 * @cfg {Number} width - used to restrict width of grid..
45831 * @cfg {Number} height - used to restrict height of grid..
45835 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
45841 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45842 * {tag: "input", type: "checkbox", autocomplete: "off"})
45844 // defaultAutoCreate : { tag: 'div' },
45845 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45847 * @cfg {String} addTitle Text to include for adding a title.
45851 onResize : function(){
45852 Roo.form.Field.superclass.onResize.apply(this, arguments);
45855 initEvents : function(){
45856 // Roo.form.Checkbox.superclass.initEvents.call(this);
45857 // has no events...
45862 getResizeEl : function(){
45866 getPositionEl : function(){
45871 onRender : function(ct, position){
45873 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
45874 var style = this.style;
45877 Roo.form.GridField.superclass.onRender.call(this, ct, position);
45878 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
45879 this.viewEl = this.wrap.createChild({ tag: 'div' });
45881 this.viewEl.applyStyles(style);
45884 this.viewEl.setWidth(this.width);
45887 this.viewEl.setHeight(this.height);
45889 //if(this.inputValue !== undefined){
45890 //this.setValue(this.value);
45893 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
45896 this.grid.render();
45897 this.grid.getDataSource().on('remove', this.refreshValue, this);
45898 this.grid.getDataSource().on('update', this.refreshValue, this);
45899 this.grid.on('afteredit', this.refreshValue, this);
45905 * Sets the value of the item.
45906 * @param {String} either an object or a string..
45908 setValue : function(v){
45910 v = v || []; // empty set..
45911 // this does not seem smart - it really only affects memoryproxy grids..
45912 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
45913 var ds = this.grid.getDataSource();
45914 // assumes a json reader..
45916 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
45917 ds.loadData( data);
45919 // clear selection so it does not get stale.
45920 if (this.grid.sm) {
45921 this.grid.sm.clearSelections();
45924 Roo.form.GridField.superclass.setValue.call(this, v);
45925 this.refreshValue();
45926 // should load data in the grid really....
45930 refreshValue: function() {
45932 this.grid.getDataSource().each(function(r) {
45935 this.el.dom.value = Roo.encode(val);
45943 * Ext JS Library 1.1.1
45944 * Copyright(c) 2006-2007, Ext JS, LLC.
45946 * Originally Released Under LGPL - original licence link has changed is not relivant.
45949 * <script type="text/javascript">
45952 * @class Roo.form.DisplayField
45953 * @extends Roo.form.Field
45954 * A generic Field to display non-editable data.
45956 * Creates a new Display Field item.
45957 * @param {Object} config Configuration options
45959 Roo.form.DisplayField = function(config){
45960 Roo.form.DisplayField.superclass.constructor.call(this, config);
45964 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
45965 inputType: 'hidden',
45971 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45973 focusClass : undefined,
45975 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45977 fieldClass: 'x-form-field',
45980 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
45982 valueRenderer: undefined,
45986 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45987 * {tag: "input", type: "checkbox", autocomplete: "off"})
45990 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45992 onResize : function(){
45993 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
45997 initEvents : function(){
45998 // Roo.form.Checkbox.superclass.initEvents.call(this);
45999 // has no events...
46004 getResizeEl : function(){
46008 getPositionEl : function(){
46013 onRender : function(ct, position){
46015 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46016 //if(this.inputValue !== undefined){
46017 this.wrap = this.el.wrap();
46019 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46021 if (this.bodyStyle) {
46022 this.viewEl.applyStyles(this.bodyStyle);
46024 //this.viewEl.setStyle('padding', '2px');
46026 this.setValue(this.value);
46031 initValue : Roo.emptyFn,
46036 onClick : function(){
46041 * Sets the checked state of the checkbox.
46042 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46044 setValue : function(v){
46046 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46047 // this might be called before we have a dom element..
46048 if (!this.viewEl) {
46051 this.viewEl.dom.innerHTML = html;
46052 Roo.form.DisplayField.superclass.setValue.call(this, v);
46062 * @class Roo.form.DayPicker
46063 * @extends Roo.form.Field
46064 * A Day picker show [M] [T] [W] ....
46066 * Creates a new Day Picker
46067 * @param {Object} config Configuration options
46069 Roo.form.DayPicker= function(config){
46070 Roo.form.DayPicker.superclass.constructor.call(this, config);
46074 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46076 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46078 focusClass : undefined,
46080 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46082 fieldClass: "x-form-field",
46085 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46086 * {tag: "input", type: "checkbox", autocomplete: "off"})
46088 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46091 actionMode : 'viewEl',
46095 inputType : 'hidden',
46098 inputElement: false, // real input element?
46099 basedOn: false, // ????
46101 isFormField: true, // not sure where this is needed!!!!
46103 onResize : function(){
46104 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46105 if(!this.boxLabel){
46106 this.el.alignTo(this.wrap, 'c-c');
46110 initEvents : function(){
46111 Roo.form.Checkbox.superclass.initEvents.call(this);
46112 this.el.on("click", this.onClick, this);
46113 this.el.on("change", this.onClick, this);
46117 getResizeEl : function(){
46121 getPositionEl : function(){
46127 onRender : function(ct, position){
46128 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46130 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46132 var r1 = '<table><tr>';
46133 var r2 = '<tr class="x-form-daypick-icons">';
46134 for (var i=0; i < 7; i++) {
46135 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46136 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46139 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46140 viewEl.select('img').on('click', this.onClick, this);
46141 this.viewEl = viewEl;
46144 // this will not work on Chrome!!!
46145 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46146 this.el.on('propertychange', this.setFromHidden, this); //ie
46154 initValue : Roo.emptyFn,
46157 * Returns the checked state of the checkbox.
46158 * @return {Boolean} True if checked, else false
46160 getValue : function(){
46161 return this.el.dom.value;
46166 onClick : function(e){
46167 //this.setChecked(!this.checked);
46168 Roo.get(e.target).toggleClass('x-menu-item-checked');
46169 this.refreshValue();
46170 //if(this.el.dom.checked != this.checked){
46171 // this.setValue(this.el.dom.checked);
46176 refreshValue : function()
46179 this.viewEl.select('img',true).each(function(e,i,n) {
46180 val += e.is(".x-menu-item-checked") ? String(n) : '';
46182 this.setValue(val, true);
46186 * Sets the checked state of the checkbox.
46187 * On is always based on a string comparison between inputValue and the param.
46188 * @param {Boolean/String} value - the value to set
46189 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46191 setValue : function(v,suppressEvent){
46192 if (!this.el.dom) {
46195 var old = this.el.dom.value ;
46196 this.el.dom.value = v;
46197 if (suppressEvent) {
46201 // update display..
46202 this.viewEl.select('img',true).each(function(e,i,n) {
46204 var on = e.is(".x-menu-item-checked");
46205 var newv = v.indexOf(String(n)) > -1;
46207 e.toggleClass('x-menu-item-checked');
46213 this.fireEvent('change', this, v, old);
46218 // handle setting of hidden value by some other method!!?!?
46219 setFromHidden: function()
46224 //console.log("SET FROM HIDDEN");
46225 //alert('setFrom hidden');
46226 this.setValue(this.el.dom.value);
46229 onDestroy : function()
46232 Roo.get(this.viewEl).remove();
46235 Roo.form.DayPicker.superclass.onDestroy.call(this);
46239 * RooJS Library 1.1.1
46240 * Copyright(c) 2008-2011 Alan Knowles
46247 * @class Roo.form.ComboCheck
46248 * @extends Roo.form.ComboBox
46249 * A combobox for multiple select items.
46251 * FIXME - could do with a reset button..
46254 * Create a new ComboCheck
46255 * @param {Object} config Configuration options
46257 Roo.form.ComboCheck = function(config){
46258 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46259 // should verify some data...
46261 // hiddenName = required..
46262 // displayField = required
46263 // valudField == required
46264 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46266 Roo.each(req, function(e) {
46267 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46268 throw "Roo.form.ComboCheck : missing value for: " + e;
46275 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46280 selectedClass: 'x-menu-item-checked',
46283 onRender : function(ct, position){
46289 var cls = 'x-combo-list';
46292 this.tpl = new Roo.Template({
46293 html : '<div class="'+cls+'-item x-menu-check-item">' +
46294 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
46295 '<span>{' + this.displayField + '}</span>' +
46302 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
46303 this.view.singleSelect = false;
46304 this.view.multiSelect = true;
46305 this.view.toggleSelect = true;
46306 this.pageTb.add(new Roo.Toolbar.Fill(), {
46309 handler: function()
46316 onViewOver : function(e, t){
46322 onViewClick : function(doFocus,index){
46326 select: function () {
46327 //Roo.log("SELECT CALLED");
46330 selectByValue : function(xv, scrollIntoView){
46331 var ar = this.getValueArray();
46334 Roo.each(ar, function(v) {
46335 if(v === undefined || v === null){
46338 var r = this.findRecord(this.valueField, v);
46340 sels.push(this.store.indexOf(r))
46344 this.view.select(sels);
46350 onSelect : function(record, index){
46351 // Roo.log("onselect Called");
46352 // this is only called by the clear button now..
46353 this.view.clearSelections();
46354 this.setValue('[]');
46355 if (this.value != this.valueBefore) {
46356 this.fireEvent('change', this, this.value, this.valueBefore);
46357 this.valueBefore = this.value;
46360 getValueArray : function()
46365 //Roo.log(this.value);
46366 if (typeof(this.value) == 'undefined') {
46369 var ar = Roo.decode(this.value);
46370 return ar instanceof Array ? ar : []; //?? valid?
46373 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
46378 expand : function ()
46381 Roo.form.ComboCheck.superclass.expand.call(this);
46382 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
46383 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
46388 collapse : function(){
46389 Roo.form.ComboCheck.superclass.collapse.call(this);
46390 var sl = this.view.getSelectedIndexes();
46391 var st = this.store;
46395 Roo.each(sl, function(i) {
46397 nv.push(r.get(this.valueField));
46399 this.setValue(Roo.encode(nv));
46400 if (this.value != this.valueBefore) {
46402 this.fireEvent('change', this, this.value, this.valueBefore);
46403 this.valueBefore = this.value;
46408 setValue : function(v){
46412 var vals = this.getValueArray();
46414 Roo.each(vals, function(k) {
46415 var r = this.findRecord(this.valueField, k);
46417 tv.push(r.data[this.displayField]);
46418 }else if(this.valueNotFoundText !== undefined){
46419 tv.push( this.valueNotFoundText );
46424 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
46425 this.hiddenField.value = v;
46431 * Ext JS Library 1.1.1
46432 * Copyright(c) 2006-2007, Ext JS, LLC.
46434 * Originally Released Under LGPL - original licence link has changed is not relivant.
46437 * <script type="text/javascript">
46441 * @class Roo.form.Signature
46442 * @extends Roo.form.Field
46446 * @param {Object} config Configuration options
46449 Roo.form.Signature = function(config){
46450 Roo.form.Signature.superclass.constructor.call(this, config);
46452 this.addEvents({// not in used??
46455 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
46456 * @param {Roo.form.Signature} combo This combo box
46461 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
46462 * @param {Roo.form.ComboBox} combo This combo box
46463 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
46469 Roo.extend(Roo.form.Signature, Roo.form.Field, {
46471 * @cfg {Object} labels Label to use when rendering a form.
46475 * confirm : "Confirm"
46480 confirm : "Confirm"
46483 * @cfg {Number} width The signature panel width (defaults to 300)
46487 * @cfg {Number} height The signature panel height (defaults to 100)
46491 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
46493 allowBlank : false,
46496 // {Object} signPanel The signature SVG panel element (defaults to {})
46498 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
46499 isMouseDown : false,
46500 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
46501 isConfirmed : false,
46502 // {String} signatureTmp SVG mapping string (defaults to empty string)
46506 defaultAutoCreate : { // modified by initCompnoent..
46512 onRender : function(ct, position){
46514 Roo.form.Signature.superclass.onRender.call(this, ct, position);
46516 this.wrap = this.el.wrap({
46517 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
46520 this.createToolbar(this);
46521 this.signPanel = this.wrap.createChild({
46523 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
46527 this.svgID = Roo.id();
46528 this.svgEl = this.signPanel.createChild({
46529 xmlns : 'http://www.w3.org/2000/svg',
46531 id : this.svgID + "-svg",
46533 height: this.height,
46534 viewBox: '0 0 '+this.width+' '+this.height,
46538 id: this.svgID + "-svg-r",
46540 height: this.height,
46545 id: this.svgID + "-svg-l",
46547 y1: (this.height*0.8), // start set the line in 80% of height
46548 x2: this.width, // end
46549 y2: (this.height*0.8), // end set the line in 80% of height
46551 'stroke-width': "1",
46552 'stroke-dasharray': "3",
46553 'shape-rendering': "crispEdges",
46554 'pointer-events': "none"
46558 id: this.svgID + "-svg-p",
46560 'stroke-width': "3",
46562 'pointer-events': 'none'
46567 this.svgBox = this.svgEl.dom.getScreenCTM();
46569 createSVG : function(){
46570 var svg = this.signPanel;
46571 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
46574 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
46575 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
46576 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
46577 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
46578 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
46579 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
46580 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
46583 isTouchEvent : function(e){
46584 return e.type.match(/^touch/);
46586 getCoords : function (e) {
46587 var pt = this.svgEl.dom.createSVGPoint();
46590 if (this.isTouchEvent(e)) {
46591 pt.x = e.targetTouches[0].clientX
46592 pt.y = e.targetTouches[0].clientY;
46594 var a = this.svgEl.dom.getScreenCTM();
46595 var b = a.inverse();
46596 var mx = pt.matrixTransform(b);
46597 return mx.x + ',' + mx.y;
46599 //mouse event headler
46600 down : function (e) {
46601 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
46602 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
46604 this.isMouseDown = true;
46606 e.preventDefault();
46608 move : function (e) {
46609 if (this.isMouseDown) {
46610 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
46611 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
46614 e.preventDefault();
46616 up : function (e) {
46617 this.isMouseDown = false;
46618 var sp = this.signatureTmp.split(' ');
46621 if(!sp[sp.length-2].match(/^L/)){
46625 this.signatureTmp = sp.join(" ");
46628 if(this.getValue() != this.signatureTmp){
46629 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46630 this.isConfirmed = false;
46632 e.preventDefault();
46636 * Protected method that will not generally be called directly. It
46637 * is called when the editor creates its toolbar. Override this method if you need to
46638 * add custom toolbar buttons.
46639 * @param {HtmlEditor} editor
46641 createToolbar : function(editor){
46642 function btn(id, toggle, handler){
46643 var xid = fid + '-'+ id ;
46647 cls : 'x-btn-icon x-edit-'+id,
46648 enableToggle:toggle !== false,
46649 scope: editor, // was editor...
46650 handler:handler||editor.relayBtnCmd,
46651 clickEvent:'mousedown',
46652 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46658 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46662 cls : ' x-signature-btn x-signature-'+id,
46663 scope: editor, // was editor...
46664 handler: this.reset,
46665 clickEvent:'mousedown',
46666 text: this.labels.clear
46673 cls : ' x-signature-btn x-signature-'+id,
46674 scope: editor, // was editor...
46675 handler: this.confirmHandler,
46676 clickEvent:'mousedown',
46677 text: this.labels.confirm
46684 * when user is clicked confirm then show this image.....
46686 * @return {String} Image Data URI
46688 getImageDataURI : function(){
46689 var svg = this.svgEl.dom.parentNode.innerHTML;
46690 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
46695 * @return {Boolean} this.isConfirmed
46697 getConfirmed : function(){
46698 return this.isConfirmed;
46702 * @return {Number} this.width
46704 getWidth : function(){
46709 * @return {Number} this.height
46711 getHeight : function(){
46712 return this.height;
46715 getSignature : function(){
46716 return this.signatureTmp;
46719 reset : function(){
46720 this.signatureTmp = '';
46721 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46722 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
46723 this.isConfirmed = false;
46724 Roo.form.Signature.superclass.reset.call(this);
46726 setSignature : function(s){
46727 this.signatureTmp = s;
46728 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46729 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
46731 this.isConfirmed = false;
46732 Roo.form.Signature.superclass.reset.call(this);
46735 // Roo.log(this.signPanel.dom.contentWindow.up())
46738 setConfirmed : function(){
46742 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
46745 confirmHandler : function(){
46746 if(!this.getSignature()){
46750 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
46751 this.setValue(this.getSignature());
46752 this.isConfirmed = true;
46754 this.fireEvent('confirm', this);
46757 // Subclasses should provide the validation implementation by overriding this
46758 validateValue : function(value){
46759 if(this.allowBlank){
46763 if(this.isConfirmed){
46770 * Ext JS Library 1.1.1
46771 * Copyright(c) 2006-2007, Ext JS, LLC.
46773 * Originally Released Under LGPL - original licence link has changed is not relivant.
46776 * <script type="text/javascript">
46781 * @class Roo.form.ComboBox
46782 * @extends Roo.form.TriggerField
46783 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
46785 * Create a new ComboBox.
46786 * @param {Object} config Configuration options
46788 Roo.form.Select = function(config){
46789 Roo.form.Select.superclass.constructor.call(this, config);
46793 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
46795 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
46798 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
46799 * rendering into an Roo.Editor, defaults to false)
46802 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
46803 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
46806 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
46809 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
46810 * the dropdown list (defaults to undefined, with no header element)
46814 * @cfg {String/Roo.Template} tpl The template to use to render the output
46818 defaultAutoCreate : {tag: "select" },
46820 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
46822 listWidth: undefined,
46824 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
46825 * mode = 'remote' or 'text' if mode = 'local')
46827 displayField: undefined,
46829 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
46830 * mode = 'remote' or 'value' if mode = 'local').
46831 * Note: use of a valueField requires the user make a selection
46832 * in order for a value to be mapped.
46834 valueField: undefined,
46838 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
46839 * field's data value (defaults to the underlying DOM element's name)
46841 hiddenName: undefined,
46843 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
46847 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
46849 selectedClass: 'x-combo-selected',
46851 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
46852 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
46853 * which displays a downward arrow icon).
46855 triggerClass : 'x-form-arrow-trigger',
46857 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
46861 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
46862 * anchor positions (defaults to 'tl-bl')
46864 listAlign: 'tl-bl?',
46866 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
46870 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
46871 * query specified by the allQuery config option (defaults to 'query')
46873 triggerAction: 'query',
46875 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
46876 * (defaults to 4, does not apply if editable = false)
46880 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
46881 * delay (typeAheadDelay) if it matches a known value (defaults to false)
46885 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
46886 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
46890 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
46891 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
46895 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
46896 * when editable = true (defaults to false)
46898 selectOnFocus:false,
46900 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
46902 queryParam: 'query',
46904 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
46905 * when mode = 'remote' (defaults to 'Loading...')
46907 loadingText: 'Loading...',
46909 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
46913 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
46917 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
46918 * traditional select (defaults to true)
46922 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
46926 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
46930 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
46931 * listWidth has a higher value)
46935 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
46936 * allow the user to set arbitrary text into the field (defaults to false)
46938 forceSelection:false,
46940 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
46941 * if typeAhead = true (defaults to 250)
46943 typeAheadDelay : 250,
46945 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
46946 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
46948 valueNotFoundText : undefined,
46951 * @cfg {String} defaultValue The value displayed after loading the store.
46956 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
46958 blockFocus : false,
46961 * @cfg {Boolean} disableClear Disable showing of clear button.
46963 disableClear : false,
46965 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
46967 alwaysQuery : false,
46973 // element that contains real text value.. (when hidden is used..)
46976 onRender : function(ct, position){
46977 Roo.form.Field.prototype.onRender.call(this, ct, position);
46980 this.store.on('beforeload', this.onBeforeLoad, this);
46981 this.store.on('load', this.onLoad, this);
46982 this.store.on('loadexception', this.onLoadException, this);
46983 this.store.load({});
46991 initEvents : function(){
46992 //Roo.form.ComboBox.superclass.initEvents.call(this);
46996 onDestroy : function(){
46999 this.store.un('beforeload', this.onBeforeLoad, this);
47000 this.store.un('load', this.onLoad, this);
47001 this.store.un('loadexception', this.onLoadException, this);
47003 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47007 fireKey : function(e){
47008 if(e.isNavKeyPress() && !this.list.isVisible()){
47009 this.fireEvent("specialkey", this, e);
47014 onResize: function(w, h){
47022 * Allow or prevent the user from directly editing the field text. If false is passed,
47023 * the user will only be able to select from the items defined in the dropdown list. This method
47024 * is the runtime equivalent of setting the 'editable' config option at config time.
47025 * @param {Boolean} value True to allow the user to directly edit the field text
47027 setEditable : function(value){
47032 onBeforeLoad : function(){
47034 Roo.log("Select before load");
47037 this.innerList.update(this.loadingText ?
47038 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47039 //this.restrictHeight();
47040 this.selectedIndex = -1;
47044 onLoad : function(){
47047 var dom = this.el.dom;
47048 dom.innerHTML = '';
47049 var od = dom.ownerDocument;
47051 if (this.emptyText) {
47052 var op = od.createElement('option');
47053 op.setAttribute('value', '');
47054 op.innerHTML = String.format('{0}', this.emptyText);
47055 dom.appendChild(op);
47057 if(this.store.getCount() > 0){
47059 var vf = this.valueField;
47060 var df = this.displayField;
47061 this.store.data.each(function(r) {
47062 // which colmsn to use... testing - cdoe / title..
47063 var op = od.createElement('option');
47064 op.setAttribute('value', r.data[vf]);
47065 op.innerHTML = String.format('{0}', r.data[df]);
47066 dom.appendChild(op);
47068 if (typeof(this.defaultValue != 'undefined')) {
47069 this.setValue(this.defaultValue);
47074 //this.onEmptyResults();
47079 onLoadException : function()
47081 dom.innerHTML = '';
47083 Roo.log("Select on load exception");
47087 Roo.log(this.store.reader.jsonData);
47088 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47089 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47095 onTypeAhead : function(){
47100 onSelect : function(record, index){
47101 Roo.log('on select?');
47103 if(this.fireEvent('beforeselect', this, record, index) !== false){
47104 this.setFromData(index > -1 ? record.data : false);
47106 this.fireEvent('select', this, record, index);
47111 * Returns the currently selected field value or empty string if no value is set.
47112 * @return {String} value The selected value
47114 getValue : function(){
47115 var dom = this.el.dom;
47116 this.value = dom.options[dom.selectedIndex].value;
47122 * Clears any text/value currently set in the field
47124 clearValue : function(){
47126 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47131 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47132 * will be displayed in the field. If the value does not match the data value of an existing item,
47133 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47134 * Otherwise the field will be blank (although the value will still be set).
47135 * @param {String} value The value to match
47137 setValue : function(v){
47138 var d = this.el.dom;
47139 for (var i =0; i < d.options.length;i++) {
47140 if (v == d.options[i].value) {
47141 d.selectedIndex = i;
47149 * @property {Object} the last set data for the element
47154 * Sets the value of the field based on a object which is related to the record format for the store.
47155 * @param {Object} value the value to set as. or false on reset?
47157 setFromData : function(o){
47158 Roo.log('setfrom data?');
47164 reset : function(){
47168 findRecord : function(prop, value){
47173 if(this.store.getCount() > 0){
47174 this.store.each(function(r){
47175 if(r.data[prop] == value){
47185 getName: function()
47187 // returns hidden if it's set..
47188 if (!this.rendered) {return ''};
47189 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47197 onEmptyResults : function(){
47198 Roo.log('empty results');
47203 * Returns true if the dropdown list is expanded, else false.
47205 isExpanded : function(){
47210 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47211 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47212 * @param {String} value The data value of the item to select
47213 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47214 * selected item if it is not currently in view (defaults to true)
47215 * @return {Boolean} True if the value matched an item in the list, else false
47217 selectByValue : function(v, scrollIntoView){
47218 Roo.log('select By Value');
47221 if(v !== undefined && v !== null){
47222 var r = this.findRecord(this.valueField || this.displayField, v);
47224 this.select(this.store.indexOf(r), scrollIntoView);
47232 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47233 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47234 * @param {Number} index The zero-based index of the list item to select
47235 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47236 * selected item if it is not currently in view (defaults to true)
47238 select : function(index, scrollIntoView){
47239 Roo.log('select ');
47242 this.selectedIndex = index;
47243 this.view.select(index);
47244 if(scrollIntoView !== false){
47245 var el = this.view.getNode(index);
47247 this.innerList.scrollChildIntoView(el, false);
47255 validateBlur : function(){
47262 initQuery : function(){
47263 this.doQuery(this.getRawValue());
47267 doForce : function(){
47268 if(this.el.dom.value.length > 0){
47269 this.el.dom.value =
47270 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47276 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47277 * query allowing the query action to be canceled if needed.
47278 * @param {String} query The SQL query to execute
47279 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47280 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47281 * saved in the current store (defaults to false)
47283 doQuery : function(q, forceAll){
47285 Roo.log('doQuery?');
47286 if(q === undefined || q === null){
47291 forceAll: forceAll,
47295 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
47299 forceAll = qe.forceAll;
47300 if(forceAll === true || (q.length >= this.minChars)){
47301 if(this.lastQuery != q || this.alwaysQuery){
47302 this.lastQuery = q;
47303 if(this.mode == 'local'){
47304 this.selectedIndex = -1;
47306 this.store.clearFilter();
47308 this.store.filter(this.displayField, q);
47312 this.store.baseParams[this.queryParam] = q;
47314 params: this.getParams(q)
47319 this.selectedIndex = -1;
47326 getParams : function(q){
47328 //p[this.queryParam] = q;
47331 p.limit = this.pageSize;
47337 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
47339 collapse : function(){
47344 collapseIf : function(e){
47349 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
47351 expand : function(){
47359 * @cfg {Boolean} grow
47363 * @cfg {Number} growMin
47367 * @cfg {Number} growMax
47375 setWidth : function()
47379 getResizeEl : function(){
47382 });//<script type="text/javasscript">
47386 * @class Roo.DDView
47387 * A DnD enabled version of Roo.View.
47388 * @param {Element/String} container The Element in which to create the View.
47389 * @param {String} tpl The template string used to create the markup for each element of the View
47390 * @param {Object} config The configuration properties. These include all the config options of
47391 * {@link Roo.View} plus some specific to this class.<br>
47393 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
47394 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
47396 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
47397 .x-view-drag-insert-above {
47398 border-top:1px dotted #3366cc;
47400 .x-view-drag-insert-below {
47401 border-bottom:1px dotted #3366cc;
47407 Roo.DDView = function(container, tpl, config) {
47408 Roo.DDView.superclass.constructor.apply(this, arguments);
47409 this.getEl().setStyle("outline", "0px none");
47410 this.getEl().unselectable();
47411 if (this.dragGroup) {
47412 this.setDraggable(this.dragGroup.split(","));
47414 if (this.dropGroup) {
47415 this.setDroppable(this.dropGroup.split(","));
47417 if (this.deletable) {
47418 this.setDeletable();
47420 this.isDirtyFlag = false;
47426 Roo.extend(Roo.DDView, Roo.View, {
47427 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
47428 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
47429 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
47430 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
47434 reset: Roo.emptyFn,
47436 clearInvalid: Roo.form.Field.prototype.clearInvalid,
47438 validate: function() {
47442 destroy: function() {
47443 this.purgeListeners();
47444 this.getEl.removeAllListeners();
47445 this.getEl().remove();
47446 if (this.dragZone) {
47447 if (this.dragZone.destroy) {
47448 this.dragZone.destroy();
47451 if (this.dropZone) {
47452 if (this.dropZone.destroy) {
47453 this.dropZone.destroy();
47458 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
47459 getName: function() {
47463 /** Loads the View from a JSON string representing the Records to put into the Store. */
47464 setValue: function(v) {
47466 throw "DDView.setValue(). DDView must be constructed with a valid Store";
47469 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
47470 this.store.proxy = new Roo.data.MemoryProxy(data);
47474 /** @return {String} a parenthesised list of the ids of the Records in the View. */
47475 getValue: function() {
47477 this.store.each(function(rec) {
47478 result += rec.id + ',';
47480 return result.substr(0, result.length - 1) + ')';
47483 getIds: function() {
47484 var i = 0, result = new Array(this.store.getCount());
47485 this.store.each(function(rec) {
47486 result[i++] = rec.id;
47491 isDirty: function() {
47492 return this.isDirtyFlag;
47496 * Part of the Roo.dd.DropZone interface. If no target node is found, the
47497 * whole Element becomes the target, and this causes the drop gesture to append.
47499 getTargetFromEvent : function(e) {
47500 var target = e.getTarget();
47501 while ((target !== null) && (target.parentNode != this.el.dom)) {
47502 target = target.parentNode;
47505 target = this.el.dom.lastChild || this.el.dom;
47511 * Create the drag data which consists of an object which has the property "ddel" as
47512 * the drag proxy element.
47514 getDragData : function(e) {
47515 var target = this.findItemFromChild(e.getTarget());
47517 this.handleSelection(e);
47518 var selNodes = this.getSelectedNodes();
47521 copy: this.copy || (this.allowCopy && e.ctrlKey),
47525 var selectedIndices = this.getSelectedIndexes();
47526 for (var i = 0; i < selectedIndices.length; i++) {
47527 dragData.records.push(this.store.getAt(selectedIndices[i]));
47529 if (selNodes.length == 1) {
47530 dragData.ddel = target.cloneNode(true); // the div element
47532 var div = document.createElement('div'); // create the multi element drag "ghost"
47533 div.className = 'multi-proxy';
47534 for (var i = 0, len = selNodes.length; i < len; i++) {
47535 div.appendChild(selNodes[i].cloneNode(true));
47537 dragData.ddel = div;
47539 //console.log(dragData)
47540 //console.log(dragData.ddel.innerHTML)
47543 //console.log('nodragData')
47547 /** Specify to which ddGroup items in this DDView may be dragged. */
47548 setDraggable: function(ddGroup) {
47549 if (ddGroup instanceof Array) {
47550 Roo.each(ddGroup, this.setDraggable, this);
47553 if (this.dragZone) {
47554 this.dragZone.addToGroup(ddGroup);
47556 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
47557 containerScroll: true,
47561 // Draggability implies selection. DragZone's mousedown selects the element.
47562 if (!this.multiSelect) { this.singleSelect = true; }
47564 // Wire the DragZone's handlers up to methods in *this*
47565 this.dragZone.getDragData = this.getDragData.createDelegate(this);
47569 /** Specify from which ddGroup this DDView accepts drops. */
47570 setDroppable: function(ddGroup) {
47571 if (ddGroup instanceof Array) {
47572 Roo.each(ddGroup, this.setDroppable, this);
47575 if (this.dropZone) {
47576 this.dropZone.addToGroup(ddGroup);
47578 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
47579 containerScroll: true,
47583 // Wire the DropZone's handlers up to methods in *this*
47584 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
47585 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
47586 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
47587 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
47588 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
47592 /** Decide whether to drop above or below a View node. */
47593 getDropPoint : function(e, n, dd){
47594 if (n == this.el.dom) { return "above"; }
47595 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
47596 var c = t + (b - t) / 2;
47597 var y = Roo.lib.Event.getPageY(e);
47605 onNodeEnter : function(n, dd, e, data){
47609 onNodeOver : function(n, dd, e, data){
47610 var pt = this.getDropPoint(e, n, dd);
47611 // set the insert point style on the target node
47612 var dragElClass = this.dropNotAllowed;
47615 if (pt == "above"){
47616 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
47617 targetElClass = "x-view-drag-insert-above";
47619 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
47620 targetElClass = "x-view-drag-insert-below";
47622 if (this.lastInsertClass != targetElClass){
47623 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
47624 this.lastInsertClass = targetElClass;
47627 return dragElClass;
47630 onNodeOut : function(n, dd, e, data){
47631 this.removeDropIndicators(n);
47634 onNodeDrop : function(n, dd, e, data){
47635 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
47638 var pt = this.getDropPoint(e, n, dd);
47639 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
47640 if (pt == "below") { insertAt++; }
47641 for (var i = 0; i < data.records.length; i++) {
47642 var r = data.records[i];
47643 var dup = this.store.getById(r.id);
47644 if (dup && (dd != this.dragZone)) {
47645 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
47648 this.store.insert(insertAt++, r.copy());
47650 data.source.isDirtyFlag = true;
47652 this.store.insert(insertAt++, r);
47654 this.isDirtyFlag = true;
47657 this.dragZone.cachedTarget = null;
47661 removeDropIndicators : function(n){
47663 Roo.fly(n).removeClass([
47664 "x-view-drag-insert-above",
47665 "x-view-drag-insert-below"]);
47666 this.lastInsertClass = "_noclass";
47671 * Utility method. Add a delete option to the DDView's context menu.
47672 * @param {String} imageUrl The URL of the "delete" icon image.
47674 setDeletable: function(imageUrl) {
47675 if (!this.singleSelect && !this.multiSelect) {
47676 this.singleSelect = true;
47678 var c = this.getContextMenu();
47679 this.contextMenu.on("itemclick", function(item) {
47682 this.remove(this.getSelectedIndexes());
47686 this.contextMenu.add({
47693 /** Return the context menu for this DDView. */
47694 getContextMenu: function() {
47695 if (!this.contextMenu) {
47696 // Create the View's context menu
47697 this.contextMenu = new Roo.menu.Menu({
47698 id: this.id + "-contextmenu"
47700 this.el.on("contextmenu", this.showContextMenu, this);
47702 return this.contextMenu;
47705 disableContextMenu: function() {
47706 if (this.contextMenu) {
47707 this.el.un("contextmenu", this.showContextMenu, this);
47711 showContextMenu: function(e, item) {
47712 item = this.findItemFromChild(e.getTarget());
47715 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
47716 this.contextMenu.showAt(e.getXY());
47721 * Remove {@link Roo.data.Record}s at the specified indices.
47722 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
47724 remove: function(selectedIndices) {
47725 selectedIndices = [].concat(selectedIndices);
47726 for (var i = 0; i < selectedIndices.length; i++) {
47727 var rec = this.store.getAt(selectedIndices[i]);
47728 this.store.remove(rec);
47733 * Double click fires the event, but also, if this is draggable, and there is only one other
47734 * related DropZone, it transfers the selected node.
47736 onDblClick : function(e){
47737 var item = this.findItemFromChild(e.getTarget());
47739 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
47742 if (this.dragGroup) {
47743 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
47744 while (targets.indexOf(this.dropZone) > -1) {
47745 targets.remove(this.dropZone);
47747 if (targets.length == 1) {
47748 this.dragZone.cachedTarget = null;
47749 var el = Roo.get(targets[0].getEl());
47750 var box = el.getBox(true);
47751 targets[0].onNodeDrop(el.dom, {
47753 xy: [box.x, box.y + box.height - 1]
47754 }, null, this.getDragData(e));
47760 handleSelection: function(e) {
47761 this.dragZone.cachedTarget = null;
47762 var item = this.findItemFromChild(e.getTarget());
47764 this.clearSelections(true);
47767 if (item && (this.multiSelect || this.singleSelect)){
47768 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
47769 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
47770 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
47771 this.unselect(item);
47773 this.select(item, this.multiSelect && e.ctrlKey);
47774 this.lastSelection = item;
47779 onItemClick : function(item, index, e){
47780 if(this.fireEvent("beforeclick", this, index, item, e) === false){
47786 unselect : function(nodeInfo, suppressEvent){
47787 var node = this.getNode(nodeInfo);
47788 if(node && this.isSelected(node)){
47789 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
47790 Roo.fly(node).removeClass(this.selectedClass);
47791 this.selections.remove(node);
47792 if(!suppressEvent){
47793 this.fireEvent("selectionchange", this, this.selections);
47801 * Ext JS Library 1.1.1
47802 * Copyright(c) 2006-2007, Ext JS, LLC.
47804 * Originally Released Under LGPL - original licence link has changed is not relivant.
47807 * <script type="text/javascript">
47811 * @class Roo.LayoutManager
47812 * @extends Roo.util.Observable
47813 * Base class for layout managers.
47815 Roo.LayoutManager = function(container, config){
47816 Roo.LayoutManager.superclass.constructor.call(this);
47817 this.el = Roo.get(container);
47818 // ie scrollbar fix
47819 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
47820 document.body.scroll = "no";
47821 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
47822 this.el.position('relative');
47824 this.id = this.el.id;
47825 this.el.addClass("x-layout-container");
47826 /** false to disable window resize monitoring @type Boolean */
47827 this.monitorWindowResize = true;
47832 * Fires when a layout is performed.
47833 * @param {Roo.LayoutManager} this
47837 * @event regionresized
47838 * Fires when the user resizes a region.
47839 * @param {Roo.LayoutRegion} region The resized region
47840 * @param {Number} newSize The new size (width for east/west, height for north/south)
47842 "regionresized" : true,
47844 * @event regioncollapsed
47845 * Fires when a region is collapsed.
47846 * @param {Roo.LayoutRegion} region The collapsed region
47848 "regioncollapsed" : true,
47850 * @event regionexpanded
47851 * Fires when a region is expanded.
47852 * @param {Roo.LayoutRegion} region The expanded region
47854 "regionexpanded" : true
47856 this.updating = false;
47857 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47860 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
47862 * Returns true if this layout is currently being updated
47863 * @return {Boolean}
47865 isUpdating : function(){
47866 return this.updating;
47870 * Suspend the LayoutManager from doing auto-layouts while
47871 * making multiple add or remove calls
47873 beginUpdate : function(){
47874 this.updating = true;
47878 * Restore auto-layouts and optionally disable the manager from performing a layout
47879 * @param {Boolean} noLayout true to disable a layout update
47881 endUpdate : function(noLayout){
47882 this.updating = false;
47888 layout: function(){
47892 onRegionResized : function(region, newSize){
47893 this.fireEvent("regionresized", region, newSize);
47897 onRegionCollapsed : function(region){
47898 this.fireEvent("regioncollapsed", region);
47901 onRegionExpanded : function(region){
47902 this.fireEvent("regionexpanded", region);
47906 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
47907 * performs box-model adjustments.
47908 * @return {Object} The size as an object {width: (the width), height: (the height)}
47910 getViewSize : function(){
47912 if(this.el.dom != document.body){
47913 size = this.el.getSize();
47915 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
47917 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
47918 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
47923 * Returns the Element this layout is bound to.
47924 * @return {Roo.Element}
47926 getEl : function(){
47931 * Returns the specified region.
47932 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
47933 * @return {Roo.LayoutRegion}
47935 getRegion : function(target){
47936 return this.regions[target.toLowerCase()];
47939 onWindowResize : function(){
47940 if(this.monitorWindowResize){
47946 * Ext JS Library 1.1.1
47947 * Copyright(c) 2006-2007, Ext JS, LLC.
47949 * Originally Released Under LGPL - original licence link has changed is not relivant.
47952 * <script type="text/javascript">
47955 * @class Roo.BorderLayout
47956 * @extends Roo.LayoutManager
47957 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
47958 * please see: <br><br>
47959 * <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>
47960 * <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>
47963 var layout = new Roo.BorderLayout(document.body, {
47997 preferredTabWidth: 150
48002 var CP = Roo.ContentPanel;
48004 layout.beginUpdate();
48005 layout.add("north", new CP("north", "North"));
48006 layout.add("south", new CP("south", {title: "South", closable: true}));
48007 layout.add("west", new CP("west", {title: "West"}));
48008 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48009 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48010 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48011 layout.getRegion("center").showPanel("center1");
48012 layout.endUpdate();
48015 <b>The container the layout is rendered into can be either the body element or any other element.
48016 If it is not the body element, the container needs to either be an absolute positioned element,
48017 or you will need to add "position:relative" to the css of the container. You will also need to specify
48018 the container size if it is not the body element.</b>
48021 * Create a new BorderLayout
48022 * @param {String/HTMLElement/Element} container The container this layout is bound to
48023 * @param {Object} config Configuration options
48025 Roo.BorderLayout = function(container, config){
48026 config = config || {};
48027 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48028 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48029 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48030 var target = this.factory.validRegions[i];
48031 if(config[target]){
48032 this.addRegion(target, config[target]);
48037 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48039 * Creates and adds a new region if it doesn't already exist.
48040 * @param {String} target The target region key (north, south, east, west or center).
48041 * @param {Object} config The regions config object
48042 * @return {BorderLayoutRegion} The new region
48044 addRegion : function(target, config){
48045 if(!this.regions[target]){
48046 var r = this.factory.create(target, this, config);
48047 this.bindRegion(target, r);
48049 return this.regions[target];
48053 bindRegion : function(name, r){
48054 this.regions[name] = r;
48055 r.on("visibilitychange", this.layout, this);
48056 r.on("paneladded", this.layout, this);
48057 r.on("panelremoved", this.layout, this);
48058 r.on("invalidated", this.layout, this);
48059 r.on("resized", this.onRegionResized, this);
48060 r.on("collapsed", this.onRegionCollapsed, this);
48061 r.on("expanded", this.onRegionExpanded, this);
48065 * Performs a layout update.
48067 layout : function(){
48068 if(this.updating) return;
48069 var size = this.getViewSize();
48070 var w = size.width;
48071 var h = size.height;
48076 //var x = 0, y = 0;
48078 var rs = this.regions;
48079 var north = rs["north"];
48080 var south = rs["south"];
48081 var west = rs["west"];
48082 var east = rs["east"];
48083 var center = rs["center"];
48084 //if(this.hideOnLayout){ // not supported anymore
48085 //c.el.setStyle("display", "none");
48087 if(north && north.isVisible()){
48088 var b = north.getBox();
48089 var m = north.getMargins();
48090 b.width = w - (m.left+m.right);
48093 centerY = b.height + b.y + m.bottom;
48094 centerH -= centerY;
48095 north.updateBox(this.safeBox(b));
48097 if(south && south.isVisible()){
48098 var b = south.getBox();
48099 var m = south.getMargins();
48100 b.width = w - (m.left+m.right);
48102 var totalHeight = (b.height + m.top + m.bottom);
48103 b.y = h - totalHeight + m.top;
48104 centerH -= totalHeight;
48105 south.updateBox(this.safeBox(b));
48107 if(west && west.isVisible()){
48108 var b = west.getBox();
48109 var m = west.getMargins();
48110 b.height = centerH - (m.top+m.bottom);
48112 b.y = centerY + m.top;
48113 var totalWidth = (b.width + m.left + m.right);
48114 centerX += totalWidth;
48115 centerW -= totalWidth;
48116 west.updateBox(this.safeBox(b));
48118 if(east && east.isVisible()){
48119 var b = east.getBox();
48120 var m = east.getMargins();
48121 b.height = centerH - (m.top+m.bottom);
48122 var totalWidth = (b.width + m.left + m.right);
48123 b.x = w - totalWidth + m.left;
48124 b.y = centerY + m.top;
48125 centerW -= totalWidth;
48126 east.updateBox(this.safeBox(b));
48129 var m = center.getMargins();
48131 x: centerX + m.left,
48132 y: centerY + m.top,
48133 width: centerW - (m.left+m.right),
48134 height: centerH - (m.top+m.bottom)
48136 //if(this.hideOnLayout){
48137 //center.el.setStyle("display", "block");
48139 center.updateBox(this.safeBox(centerBox));
48142 this.fireEvent("layout", this);
48146 safeBox : function(box){
48147 box.width = Math.max(0, box.width);
48148 box.height = Math.max(0, box.height);
48153 * Adds a ContentPanel (or subclass) to this layout.
48154 * @param {String} target The target region key (north, south, east, west or center).
48155 * @param {Roo.ContentPanel} panel The panel to add
48156 * @return {Roo.ContentPanel} The added panel
48158 add : function(target, panel){
48160 target = target.toLowerCase();
48161 return this.regions[target].add(panel);
48165 * Remove a ContentPanel (or subclass) to this layout.
48166 * @param {String} target The target region key (north, south, east, west or center).
48167 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48168 * @return {Roo.ContentPanel} The removed panel
48170 remove : function(target, panel){
48171 target = target.toLowerCase();
48172 return this.regions[target].remove(panel);
48176 * Searches all regions for a panel with the specified id
48177 * @param {String} panelId
48178 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48180 findPanel : function(panelId){
48181 var rs = this.regions;
48182 for(var target in rs){
48183 if(typeof rs[target] != "function"){
48184 var p = rs[target].getPanel(panelId);
48194 * Searches all regions for a panel with the specified id and activates (shows) it.
48195 * @param {String/ContentPanel} panelId The panels id or the panel itself
48196 * @return {Roo.ContentPanel} The shown panel or null
48198 showPanel : function(panelId) {
48199 var rs = this.regions;
48200 for(var target in rs){
48201 var r = rs[target];
48202 if(typeof r != "function"){
48203 if(r.hasPanel(panelId)){
48204 return r.showPanel(panelId);
48212 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48213 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48215 restoreState : function(provider){
48217 provider = Roo.state.Manager;
48219 var sm = new Roo.LayoutStateManager();
48220 sm.init(this, provider);
48224 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48225 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48226 * a valid ContentPanel config object. Example:
48228 // Create the main layout
48229 var layout = new Roo.BorderLayout('main-ct', {
48240 // Create and add multiple ContentPanels at once via configs
48243 id: 'source-files',
48245 title:'Ext Source Files',
48258 * @param {Object} regions An object containing ContentPanel configs by region name
48260 batchAdd : function(regions){
48261 this.beginUpdate();
48262 for(var rname in regions){
48263 var lr = this.regions[rname];
48265 this.addTypedPanels(lr, regions[rname]);
48272 addTypedPanels : function(lr, ps){
48273 if(typeof ps == 'string'){
48274 lr.add(new Roo.ContentPanel(ps));
48276 else if(ps instanceof Array){
48277 for(var i =0, len = ps.length; i < len; i++){
48278 this.addTypedPanels(lr, ps[i]);
48281 else if(!ps.events){ // raw config?
48283 delete ps.el; // prevent conflict
48284 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48286 else { // panel object assumed!
48291 * Adds a xtype elements to the layout.
48295 xtype : 'ContentPanel',
48302 xtype : 'NestedLayoutPanel',
48308 items : [ ... list of content panels or nested layout panels.. ]
48312 * @param {Object} cfg Xtype definition of item to add.
48314 addxtype : function(cfg)
48316 // basically accepts a pannel...
48317 // can accept a layout region..!?!?
48318 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
48320 if (!cfg.xtype.match(/Panel$/)) {
48325 if (typeof(cfg.region) == 'undefined') {
48326 Roo.log("Failed to add Panel, region was not set");
48330 var region = cfg.region;
48336 xitems = cfg.items;
48343 case 'ContentPanel': // ContentPanel (el, cfg)
48344 case 'ScrollPanel': // ContentPanel (el, cfg)
48346 if(cfg.autoCreate) {
48347 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48349 var el = this.el.createChild();
48350 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
48353 this.add(region, ret);
48357 case 'TreePanel': // our new panel!
48358 cfg.el = this.el.createChild();
48359 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48360 this.add(region, ret);
48363 case 'NestedLayoutPanel':
48364 // create a new Layout (which is a Border Layout...
48365 var el = this.el.createChild();
48366 var clayout = cfg.layout;
48368 clayout.items = clayout.items || [];
48369 // replace this exitems with the clayout ones..
48370 xitems = clayout.items;
48373 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
48374 cfg.background = false;
48376 var layout = new Roo.BorderLayout(el, clayout);
48378 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
48379 //console.log('adding nested layout panel ' + cfg.toSource());
48380 this.add(region, ret);
48381 nb = {}; /// find first...
48386 // needs grid and region
48388 //var el = this.getRegion(region).el.createChild();
48389 var el = this.el.createChild();
48390 // create the grid first...
48392 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
48394 if (region == 'center' && this.active ) {
48395 cfg.background = false;
48397 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
48399 this.add(region, ret);
48400 if (cfg.background) {
48401 ret.on('activate', function(gp) {
48402 if (!gp.grid.rendered) {
48417 if (typeof(Roo[cfg.xtype]) != 'undefined') {
48419 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48420 this.add(region, ret);
48423 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
48427 // GridPanel (grid, cfg)
48430 this.beginUpdate();
48434 Roo.each(xitems, function(i) {
48435 region = nb && i.region ? i.region : false;
48437 var add = ret.addxtype(i);
48440 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
48441 if (!i.background) {
48442 abn[region] = nb[region] ;
48449 // make the last non-background panel active..
48450 //if (nb) { Roo.log(abn); }
48453 for(var r in abn) {
48454 region = this.getRegion(r);
48456 // tried using nb[r], but it does not work..
48458 region.showPanel(abn[r]);
48469 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
48470 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
48471 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
48472 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
48475 var CP = Roo.ContentPanel;
48477 var layout = Roo.BorderLayout.create({
48481 panels: [new CP("north", "North")]
48490 panels: [new CP("west", {title: "West"})]
48499 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
48508 panels: [new CP("south", {title: "South", closable: true})]
48515 preferredTabWidth: 150,
48517 new CP("center1", {title: "Close Me", closable: true}),
48518 new CP("center2", {title: "Center Panel", closable: false})
48523 layout.getRegion("center").showPanel("center1");
48528 Roo.BorderLayout.create = function(config, targetEl){
48529 var layout = new Roo.BorderLayout(targetEl || document.body, config);
48530 layout.beginUpdate();
48531 var regions = Roo.BorderLayout.RegionFactory.validRegions;
48532 for(var j = 0, jlen = regions.length; j < jlen; j++){
48533 var lr = regions[j];
48534 if(layout.regions[lr] && config[lr].panels){
48535 var r = layout.regions[lr];
48536 var ps = config[lr].panels;
48537 layout.addTypedPanels(r, ps);
48540 layout.endUpdate();
48545 Roo.BorderLayout.RegionFactory = {
48547 validRegions : ["north","south","east","west","center"],
48550 create : function(target, mgr, config){
48551 target = target.toLowerCase();
48552 if(config.lightweight || config.basic){
48553 return new Roo.BasicLayoutRegion(mgr, config, target);
48557 return new Roo.NorthLayoutRegion(mgr, config);
48559 return new Roo.SouthLayoutRegion(mgr, config);
48561 return new Roo.EastLayoutRegion(mgr, config);
48563 return new Roo.WestLayoutRegion(mgr, config);
48565 return new Roo.CenterLayoutRegion(mgr, config);
48567 throw 'Layout region "'+target+'" not supported.';
48571 * Ext JS Library 1.1.1
48572 * Copyright(c) 2006-2007, Ext JS, LLC.
48574 * Originally Released Under LGPL - original licence link has changed is not relivant.
48577 * <script type="text/javascript">
48581 * @class Roo.BasicLayoutRegion
48582 * @extends Roo.util.Observable
48583 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
48584 * and does not have a titlebar, tabs or any other features. All it does is size and position
48585 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
48587 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
48589 this.position = pos;
48592 * @scope Roo.BasicLayoutRegion
48596 * @event beforeremove
48597 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
48598 * @param {Roo.LayoutRegion} this
48599 * @param {Roo.ContentPanel} panel The panel
48600 * @param {Object} e The cancel event object
48602 "beforeremove" : true,
48604 * @event invalidated
48605 * Fires when the layout for this region is changed.
48606 * @param {Roo.LayoutRegion} this
48608 "invalidated" : true,
48610 * @event visibilitychange
48611 * Fires when this region is shown or hidden
48612 * @param {Roo.LayoutRegion} this
48613 * @param {Boolean} visibility true or false
48615 "visibilitychange" : true,
48617 * @event paneladded
48618 * Fires when a panel is added.
48619 * @param {Roo.LayoutRegion} this
48620 * @param {Roo.ContentPanel} panel The panel
48622 "paneladded" : true,
48624 * @event panelremoved
48625 * Fires when a panel is removed.
48626 * @param {Roo.LayoutRegion} this
48627 * @param {Roo.ContentPanel} panel The panel
48629 "panelremoved" : true,
48632 * Fires when this region is collapsed.
48633 * @param {Roo.LayoutRegion} this
48635 "collapsed" : true,
48638 * Fires when this region is expanded.
48639 * @param {Roo.LayoutRegion} this
48644 * Fires when this region is slid into view.
48645 * @param {Roo.LayoutRegion} this
48647 "slideshow" : true,
48650 * Fires when this region slides out of view.
48651 * @param {Roo.LayoutRegion} this
48653 "slidehide" : true,
48655 * @event panelactivated
48656 * Fires when a panel is activated.
48657 * @param {Roo.LayoutRegion} this
48658 * @param {Roo.ContentPanel} panel The activated panel
48660 "panelactivated" : true,
48663 * Fires when the user resizes this region.
48664 * @param {Roo.LayoutRegion} this
48665 * @param {Number} newSize The new size (width for east/west, height for north/south)
48669 /** A collection of panels in this region. @type Roo.util.MixedCollection */
48670 this.panels = new Roo.util.MixedCollection();
48671 this.panels.getKey = this.getPanelId.createDelegate(this);
48673 this.activePanel = null;
48674 // ensure listeners are added...
48676 if (config.listeners || config.events) {
48677 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
48678 listeners : config.listeners || {},
48679 events : config.events || {}
48683 if(skipConfig !== true){
48684 this.applyConfig(config);
48688 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
48689 getPanelId : function(p){
48693 applyConfig : function(config){
48694 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
48695 this.config = config;
48700 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
48701 * the width, for horizontal (north, south) the height.
48702 * @param {Number} newSize The new width or height
48704 resizeTo : function(newSize){
48705 var el = this.el ? this.el :
48706 (this.activePanel ? this.activePanel.getEl() : null);
48708 switch(this.position){
48711 el.setWidth(newSize);
48712 this.fireEvent("resized", this, newSize);
48716 el.setHeight(newSize);
48717 this.fireEvent("resized", this, newSize);
48723 getBox : function(){
48724 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
48727 getMargins : function(){
48728 return this.margins;
48731 updateBox : function(box){
48733 var el = this.activePanel.getEl();
48734 el.dom.style.left = box.x + "px";
48735 el.dom.style.top = box.y + "px";
48736 this.activePanel.setSize(box.width, box.height);
48740 * Returns the container element for this region.
48741 * @return {Roo.Element}
48743 getEl : function(){
48744 return this.activePanel;
48748 * Returns true if this region is currently visible.
48749 * @return {Boolean}
48751 isVisible : function(){
48752 return this.activePanel ? true : false;
48755 setActivePanel : function(panel){
48756 panel = this.getPanel(panel);
48757 if(this.activePanel && this.activePanel != panel){
48758 this.activePanel.setActiveState(false);
48759 this.activePanel.getEl().setLeftTop(-10000,-10000);
48761 this.activePanel = panel;
48762 panel.setActiveState(true);
48764 panel.setSize(this.box.width, this.box.height);
48766 this.fireEvent("panelactivated", this, panel);
48767 this.fireEvent("invalidated");
48771 * Show the specified panel.
48772 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
48773 * @return {Roo.ContentPanel} The shown panel or null
48775 showPanel : function(panel){
48776 if(panel = this.getPanel(panel)){
48777 this.setActivePanel(panel);
48783 * Get the active panel for this region.
48784 * @return {Roo.ContentPanel} The active panel or null
48786 getActivePanel : function(){
48787 return this.activePanel;
48791 * Add the passed ContentPanel(s)
48792 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48793 * @return {Roo.ContentPanel} The panel added (if only one was added)
48795 add : function(panel){
48796 if(arguments.length > 1){
48797 for(var i = 0, len = arguments.length; i < len; i++) {
48798 this.add(arguments[i]);
48802 if(this.hasPanel(panel)){
48803 this.showPanel(panel);
48806 var el = panel.getEl();
48807 if(el.dom.parentNode != this.mgr.el.dom){
48808 this.mgr.el.dom.appendChild(el.dom);
48810 if(panel.setRegion){
48811 panel.setRegion(this);
48813 this.panels.add(panel);
48814 el.setStyle("position", "absolute");
48815 if(!panel.background){
48816 this.setActivePanel(panel);
48817 if(this.config.initialSize && this.panels.getCount()==1){
48818 this.resizeTo(this.config.initialSize);
48821 this.fireEvent("paneladded", this, panel);
48826 * Returns true if the panel is in this region.
48827 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48828 * @return {Boolean}
48830 hasPanel : function(panel){
48831 if(typeof panel == "object"){ // must be panel obj
48832 panel = panel.getId();
48834 return this.getPanel(panel) ? true : false;
48838 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48839 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48840 * @param {Boolean} preservePanel Overrides the config preservePanel option
48841 * @return {Roo.ContentPanel} The panel that was removed
48843 remove : function(panel, preservePanel){
48844 panel = this.getPanel(panel);
48849 this.fireEvent("beforeremove", this, panel, e);
48850 if(e.cancel === true){
48853 var panelId = panel.getId();
48854 this.panels.removeKey(panelId);
48859 * Returns the panel specified or null if it's not in this region.
48860 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
48861 * @return {Roo.ContentPanel}
48863 getPanel : function(id){
48864 if(typeof id == "object"){ // must be panel obj
48867 return this.panels.get(id);
48871 * Returns this regions position (north/south/east/west/center).
48874 getPosition: function(){
48875 return this.position;
48879 * Ext JS Library 1.1.1
48880 * Copyright(c) 2006-2007, Ext JS, LLC.
48882 * Originally Released Under LGPL - original licence link has changed is not relivant.
48885 * <script type="text/javascript">
48889 * @class Roo.LayoutRegion
48890 * @extends Roo.BasicLayoutRegion
48891 * This class represents a region in a layout manager.
48892 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
48893 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
48894 * @cfg {Boolean} floatable False to disable floating (defaults to true)
48895 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
48896 * @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})
48897 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
48898 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
48899 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
48900 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
48901 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
48902 * @cfg {String} title The title for the region (overrides panel titles)
48903 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
48904 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
48905 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
48906 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
48907 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
48908 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
48909 * the space available, similar to FireFox 1.5 tabs (defaults to false)
48910 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
48911 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
48912 * @cfg {Boolean} showPin True to show a pin button
48913 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
48914 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
48915 * @cfg {Boolean} disableTabTips True to disable tab tooltips
48916 * @cfg {Number} width For East/West panels
48917 * @cfg {Number} height For North/South panels
48918 * @cfg {Boolean} split To show the splitter
48919 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
48921 Roo.LayoutRegion = function(mgr, config, pos){
48922 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
48923 var dh = Roo.DomHelper;
48924 /** This region's container element
48925 * @type Roo.Element */
48926 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
48927 /** This region's title element
48928 * @type Roo.Element */
48930 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
48931 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
48932 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
48934 this.titleEl.enableDisplayMode();
48935 /** This region's title text element
48936 * @type HTMLElement */
48937 this.titleTextEl = this.titleEl.dom.firstChild;
48938 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
48939 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
48940 this.closeBtn.enableDisplayMode();
48941 this.closeBtn.on("click", this.closeClicked, this);
48942 this.closeBtn.hide();
48944 this.createBody(config);
48945 this.visible = true;
48946 this.collapsed = false;
48948 if(config.hideWhenEmpty){
48950 this.on("paneladded", this.validateVisibility, this);
48951 this.on("panelremoved", this.validateVisibility, this);
48953 this.applyConfig(config);
48956 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
48958 createBody : function(){
48959 /** This region's body element
48960 * @type Roo.Element */
48961 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
48964 applyConfig : function(c){
48965 if(c.collapsible && this.position != "center" && !this.collapsedEl){
48966 var dh = Roo.DomHelper;
48967 if(c.titlebar !== false){
48968 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
48969 this.collapseBtn.on("click", this.collapse, this);
48970 this.collapseBtn.enableDisplayMode();
48972 if(c.showPin === true || this.showPin){
48973 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
48974 this.stickBtn.enableDisplayMode();
48975 this.stickBtn.on("click", this.expand, this);
48976 this.stickBtn.hide();
48979 /** This region's collapsed element
48980 * @type Roo.Element */
48981 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
48982 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
48984 if(c.floatable !== false){
48985 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
48986 this.collapsedEl.on("click", this.collapseClick, this);
48989 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
48990 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
48991 id: "message", unselectable: "on", style:{"float":"left"}});
48992 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
48994 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
48995 this.expandBtn.on("click", this.expand, this);
48997 if(this.collapseBtn){
48998 this.collapseBtn.setVisible(c.collapsible == true);
49000 this.cmargins = c.cmargins || this.cmargins ||
49001 (this.position == "west" || this.position == "east" ?
49002 {top: 0, left: 2, right:2, bottom: 0} :
49003 {top: 2, left: 0, right:0, bottom: 2});
49004 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49005 this.bottomTabs = c.tabPosition != "top";
49006 this.autoScroll = c.autoScroll || false;
49007 if(this.autoScroll){
49008 this.bodyEl.setStyle("overflow", "auto");
49010 this.bodyEl.setStyle("overflow", "hidden");
49012 //if(c.titlebar !== false){
49013 if((!c.titlebar && !c.title) || c.titlebar === false){
49014 this.titleEl.hide();
49016 this.titleEl.show();
49018 this.titleTextEl.innerHTML = c.title;
49022 this.duration = c.duration || .30;
49023 this.slideDuration = c.slideDuration || .45;
49026 this.collapse(true);
49033 * Returns true if this region is currently visible.
49034 * @return {Boolean}
49036 isVisible : function(){
49037 return this.visible;
49041 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49042 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49044 setCollapsedTitle : function(title){
49045 title = title || " ";
49046 if(this.collapsedTitleTextEl){
49047 this.collapsedTitleTextEl.innerHTML = title;
49051 getBox : function(){
49053 if(!this.collapsed){
49054 b = this.el.getBox(false, true);
49056 b = this.collapsedEl.getBox(false, true);
49061 getMargins : function(){
49062 return this.collapsed ? this.cmargins : this.margins;
49065 highlight : function(){
49066 this.el.addClass("x-layout-panel-dragover");
49069 unhighlight : function(){
49070 this.el.removeClass("x-layout-panel-dragover");
49073 updateBox : function(box){
49075 if(!this.collapsed){
49076 this.el.dom.style.left = box.x + "px";
49077 this.el.dom.style.top = box.y + "px";
49078 this.updateBody(box.width, box.height);
49080 this.collapsedEl.dom.style.left = box.x + "px";
49081 this.collapsedEl.dom.style.top = box.y + "px";
49082 this.collapsedEl.setSize(box.width, box.height);
49085 this.tabs.autoSizeTabs();
49089 updateBody : function(w, h){
49091 this.el.setWidth(w);
49092 w -= this.el.getBorderWidth("rl");
49093 if(this.config.adjustments){
49094 w += this.config.adjustments[0];
49098 this.el.setHeight(h);
49099 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49100 h -= this.el.getBorderWidth("tb");
49101 if(this.config.adjustments){
49102 h += this.config.adjustments[1];
49104 this.bodyEl.setHeight(h);
49106 h = this.tabs.syncHeight(h);
49109 if(this.panelSize){
49110 w = w !== null ? w : this.panelSize.width;
49111 h = h !== null ? h : this.panelSize.height;
49113 if(this.activePanel){
49114 var el = this.activePanel.getEl();
49115 w = w !== null ? w : el.getWidth();
49116 h = h !== null ? h : el.getHeight();
49117 this.panelSize = {width: w, height: h};
49118 this.activePanel.setSize(w, h);
49120 if(Roo.isIE && this.tabs){
49121 this.tabs.el.repaint();
49126 * Returns the container element for this region.
49127 * @return {Roo.Element}
49129 getEl : function(){
49134 * Hides this region.
49137 if(!this.collapsed){
49138 this.el.dom.style.left = "-2000px";
49141 this.collapsedEl.dom.style.left = "-2000px";
49142 this.collapsedEl.hide();
49144 this.visible = false;
49145 this.fireEvent("visibilitychange", this, false);
49149 * Shows this region if it was previously hidden.
49152 if(!this.collapsed){
49155 this.collapsedEl.show();
49157 this.visible = true;
49158 this.fireEvent("visibilitychange", this, true);
49161 closeClicked : function(){
49162 if(this.activePanel){
49163 this.remove(this.activePanel);
49167 collapseClick : function(e){
49169 e.stopPropagation();
49172 e.stopPropagation();
49178 * Collapses this region.
49179 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49181 collapse : function(skipAnim){
49182 if(this.collapsed) return;
49183 this.collapsed = true;
49185 this.split.el.hide();
49187 if(this.config.animate && skipAnim !== true){
49188 this.fireEvent("invalidated", this);
49189 this.animateCollapse();
49191 this.el.setLocation(-20000,-20000);
49193 this.collapsedEl.show();
49194 this.fireEvent("collapsed", this);
49195 this.fireEvent("invalidated", this);
49199 animateCollapse : function(){
49204 * Expands this region if it was previously collapsed.
49205 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49206 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49208 expand : function(e, skipAnim){
49209 if(e) e.stopPropagation();
49210 if(!this.collapsed || this.el.hasActiveFx()) return;
49212 this.afterSlideIn();
49215 this.collapsed = false;
49216 if(this.config.animate && skipAnim !== true){
49217 this.animateExpand();
49221 this.split.el.show();
49223 this.collapsedEl.setLocation(-2000,-2000);
49224 this.collapsedEl.hide();
49225 this.fireEvent("invalidated", this);
49226 this.fireEvent("expanded", this);
49230 animateExpand : function(){
49234 initTabs : function()
49236 this.bodyEl.setStyle("overflow", "hidden");
49237 var ts = new Roo.TabPanel(
49240 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49241 disableTooltips: this.config.disableTabTips,
49242 toolbar : this.config.toolbar
49245 if(this.config.hideTabs){
49246 ts.stripWrap.setDisplayed(false);
49249 ts.resizeTabs = this.config.resizeTabs === true;
49250 ts.minTabWidth = this.config.minTabWidth || 40;
49251 ts.maxTabWidth = this.config.maxTabWidth || 250;
49252 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49253 ts.monitorResize = false;
49254 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49255 ts.bodyEl.addClass('x-layout-tabs-body');
49256 this.panels.each(this.initPanelAsTab, this);
49259 initPanelAsTab : function(panel){
49260 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49261 this.config.closeOnTab && panel.isClosable());
49262 if(panel.tabTip !== undefined){
49263 ti.setTooltip(panel.tabTip);
49265 ti.on("activate", function(){
49266 this.setActivePanel(panel);
49268 if(this.config.closeOnTab){
49269 ti.on("beforeclose", function(t, e){
49271 this.remove(panel);
49277 updatePanelTitle : function(panel, title){
49278 if(this.activePanel == panel){
49279 this.updateTitle(title);
49282 var ti = this.tabs.getTab(panel.getEl().id);
49284 if(panel.tabTip !== undefined){
49285 ti.setTooltip(panel.tabTip);
49290 updateTitle : function(title){
49291 if(this.titleTextEl && !this.config.title){
49292 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
49296 setActivePanel : function(panel){
49297 panel = this.getPanel(panel);
49298 if(this.activePanel && this.activePanel != panel){
49299 this.activePanel.setActiveState(false);
49301 this.activePanel = panel;
49302 panel.setActiveState(true);
49303 if(this.panelSize){
49304 panel.setSize(this.panelSize.width, this.panelSize.height);
49307 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
49309 this.updateTitle(panel.getTitle());
49311 this.fireEvent("invalidated", this);
49313 this.fireEvent("panelactivated", this, panel);
49317 * Shows the specified panel.
49318 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
49319 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
49321 showPanel : function(panel){
49322 if(panel = this.getPanel(panel)){
49324 var tab = this.tabs.getTab(panel.getEl().id);
49325 if(tab.isHidden()){
49326 this.tabs.unhideTab(tab.id);
49330 this.setActivePanel(panel);
49337 * Get the active panel for this region.
49338 * @return {Roo.ContentPanel} The active panel or null
49340 getActivePanel : function(){
49341 return this.activePanel;
49344 validateVisibility : function(){
49345 if(this.panels.getCount() < 1){
49346 this.updateTitle(" ");
49347 this.closeBtn.hide();
49350 if(!this.isVisible()){
49357 * Adds the passed ContentPanel(s) to this region.
49358 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49359 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
49361 add : function(panel){
49362 if(arguments.length > 1){
49363 for(var i = 0, len = arguments.length; i < len; i++) {
49364 this.add(arguments[i]);
49368 if(this.hasPanel(panel)){
49369 this.showPanel(panel);
49372 panel.setRegion(this);
49373 this.panels.add(panel);
49374 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
49375 this.bodyEl.dom.appendChild(panel.getEl().dom);
49376 if(panel.background !== true){
49377 this.setActivePanel(panel);
49379 this.fireEvent("paneladded", this, panel);
49385 this.initPanelAsTab(panel);
49387 if(panel.background !== true){
49388 this.tabs.activate(panel.getEl().id);
49390 this.fireEvent("paneladded", this, panel);
49395 * Hides the tab for the specified panel.
49396 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49398 hidePanel : function(panel){
49399 if(this.tabs && (panel = this.getPanel(panel))){
49400 this.tabs.hideTab(panel.getEl().id);
49405 * Unhides the tab for a previously hidden panel.
49406 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49408 unhidePanel : function(panel){
49409 if(this.tabs && (panel = this.getPanel(panel))){
49410 this.tabs.unhideTab(panel.getEl().id);
49414 clearPanels : function(){
49415 while(this.panels.getCount() > 0){
49416 this.remove(this.panels.first());
49421 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49422 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49423 * @param {Boolean} preservePanel Overrides the config preservePanel option
49424 * @return {Roo.ContentPanel} The panel that was removed
49426 remove : function(panel, preservePanel){
49427 panel = this.getPanel(panel);
49432 this.fireEvent("beforeremove", this, panel, e);
49433 if(e.cancel === true){
49436 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
49437 var panelId = panel.getId();
49438 this.panels.removeKey(panelId);
49440 document.body.appendChild(panel.getEl().dom);
49443 this.tabs.removeTab(panel.getEl().id);
49444 }else if (!preservePanel){
49445 this.bodyEl.dom.removeChild(panel.getEl().dom);
49447 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
49448 var p = this.panels.first();
49449 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
49450 tempEl.appendChild(p.getEl().dom);
49451 this.bodyEl.update("");
49452 this.bodyEl.dom.appendChild(p.getEl().dom);
49454 this.updateTitle(p.getTitle());
49456 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49457 this.setActivePanel(p);
49459 panel.setRegion(null);
49460 if(this.activePanel == panel){
49461 this.activePanel = null;
49463 if(this.config.autoDestroy !== false && preservePanel !== true){
49464 try{panel.destroy();}catch(e){}
49466 this.fireEvent("panelremoved", this, panel);
49471 * Returns the TabPanel component used by this region
49472 * @return {Roo.TabPanel}
49474 getTabs : function(){
49478 createTool : function(parentEl, className){
49479 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
49480 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
49481 btn.addClassOnOver("x-layout-tools-button-over");
49486 * Ext JS Library 1.1.1
49487 * Copyright(c) 2006-2007, Ext JS, LLC.
49489 * Originally Released Under LGPL - original licence link has changed is not relivant.
49492 * <script type="text/javascript">
49498 * @class Roo.SplitLayoutRegion
49499 * @extends Roo.LayoutRegion
49500 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
49502 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
49503 this.cursor = cursor;
49504 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
49507 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
49508 splitTip : "Drag to resize.",
49509 collapsibleSplitTip : "Drag to resize. Double click to hide.",
49510 useSplitTips : false,
49512 applyConfig : function(config){
49513 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
49516 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
49517 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
49518 /** The SplitBar for this region
49519 * @type Roo.SplitBar */
49520 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
49521 this.split.on("moved", this.onSplitMove, this);
49522 this.split.useShim = config.useShim === true;
49523 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
49524 if(this.useSplitTips){
49525 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
49527 if(config.collapsible){
49528 this.split.el.on("dblclick", this.collapse, this);
49531 if(typeof config.minSize != "undefined"){
49532 this.split.minSize = config.minSize;
49534 if(typeof config.maxSize != "undefined"){
49535 this.split.maxSize = config.maxSize;
49537 if(config.hideWhenEmpty || config.hidden || config.collapsed){
49538 this.hideSplitter();
49543 getHMaxSize : function(){
49544 var cmax = this.config.maxSize || 10000;
49545 var center = this.mgr.getRegion("center");
49546 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
49549 getVMaxSize : function(){
49550 var cmax = this.config.maxSize || 10000;
49551 var center = this.mgr.getRegion("center");
49552 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
49555 onSplitMove : function(split, newSize){
49556 this.fireEvent("resized", this, newSize);
49560 * Returns the {@link Roo.SplitBar} for this region.
49561 * @return {Roo.SplitBar}
49563 getSplitBar : function(){
49568 this.hideSplitter();
49569 Roo.SplitLayoutRegion.superclass.hide.call(this);
49572 hideSplitter : function(){
49574 this.split.el.setLocation(-2000,-2000);
49575 this.split.el.hide();
49581 this.split.el.show();
49583 Roo.SplitLayoutRegion.superclass.show.call(this);
49586 beforeSlide: function(){
49587 if(Roo.isGecko){// firefox overflow auto bug workaround
49588 this.bodyEl.clip();
49589 if(this.tabs) this.tabs.bodyEl.clip();
49590 if(this.activePanel){
49591 this.activePanel.getEl().clip();
49593 if(this.activePanel.beforeSlide){
49594 this.activePanel.beforeSlide();
49600 afterSlide : function(){
49601 if(Roo.isGecko){// firefox overflow auto bug workaround
49602 this.bodyEl.unclip();
49603 if(this.tabs) this.tabs.bodyEl.unclip();
49604 if(this.activePanel){
49605 this.activePanel.getEl().unclip();
49606 if(this.activePanel.afterSlide){
49607 this.activePanel.afterSlide();
49613 initAutoHide : function(){
49614 if(this.autoHide !== false){
49615 if(!this.autoHideHd){
49616 var st = new Roo.util.DelayedTask(this.slideIn, this);
49617 this.autoHideHd = {
49618 "mouseout": function(e){
49619 if(!e.within(this.el, true)){
49623 "mouseover" : function(e){
49629 this.el.on(this.autoHideHd);
49633 clearAutoHide : function(){
49634 if(this.autoHide !== false){
49635 this.el.un("mouseout", this.autoHideHd.mouseout);
49636 this.el.un("mouseover", this.autoHideHd.mouseover);
49640 clearMonitor : function(){
49641 Roo.get(document).un("click", this.slideInIf, this);
49644 // these names are backwards but not changed for compat
49645 slideOut : function(){
49646 if(this.isSlid || this.el.hasActiveFx()){
49649 this.isSlid = true;
49650 if(this.collapseBtn){
49651 this.collapseBtn.hide();
49653 this.closeBtnState = this.closeBtn.getStyle('display');
49654 this.closeBtn.hide();
49656 this.stickBtn.show();
49659 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
49660 this.beforeSlide();
49661 this.el.setStyle("z-index", 10001);
49662 this.el.slideIn(this.getSlideAnchor(), {
49663 callback: function(){
49665 this.initAutoHide();
49666 Roo.get(document).on("click", this.slideInIf, this);
49667 this.fireEvent("slideshow", this);
49674 afterSlideIn : function(){
49675 this.clearAutoHide();
49676 this.isSlid = false;
49677 this.clearMonitor();
49678 this.el.setStyle("z-index", "");
49679 if(this.collapseBtn){
49680 this.collapseBtn.show();
49682 this.closeBtn.setStyle('display', this.closeBtnState);
49684 this.stickBtn.hide();
49686 this.fireEvent("slidehide", this);
49689 slideIn : function(cb){
49690 if(!this.isSlid || this.el.hasActiveFx()){
49694 this.isSlid = false;
49695 this.beforeSlide();
49696 this.el.slideOut(this.getSlideAnchor(), {
49697 callback: function(){
49698 this.el.setLeftTop(-10000, -10000);
49700 this.afterSlideIn();
49708 slideInIf : function(e){
49709 if(!e.within(this.el)){
49714 animateCollapse : function(){
49715 this.beforeSlide();
49716 this.el.setStyle("z-index", 20000);
49717 var anchor = this.getSlideAnchor();
49718 this.el.slideOut(anchor, {
49719 callback : function(){
49720 this.el.setStyle("z-index", "");
49721 this.collapsedEl.slideIn(anchor, {duration:.3});
49723 this.el.setLocation(-10000,-10000);
49725 this.fireEvent("collapsed", this);
49732 animateExpand : function(){
49733 this.beforeSlide();
49734 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
49735 this.el.setStyle("z-index", 20000);
49736 this.collapsedEl.hide({
49739 this.el.slideIn(this.getSlideAnchor(), {
49740 callback : function(){
49741 this.el.setStyle("z-index", "");
49744 this.split.el.show();
49746 this.fireEvent("invalidated", this);
49747 this.fireEvent("expanded", this);
49775 getAnchor : function(){
49776 return this.anchors[this.position];
49779 getCollapseAnchor : function(){
49780 return this.canchors[this.position];
49783 getSlideAnchor : function(){
49784 return this.sanchors[this.position];
49787 getAlignAdj : function(){
49788 var cm = this.cmargins;
49789 switch(this.position){
49805 getExpandAdj : function(){
49806 var c = this.collapsedEl, cm = this.cmargins;
49807 switch(this.position){
49809 return [-(cm.right+c.getWidth()+cm.left), 0];
49812 return [cm.right+c.getWidth()+cm.left, 0];
49815 return [0, -(cm.top+cm.bottom+c.getHeight())];
49818 return [0, cm.top+cm.bottom+c.getHeight()];
49824 * Ext JS Library 1.1.1
49825 * Copyright(c) 2006-2007, Ext JS, LLC.
49827 * Originally Released Under LGPL - original licence link has changed is not relivant.
49830 * <script type="text/javascript">
49833 * These classes are private internal classes
49835 Roo.CenterLayoutRegion = function(mgr, config){
49836 Roo.LayoutRegion.call(this, mgr, config, "center");
49837 this.visible = true;
49838 this.minWidth = config.minWidth || 20;
49839 this.minHeight = config.minHeight || 20;
49842 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
49844 // center panel can't be hidden
49848 // center panel can't be hidden
49851 getMinWidth: function(){
49852 return this.minWidth;
49855 getMinHeight: function(){
49856 return this.minHeight;
49861 Roo.NorthLayoutRegion = function(mgr, config){
49862 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
49864 this.split.placement = Roo.SplitBar.TOP;
49865 this.split.orientation = Roo.SplitBar.VERTICAL;
49866 this.split.el.addClass("x-layout-split-v");
49868 var size = config.initialSize || config.height;
49869 if(typeof size != "undefined"){
49870 this.el.setHeight(size);
49873 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
49874 orientation: Roo.SplitBar.VERTICAL,
49875 getBox : function(){
49876 if(this.collapsed){
49877 return this.collapsedEl.getBox();
49879 var box = this.el.getBox();
49881 box.height += this.split.el.getHeight();
49886 updateBox : function(box){
49887 if(this.split && !this.collapsed){
49888 box.height -= this.split.el.getHeight();
49889 this.split.el.setLeft(box.x);
49890 this.split.el.setTop(box.y+box.height);
49891 this.split.el.setWidth(box.width);
49893 if(this.collapsed){
49894 this.updateBody(box.width, null);
49896 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49900 Roo.SouthLayoutRegion = function(mgr, config){
49901 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
49903 this.split.placement = Roo.SplitBar.BOTTOM;
49904 this.split.orientation = Roo.SplitBar.VERTICAL;
49905 this.split.el.addClass("x-layout-split-v");
49907 var size = config.initialSize || config.height;
49908 if(typeof size != "undefined"){
49909 this.el.setHeight(size);
49912 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
49913 orientation: Roo.SplitBar.VERTICAL,
49914 getBox : function(){
49915 if(this.collapsed){
49916 return this.collapsedEl.getBox();
49918 var box = this.el.getBox();
49920 var sh = this.split.el.getHeight();
49927 updateBox : function(box){
49928 if(this.split && !this.collapsed){
49929 var sh = this.split.el.getHeight();
49932 this.split.el.setLeft(box.x);
49933 this.split.el.setTop(box.y-sh);
49934 this.split.el.setWidth(box.width);
49936 if(this.collapsed){
49937 this.updateBody(box.width, null);
49939 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49943 Roo.EastLayoutRegion = function(mgr, config){
49944 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
49946 this.split.placement = Roo.SplitBar.RIGHT;
49947 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49948 this.split.el.addClass("x-layout-split-h");
49950 var size = config.initialSize || config.width;
49951 if(typeof size != "undefined"){
49952 this.el.setWidth(size);
49955 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
49956 orientation: Roo.SplitBar.HORIZONTAL,
49957 getBox : function(){
49958 if(this.collapsed){
49959 return this.collapsedEl.getBox();
49961 var box = this.el.getBox();
49963 var sw = this.split.el.getWidth();
49970 updateBox : function(box){
49971 if(this.split && !this.collapsed){
49972 var sw = this.split.el.getWidth();
49974 this.split.el.setLeft(box.x);
49975 this.split.el.setTop(box.y);
49976 this.split.el.setHeight(box.height);
49979 if(this.collapsed){
49980 this.updateBody(null, box.height);
49982 Roo.LayoutRegion.prototype.updateBox.call(this, box);
49986 Roo.WestLayoutRegion = function(mgr, config){
49987 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
49989 this.split.placement = Roo.SplitBar.LEFT;
49990 this.split.orientation = Roo.SplitBar.HORIZONTAL;
49991 this.split.el.addClass("x-layout-split-h");
49993 var size = config.initialSize || config.width;
49994 if(typeof size != "undefined"){
49995 this.el.setWidth(size);
49998 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
49999 orientation: Roo.SplitBar.HORIZONTAL,
50000 getBox : function(){
50001 if(this.collapsed){
50002 return this.collapsedEl.getBox();
50004 var box = this.el.getBox();
50006 box.width += this.split.el.getWidth();
50011 updateBox : function(box){
50012 if(this.split && !this.collapsed){
50013 var sw = this.split.el.getWidth();
50015 this.split.el.setLeft(box.x+box.width);
50016 this.split.el.setTop(box.y);
50017 this.split.el.setHeight(box.height);
50019 if(this.collapsed){
50020 this.updateBody(null, box.height);
50022 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50027 * Ext JS Library 1.1.1
50028 * Copyright(c) 2006-2007, Ext JS, LLC.
50030 * Originally Released Under LGPL - original licence link has changed is not relivant.
50033 * <script type="text/javascript">
50038 * Private internal class for reading and applying state
50040 Roo.LayoutStateManager = function(layout){
50041 // default empty state
50050 Roo.LayoutStateManager.prototype = {
50051 init : function(layout, provider){
50052 this.provider = provider;
50053 var state = provider.get(layout.id+"-layout-state");
50055 var wasUpdating = layout.isUpdating();
50057 layout.beginUpdate();
50059 for(var key in state){
50060 if(typeof state[key] != "function"){
50061 var rstate = state[key];
50062 var r = layout.getRegion(key);
50065 r.resizeTo(rstate.size);
50067 if(rstate.collapsed == true){
50070 r.expand(null, true);
50076 layout.endUpdate();
50078 this.state = state;
50080 this.layout = layout;
50081 layout.on("regionresized", this.onRegionResized, this);
50082 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50083 layout.on("regionexpanded", this.onRegionExpanded, this);
50086 storeState : function(){
50087 this.provider.set(this.layout.id+"-layout-state", this.state);
50090 onRegionResized : function(region, newSize){
50091 this.state[region.getPosition()].size = newSize;
50095 onRegionCollapsed : function(region){
50096 this.state[region.getPosition()].collapsed = true;
50100 onRegionExpanded : function(region){
50101 this.state[region.getPosition()].collapsed = false;
50106 * Ext JS Library 1.1.1
50107 * Copyright(c) 2006-2007, Ext JS, LLC.
50109 * Originally Released Under LGPL - original licence link has changed is not relivant.
50112 * <script type="text/javascript">
50115 * @class Roo.ContentPanel
50116 * @extends Roo.util.Observable
50117 * A basic ContentPanel element.
50118 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50119 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50120 * @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
50121 * @cfg {Boolean} closable True if the panel can be closed/removed
50122 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50123 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50124 * @cfg {Toolbar} toolbar A toolbar for this panel
50125 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50126 * @cfg {String} title The title for this panel
50127 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50128 * @cfg {String} url Calls {@link #setUrl} with this value
50129 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50130 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50131 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50132 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50135 * Create a new ContentPanel.
50136 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50137 * @param {String/Object} config A string to set only the title or a config object
50138 * @param {String} content (optional) Set the HTML content for this panel
50139 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50141 Roo.ContentPanel = function(el, config, content){
50145 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50149 if (config && config.parentLayout) {
50150 el = config.parentLayout.el.createChild();
50153 if(el.autoCreate){ // xtype is available if this is called from factory
50157 this.el = Roo.get(el);
50158 if(!this.el && config && config.autoCreate){
50159 if(typeof config.autoCreate == "object"){
50160 if(!config.autoCreate.id){
50161 config.autoCreate.id = config.id||el;
50163 this.el = Roo.DomHelper.append(document.body,
50164 config.autoCreate, true);
50166 this.el = Roo.DomHelper.append(document.body,
50167 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50170 this.closable = false;
50171 this.loaded = false;
50172 this.active = false;
50173 if(typeof config == "string"){
50174 this.title = config;
50176 Roo.apply(this, config);
50179 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50180 this.wrapEl = this.el.wrap();
50181 this.toolbar.container = this.el.insertSibling(false, 'before');
50182 this.toolbar = new Roo.Toolbar(this.toolbar);
50185 // xtype created footer. - not sure if will work as we normally have to render first..
50186 if (this.footer && !this.footer.el && this.footer.xtype) {
50187 if (!this.wrapEl) {
50188 this.wrapEl = this.el.wrap();
50191 this.footer.container = this.wrapEl.createChild();
50193 this.footer = Roo.factory(this.footer, Roo);
50198 this.resizeEl = Roo.get(this.resizeEl, true);
50200 this.resizeEl = this.el;
50202 // handle view.xtype
50210 * Fires when this panel is activated.
50211 * @param {Roo.ContentPanel} this
50215 * @event deactivate
50216 * Fires when this panel is activated.
50217 * @param {Roo.ContentPanel} this
50219 "deactivate" : true,
50223 * Fires when this panel is resized if fitToFrame is true.
50224 * @param {Roo.ContentPanel} this
50225 * @param {Number} width The width after any component adjustments
50226 * @param {Number} height The height after any component adjustments
50232 * Fires when this tab is created
50233 * @param {Roo.ContentPanel} this
50244 if(this.autoScroll){
50245 this.resizeEl.setStyle("overflow", "auto");
50247 // fix randome scrolling
50248 this.el.on('scroll', function() {
50249 Roo.log('fix random scolling');
50250 this.scrollTo('top',0);
50253 content = content || this.content;
50255 this.setContent(content);
50257 if(config && config.url){
50258 this.setUrl(this.url, this.params, this.loadOnce);
50263 Roo.ContentPanel.superclass.constructor.call(this);
50265 if (this.view && typeof(this.view.xtype) != 'undefined') {
50266 this.view.el = this.el.appendChild(document.createElement("div"));
50267 this.view = Roo.factory(this.view);
50268 this.view.render && this.view.render(false, '');
50272 this.fireEvent('render', this);
50275 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50277 setRegion : function(region){
50278 this.region = region;
50280 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50282 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50287 * Returns the toolbar for this Panel if one was configured.
50288 * @return {Roo.Toolbar}
50290 getToolbar : function(){
50291 return this.toolbar;
50294 setActiveState : function(active){
50295 this.active = active;
50297 this.fireEvent("deactivate", this);
50299 this.fireEvent("activate", this);
50303 * Updates this panel's element
50304 * @param {String} content The new content
50305 * @param {Boolean} loadScripts (optional) true to look for and process scripts
50307 setContent : function(content, loadScripts){
50308 this.el.update(content, loadScripts);
50311 ignoreResize : function(w, h){
50312 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
50315 this.lastSize = {width: w, height: h};
50320 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
50321 * @return {Roo.UpdateManager} The UpdateManager
50323 getUpdateManager : function(){
50324 return this.el.getUpdateManager();
50327 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
50328 * @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:
50331 url: "your-url.php",
50332 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
50333 callback: yourFunction,
50334 scope: yourObject, //(optional scope)
50337 text: "Loading...",
50342 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
50343 * 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.
50344 * @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}
50345 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
50346 * @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.
50347 * @return {Roo.ContentPanel} this
50350 var um = this.el.getUpdateManager();
50351 um.update.apply(um, arguments);
50357 * 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.
50358 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
50359 * @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)
50360 * @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)
50361 * @return {Roo.UpdateManager} The UpdateManager
50363 setUrl : function(url, params, loadOnce){
50364 if(this.refreshDelegate){
50365 this.removeListener("activate", this.refreshDelegate);
50367 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
50368 this.on("activate", this.refreshDelegate);
50369 return this.el.getUpdateManager();
50372 _handleRefresh : function(url, params, loadOnce){
50373 if(!loadOnce || !this.loaded){
50374 var updater = this.el.getUpdateManager();
50375 updater.update(url, params, this._setLoaded.createDelegate(this));
50379 _setLoaded : function(){
50380 this.loaded = true;
50384 * Returns this panel's id
50387 getId : function(){
50392 * Returns this panel's element - used by regiosn to add.
50393 * @return {Roo.Element}
50395 getEl : function(){
50396 return this.wrapEl || this.el;
50399 adjustForComponents : function(width, height)
50401 //Roo.log('adjustForComponents ');
50402 if(this.resizeEl != this.el){
50403 width -= this.el.getFrameWidth('lr');
50404 height -= this.el.getFrameWidth('tb');
50407 var te = this.toolbar.getEl();
50408 height -= te.getHeight();
50409 te.setWidth(width);
50412 var te = this.footer.getEl();
50413 Roo.log("footer:" + te.getHeight());
50415 height -= te.getHeight();
50416 te.setWidth(width);
50420 if(this.adjustments){
50421 width += this.adjustments[0];
50422 height += this.adjustments[1];
50424 return {"width": width, "height": height};
50427 setSize : function(width, height){
50428 if(this.fitToFrame && !this.ignoreResize(width, height)){
50429 if(this.fitContainer && this.resizeEl != this.el){
50430 this.el.setSize(width, height);
50432 var size = this.adjustForComponents(width, height);
50433 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
50434 this.fireEvent('resize', this, size.width, size.height);
50439 * Returns this panel's title
50442 getTitle : function(){
50447 * Set this panel's title
50448 * @param {String} title
50450 setTitle : function(title){
50451 this.title = title;
50453 this.region.updatePanelTitle(this, title);
50458 * Returns true is this panel was configured to be closable
50459 * @return {Boolean}
50461 isClosable : function(){
50462 return this.closable;
50465 beforeSlide : function(){
50467 this.resizeEl.clip();
50470 afterSlide : function(){
50472 this.resizeEl.unclip();
50476 * Force a content refresh from the URL specified in the {@link #setUrl} method.
50477 * Will fail silently if the {@link #setUrl} method has not been called.
50478 * This does not activate the panel, just updates its content.
50480 refresh : function(){
50481 if(this.refreshDelegate){
50482 this.loaded = false;
50483 this.refreshDelegate();
50488 * Destroys this panel
50490 destroy : function(){
50491 this.el.removeAllListeners();
50492 var tempEl = document.createElement("span");
50493 tempEl.appendChild(this.el.dom);
50494 tempEl.innerHTML = "";
50500 * form - if the content panel contains a form - this is a reference to it.
50501 * @type {Roo.form.Form}
50505 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
50506 * This contains a reference to it.
50512 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
50522 * @param {Object} cfg Xtype definition of item to add.
50525 addxtype : function(cfg) {
50527 if (cfg.xtype.match(/^Form$/)) {
50530 //if (this.footer) {
50531 // el = this.footer.container.insertSibling(false, 'before');
50533 el = this.el.createChild();
50536 this.form = new Roo.form.Form(cfg);
50539 if ( this.form.allItems.length) this.form.render(el.dom);
50542 // should only have one of theses..
50543 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
50544 // views.. should not be just added - used named prop 'view''
50546 cfg.el = this.el.appendChild(document.createElement("div"));
50549 var ret = new Roo.factory(cfg);
50551 ret.render && ret.render(false, ''); // render blank..
50560 * @class Roo.GridPanel
50561 * @extends Roo.ContentPanel
50563 * Create a new GridPanel.
50564 * @param {Roo.grid.Grid} grid The grid for this panel
50565 * @param {String/Object} config A string to set only the panel's title, or a config object
50567 Roo.GridPanel = function(grid, config){
50570 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
50571 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
50573 this.wrapper.dom.appendChild(grid.getGridEl().dom);
50575 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
50578 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
50580 // xtype created footer. - not sure if will work as we normally have to render first..
50581 if (this.footer && !this.footer.el && this.footer.xtype) {
50583 this.footer.container = this.grid.getView().getFooterPanel(true);
50584 this.footer.dataSource = this.grid.dataSource;
50585 this.footer = Roo.factory(this.footer, Roo);
50589 grid.monitorWindowResize = false; // turn off autosizing
50590 grid.autoHeight = false;
50591 grid.autoWidth = false;
50593 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
50596 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
50597 getId : function(){
50598 return this.grid.id;
50602 * Returns the grid for this panel
50603 * @return {Roo.grid.Grid}
50605 getGrid : function(){
50609 setSize : function(width, height){
50610 if(!this.ignoreResize(width, height)){
50611 var grid = this.grid;
50612 var size = this.adjustForComponents(width, height);
50613 grid.getGridEl().setSize(size.width, size.height);
50618 beforeSlide : function(){
50619 this.grid.getView().scroller.clip();
50622 afterSlide : function(){
50623 this.grid.getView().scroller.unclip();
50626 destroy : function(){
50627 this.grid.destroy();
50629 Roo.GridPanel.superclass.destroy.call(this);
50635 * @class Roo.NestedLayoutPanel
50636 * @extends Roo.ContentPanel
50638 * Create a new NestedLayoutPanel.
50641 * @param {Roo.BorderLayout} layout The layout for this panel
50642 * @param {String/Object} config A string to set only the title or a config object
50644 Roo.NestedLayoutPanel = function(layout, config)
50646 // construct with only one argument..
50647 /* FIXME - implement nicer consturctors
50648 if (layout.layout) {
50650 layout = config.layout;
50651 delete config.layout;
50653 if (layout.xtype && !layout.getEl) {
50654 // then layout needs constructing..
50655 layout = Roo.factory(layout, Roo);
50660 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
50662 layout.monitorWindowResize = false; // turn off autosizing
50663 this.layout = layout;
50664 this.layout.getEl().addClass("x-layout-nested-layout");
50671 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
50673 setSize : function(width, height){
50674 if(!this.ignoreResize(width, height)){
50675 var size = this.adjustForComponents(width, height);
50676 var el = this.layout.getEl();
50677 el.setSize(size.width, size.height);
50678 var touch = el.dom.offsetWidth;
50679 this.layout.layout();
50680 // ie requires a double layout on the first pass
50681 if(Roo.isIE && !this.initialized){
50682 this.initialized = true;
50683 this.layout.layout();
50688 // activate all subpanels if not currently active..
50690 setActiveState : function(active){
50691 this.active = active;
50693 this.fireEvent("deactivate", this);
50697 this.fireEvent("activate", this);
50698 // not sure if this should happen before or after..
50699 if (!this.layout) {
50700 return; // should not happen..
50703 for (var r in this.layout.regions) {
50704 reg = this.layout.getRegion(r);
50705 if (reg.getActivePanel()) {
50706 //reg.showPanel(reg.getActivePanel()); // force it to activate..
50707 reg.setActivePanel(reg.getActivePanel());
50710 if (!reg.panels.length) {
50713 reg.showPanel(reg.getPanel(0));
50722 * Returns the nested BorderLayout for this panel
50723 * @return {Roo.BorderLayout}
50725 getLayout : function(){
50726 return this.layout;
50730 * Adds a xtype elements to the layout of the nested panel
50734 xtype : 'ContentPanel',
50741 xtype : 'NestedLayoutPanel',
50747 items : [ ... list of content panels or nested layout panels.. ]
50751 * @param {Object} cfg Xtype definition of item to add.
50753 addxtype : function(cfg) {
50754 return this.layout.addxtype(cfg);
50759 Roo.ScrollPanel = function(el, config, content){
50760 config = config || {};
50761 config.fitToFrame = true;
50762 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
50764 this.el.dom.style.overflow = "hidden";
50765 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
50766 this.el.removeClass("x-layout-inactive-content");
50767 this.el.on("mousewheel", this.onWheel, this);
50769 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
50770 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
50771 up.unselectable(); down.unselectable();
50772 up.on("click", this.scrollUp, this);
50773 down.on("click", this.scrollDown, this);
50774 up.addClassOnOver("x-scroller-btn-over");
50775 down.addClassOnOver("x-scroller-btn-over");
50776 up.addClassOnClick("x-scroller-btn-click");
50777 down.addClassOnClick("x-scroller-btn-click");
50778 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
50780 this.resizeEl = this.el;
50781 this.el = wrap; this.up = up; this.down = down;
50784 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
50786 wheelIncrement : 5,
50787 scrollUp : function(){
50788 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
50791 scrollDown : function(){
50792 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
50795 afterScroll : function(){
50796 var el = this.resizeEl;
50797 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
50798 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50799 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
50802 setSize : function(){
50803 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
50804 this.afterScroll();
50807 onWheel : function(e){
50808 var d = e.getWheelDelta();
50809 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
50810 this.afterScroll();
50814 setContent : function(content, loadScripts){
50815 this.resizeEl.update(content, loadScripts);
50829 * @class Roo.TreePanel
50830 * @extends Roo.ContentPanel
50832 * Create a new TreePanel. - defaults to fit/scoll contents.
50833 * @param {String/Object} config A string to set only the panel's title, or a config object
50834 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
50836 Roo.TreePanel = function(config){
50837 var el = config.el;
50838 var tree = config.tree;
50839 delete config.tree;
50840 delete config.el; // hopefull!
50842 // wrapper for IE7 strict & safari scroll issue
50844 var treeEl = el.createChild();
50845 config.resizeEl = treeEl;
50849 Roo.TreePanel.superclass.constructor.call(this, el, config);
50852 this.tree = new Roo.tree.TreePanel(treeEl , tree);
50853 //console.log(tree);
50854 this.on('activate', function()
50856 if (this.tree.rendered) {
50859 //console.log('render tree');
50860 this.tree.render();
50862 // this should not be needed.. - it's actually the 'el' that resizes?
50863 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
50865 //this.on('resize', function (cp, w, h) {
50866 // this.tree.innerCt.setWidth(w);
50867 // this.tree.innerCt.setHeight(h);
50868 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
50875 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
50892 * Ext JS Library 1.1.1
50893 * Copyright(c) 2006-2007, Ext JS, LLC.
50895 * Originally Released Under LGPL - original licence link has changed is not relivant.
50898 * <script type="text/javascript">
50903 * @class Roo.ReaderLayout
50904 * @extends Roo.BorderLayout
50905 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
50906 * center region containing two nested regions (a top one for a list view and one for item preview below),
50907 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
50908 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
50909 * expedites the setup of the overall layout and regions for this common application style.
50912 var reader = new Roo.ReaderLayout();
50913 var CP = Roo.ContentPanel; // shortcut for adding
50915 reader.beginUpdate();
50916 reader.add("north", new CP("north", "North"));
50917 reader.add("west", new CP("west", {title: "West"}));
50918 reader.add("east", new CP("east", {title: "East"}));
50920 reader.regions.listView.add(new CP("listView", "List"));
50921 reader.regions.preview.add(new CP("preview", "Preview"));
50922 reader.endUpdate();
50925 * Create a new ReaderLayout
50926 * @param {Object} config Configuration options
50927 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
50928 * document.body if omitted)
50930 Roo.ReaderLayout = function(config, renderTo){
50931 var c = config || {size:{}};
50932 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
50933 north: c.north !== false ? Roo.apply({
50937 }, c.north) : false,
50938 west: c.west !== false ? Roo.apply({
50946 margins:{left:5,right:0,bottom:5,top:5},
50947 cmargins:{left:5,right:5,bottom:5,top:5}
50948 }, c.west) : false,
50949 east: c.east !== false ? Roo.apply({
50957 margins:{left:0,right:5,bottom:5,top:5},
50958 cmargins:{left:5,right:5,bottom:5,top:5}
50959 }, c.east) : false,
50960 center: Roo.apply({
50961 tabPosition: 'top',
50965 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
50969 this.el.addClass('x-reader');
50971 this.beginUpdate();
50973 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
50974 south: c.preview !== false ? Roo.apply({
50981 cmargins:{top:5,left:0, right:0, bottom:0}
50982 }, c.preview) : false,
50983 center: Roo.apply({
50989 this.add('center', new Roo.NestedLayoutPanel(inner,
50990 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
50994 this.regions.preview = inner.getRegion('south');
50995 this.regions.listView = inner.getRegion('center');
50998 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51000 * Ext JS Library 1.1.1
51001 * Copyright(c) 2006-2007, Ext JS, LLC.
51003 * Originally Released Under LGPL - original licence link has changed is not relivant.
51006 * <script type="text/javascript">
51010 * @class Roo.grid.Grid
51011 * @extends Roo.util.Observable
51012 * This class represents the primary interface of a component based grid control.
51013 * <br><br>Usage:<pre><code>
51014 var grid = new Roo.grid.Grid("my-container-id", {
51017 selModel: mySelectionModel,
51018 autoSizeColumns: true,
51019 monitorWindowResize: false,
51020 trackMouseOver: true
51025 * <b>Common Problems:</b><br/>
51026 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51027 * element will correct this<br/>
51028 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51029 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51030 * are unpredictable.<br/>
51031 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51032 * grid to calculate dimensions/offsets.<br/>
51034 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51035 * The container MUST have some type of size defined for the grid to fill. The container will be
51036 * automatically set to position relative if it isn't already.
51037 * @param {Object} config A config object that sets properties on this grid.
51039 Roo.grid.Grid = function(container, config){
51040 // initialize the container
51041 this.container = Roo.get(container);
51042 this.container.update("");
51043 this.container.setStyle("overflow", "hidden");
51044 this.container.addClass('x-grid-container');
51046 this.id = this.container.id;
51048 Roo.apply(this, config);
51049 // check and correct shorthanded configs
51051 this.dataSource = this.ds;
51055 this.colModel = this.cm;
51059 this.selModel = this.sm;
51063 if (this.selModel) {
51064 this.selModel = Roo.factory(this.selModel, Roo.grid);
51065 this.sm = this.selModel;
51066 this.sm.xmodule = this.xmodule || false;
51068 if (typeof(this.colModel.config) == 'undefined') {
51069 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51070 this.cm = this.colModel;
51071 this.cm.xmodule = this.xmodule || false;
51073 if (this.dataSource) {
51074 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51075 this.ds = this.dataSource;
51076 this.ds.xmodule = this.xmodule || false;
51083 this.container.setWidth(this.width);
51087 this.container.setHeight(this.height);
51094 * The raw click event for the entire grid.
51095 * @param {Roo.EventObject} e
51100 * The raw dblclick event for the entire grid.
51101 * @param {Roo.EventObject} e
51105 * @event contextmenu
51106 * The raw contextmenu event for the entire grid.
51107 * @param {Roo.EventObject} e
51109 "contextmenu" : true,
51112 * The raw mousedown event for the entire grid.
51113 * @param {Roo.EventObject} e
51115 "mousedown" : true,
51118 * The raw mouseup event for the entire grid.
51119 * @param {Roo.EventObject} e
51124 * The raw mouseover event for the entire grid.
51125 * @param {Roo.EventObject} e
51127 "mouseover" : true,
51130 * The raw mouseout event for the entire grid.
51131 * @param {Roo.EventObject} e
51136 * The raw keypress event for the entire grid.
51137 * @param {Roo.EventObject} e
51142 * The raw keydown event for the entire grid.
51143 * @param {Roo.EventObject} e
51151 * Fires when a cell is clicked
51152 * @param {Grid} this
51153 * @param {Number} rowIndex
51154 * @param {Number} columnIndex
51155 * @param {Roo.EventObject} e
51157 "cellclick" : true,
51159 * @event celldblclick
51160 * Fires when a cell is double clicked
51161 * @param {Grid} this
51162 * @param {Number} rowIndex
51163 * @param {Number} columnIndex
51164 * @param {Roo.EventObject} e
51166 "celldblclick" : true,
51169 * Fires when a row is clicked
51170 * @param {Grid} this
51171 * @param {Number} rowIndex
51172 * @param {Roo.EventObject} e
51176 * @event rowdblclick
51177 * Fires when a row is double clicked
51178 * @param {Grid} this
51179 * @param {Number} rowIndex
51180 * @param {Roo.EventObject} e
51182 "rowdblclick" : true,
51184 * @event headerclick
51185 * Fires when a header is clicked
51186 * @param {Grid} this
51187 * @param {Number} columnIndex
51188 * @param {Roo.EventObject} e
51190 "headerclick" : true,
51192 * @event headerdblclick
51193 * Fires when a header cell is double clicked
51194 * @param {Grid} this
51195 * @param {Number} columnIndex
51196 * @param {Roo.EventObject} e
51198 "headerdblclick" : true,
51200 * @event rowcontextmenu
51201 * Fires when a row is right clicked
51202 * @param {Grid} this
51203 * @param {Number} rowIndex
51204 * @param {Roo.EventObject} e
51206 "rowcontextmenu" : true,
51208 * @event cellcontextmenu
51209 * Fires when a cell is right clicked
51210 * @param {Grid} this
51211 * @param {Number} rowIndex
51212 * @param {Number} cellIndex
51213 * @param {Roo.EventObject} e
51215 "cellcontextmenu" : true,
51217 * @event headercontextmenu
51218 * Fires when a header is right clicked
51219 * @param {Grid} this
51220 * @param {Number} columnIndex
51221 * @param {Roo.EventObject} e
51223 "headercontextmenu" : true,
51225 * @event bodyscroll
51226 * Fires when the body element is scrolled
51227 * @param {Number} scrollLeft
51228 * @param {Number} scrollTop
51230 "bodyscroll" : true,
51232 * @event columnresize
51233 * Fires when the user resizes a column
51234 * @param {Number} columnIndex
51235 * @param {Number} newSize
51237 "columnresize" : true,
51239 * @event columnmove
51240 * Fires when the user moves a column
51241 * @param {Number} oldIndex
51242 * @param {Number} newIndex
51244 "columnmove" : true,
51247 * Fires when row(s) start being dragged
51248 * @param {Grid} this
51249 * @param {Roo.GridDD} dd The drag drop object
51250 * @param {event} e The raw browser event
51252 "startdrag" : true,
51255 * Fires when a drag operation is complete
51256 * @param {Grid} this
51257 * @param {Roo.GridDD} dd The drag drop object
51258 * @param {event} e The raw browser event
51263 * Fires when dragged row(s) are dropped on a valid DD target
51264 * @param {Grid} this
51265 * @param {Roo.GridDD} dd The drag drop object
51266 * @param {String} targetId The target drag drop object
51267 * @param {event} e The raw browser event
51272 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51273 * @param {Grid} this
51274 * @param {Roo.GridDD} dd The drag drop object
51275 * @param {String} targetId The target drag drop object
51276 * @param {event} e The raw browser event
51281 * Fires when the dragged row(s) first cross another DD target while being dragged
51282 * @param {Grid} this
51283 * @param {Roo.GridDD} dd The drag drop object
51284 * @param {String} targetId The target drag drop object
51285 * @param {event} e The raw browser event
51287 "dragenter" : true,
51290 * Fires when the dragged row(s) leave another DD target while being dragged
51291 * @param {Grid} this
51292 * @param {Roo.GridDD} dd The drag drop object
51293 * @param {String} targetId The target drag drop object
51294 * @param {event} e The raw browser event
51299 * Fires when a row is rendered, so you can change add a style to it.
51300 * @param {GridView} gridview The grid view
51301 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
51307 * Fires when the grid is rendered
51308 * @param {Grid} grid
51313 Roo.grid.Grid.superclass.constructor.call(this);
51315 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
51318 * @cfg {String} ddGroup - drag drop group.
51322 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
51324 minColumnWidth : 25,
51327 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
51328 * <b>on initial render.</b> It is more efficient to explicitly size the columns
51329 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
51331 autoSizeColumns : false,
51334 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
51336 autoSizeHeaders : true,
51339 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
51341 monitorWindowResize : true,
51344 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
51345 * rows measured to get a columns size. Default is 0 (all rows).
51347 maxRowsToMeasure : 0,
51350 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
51352 trackMouseOver : true,
51355 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
51359 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
51361 enableDragDrop : false,
51364 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
51366 enableColumnMove : true,
51369 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
51371 enableColumnHide : true,
51374 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
51376 enableRowHeightSync : false,
51379 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
51384 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
51386 autoHeight : false,
51389 * @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.
51391 autoExpandColumn : false,
51394 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
51397 autoExpandMin : 50,
51400 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
51402 autoExpandMax : 1000,
51405 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
51410 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
51414 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
51424 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
51425 * of a fixed width. Default is false.
51428 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
51431 * Called once after all setup has been completed and the grid is ready to be rendered.
51432 * @return {Roo.grid.Grid} this
51434 render : function()
51436 var c = this.container;
51437 // try to detect autoHeight/width mode
51438 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
51439 this.autoHeight = true;
51441 var view = this.getView();
51444 c.on("click", this.onClick, this);
51445 c.on("dblclick", this.onDblClick, this);
51446 c.on("contextmenu", this.onContextMenu, this);
51447 c.on("keydown", this.onKeyDown, this);
51449 c.on("touchstart", this.onTouchStart, this);
51452 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
51454 this.getSelectionModel().init(this);
51459 this.loadMask = new Roo.LoadMask(this.container,
51460 Roo.apply({store:this.dataSource}, this.loadMask));
51464 if (this.toolbar && this.toolbar.xtype) {
51465 this.toolbar.container = this.getView().getHeaderPanel(true);
51466 this.toolbar = new Roo.Toolbar(this.toolbar);
51468 if (this.footer && this.footer.xtype) {
51469 this.footer.dataSource = this.getDataSource();
51470 this.footer.container = this.getView().getFooterPanel(true);
51471 this.footer = Roo.factory(this.footer, Roo);
51473 if (this.dropTarget && this.dropTarget.xtype) {
51474 delete this.dropTarget.xtype;
51475 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
51479 this.rendered = true;
51480 this.fireEvent('render', this);
51485 * Reconfigures the grid to use a different Store and Column Model.
51486 * The View will be bound to the new objects and refreshed.
51487 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
51488 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
51490 reconfigure : function(dataSource, colModel){
51492 this.loadMask.destroy();
51493 this.loadMask = new Roo.LoadMask(this.container,
51494 Roo.apply({store:dataSource}, this.loadMask));
51496 this.view.bind(dataSource, colModel);
51497 this.dataSource = dataSource;
51498 this.colModel = colModel;
51499 this.view.refresh(true);
51503 onKeyDown : function(e){
51504 this.fireEvent("keydown", e);
51508 * Destroy this grid.
51509 * @param {Boolean} removeEl True to remove the element
51511 destroy : function(removeEl, keepListeners){
51513 this.loadMask.destroy();
51515 var c = this.container;
51516 c.removeAllListeners();
51517 this.view.destroy();
51518 this.colModel.purgeListeners();
51519 if(!keepListeners){
51520 this.purgeListeners();
51523 if(removeEl === true){
51529 processEvent : function(name, e){
51530 // does this fire select???
51531 Roo.log('grid:processEvent ' + name);
51533 if (name != 'touchstart' ) {
51534 this.fireEvent(name, e);
51537 var t = e.getTarget();
51539 var header = v.findHeaderIndex(t);
51540 if(header !== false){
51541 this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
51543 var row = v.findRowIndex(t);
51544 var cell = v.findCellIndex(t);
51545 if (name == 'touchstart') {
51546 // first touch is always a click.
51547 // hopefull this happens after selection is updated.?
51550 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
51551 var cs = this.selModel.getSelectedCell();
51552 if (row == cs[0] && cell == cs[1]){
51556 if (typeof(this.selModel.getSelections) != 'undefined') {
51557 var cs = this.selModel.getSelections();
51558 var ds = this.dataSource;
51559 if (cs.length == 1 && ds.getAt(row) == cs[0]){
51570 this.fireEvent("row" + name, this, row, e);
51571 if(cell !== false){
51572 this.fireEvent("cell" + name, this, row, cell, e);
51579 onClick : function(e){
51580 this.processEvent("click", e);
51583 onTouchStart : function(e){
51584 this.processEvent("touchstart", e);
51588 onContextMenu : function(e, t){
51589 this.processEvent("contextmenu", e);
51593 onDblClick : function(e){
51594 this.processEvent("dblclick", e);
51598 walkCells : function(row, col, step, fn, scope){
51599 var cm = this.colModel, clen = cm.getColumnCount();
51600 var ds = this.dataSource, rlen = ds.getCount(), first = true;
51612 if(fn.call(scope || this, row, col, cm) === true){
51630 if(fn.call(scope || this, row, col, cm) === true){
51642 getSelections : function(){
51643 return this.selModel.getSelections();
51647 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
51648 * but if manual update is required this method will initiate it.
51650 autoSize : function(){
51652 this.view.layout();
51653 if(this.view.adjustForScroll){
51654 this.view.adjustForScroll();
51660 * Returns the grid's underlying element.
51661 * @return {Element} The element
51663 getGridEl : function(){
51664 return this.container;
51667 // private for compatibility, overridden by editor grid
51668 stopEditing : function(){},
51671 * Returns the grid's SelectionModel.
51672 * @return {SelectionModel}
51674 getSelectionModel : function(){
51675 if(!this.selModel){
51676 this.selModel = new Roo.grid.RowSelectionModel();
51678 return this.selModel;
51682 * Returns the grid's DataSource.
51683 * @return {DataSource}
51685 getDataSource : function(){
51686 return this.dataSource;
51690 * Returns the grid's ColumnModel.
51691 * @return {ColumnModel}
51693 getColumnModel : function(){
51694 return this.colModel;
51698 * Returns the grid's GridView object.
51699 * @return {GridView}
51701 getView : function(){
51703 this.view = new Roo.grid.GridView(this.viewConfig);
51708 * Called to get grid's drag proxy text, by default returns this.ddText.
51711 getDragDropText : function(){
51712 var count = this.selModel.getCount();
51713 return String.format(this.ddText, count, count == 1 ? '' : 's');
51717 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
51718 * %0 is replaced with the number of selected rows.
51721 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
51723 * Ext JS Library 1.1.1
51724 * Copyright(c) 2006-2007, Ext JS, LLC.
51726 * Originally Released Under LGPL - original licence link has changed is not relivant.
51729 * <script type="text/javascript">
51732 Roo.grid.AbstractGridView = function(){
51736 "beforerowremoved" : true,
51737 "beforerowsinserted" : true,
51738 "beforerefresh" : true,
51739 "rowremoved" : true,
51740 "rowsinserted" : true,
51741 "rowupdated" : true,
51744 Roo.grid.AbstractGridView.superclass.constructor.call(this);
51747 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
51748 rowClass : "x-grid-row",
51749 cellClass : "x-grid-cell",
51750 tdClass : "x-grid-td",
51751 hdClass : "x-grid-hd",
51752 splitClass : "x-grid-hd-split",
51754 init: function(grid){
51756 var cid = this.grid.getGridEl().id;
51757 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
51758 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
51759 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
51760 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
51763 getColumnRenderers : function(){
51764 var renderers = [];
51765 var cm = this.grid.colModel;
51766 var colCount = cm.getColumnCount();
51767 for(var i = 0; i < colCount; i++){
51768 renderers[i] = cm.getRenderer(i);
51773 getColumnIds : function(){
51775 var cm = this.grid.colModel;
51776 var colCount = cm.getColumnCount();
51777 for(var i = 0; i < colCount; i++){
51778 ids[i] = cm.getColumnId(i);
51783 getDataIndexes : function(){
51784 if(!this.indexMap){
51785 this.indexMap = this.buildIndexMap();
51787 return this.indexMap.colToData;
51790 getColumnIndexByDataIndex : function(dataIndex){
51791 if(!this.indexMap){
51792 this.indexMap = this.buildIndexMap();
51794 return this.indexMap.dataToCol[dataIndex];
51798 * Set a css style for a column dynamically.
51799 * @param {Number} colIndex The index of the column
51800 * @param {String} name The css property name
51801 * @param {String} value The css value
51803 setCSSStyle : function(colIndex, name, value){
51804 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
51805 Roo.util.CSS.updateRule(selector, name, value);
51808 generateRules : function(cm){
51809 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
51810 Roo.util.CSS.removeStyleSheet(rulesId);
51811 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51812 var cid = cm.getColumnId(i);
51813 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
51814 this.tdSelector, cid, " {\n}\n",
51815 this.hdSelector, cid, " {\n}\n",
51816 this.splitSelector, cid, " {\n}\n");
51818 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
51822 * Ext JS Library 1.1.1
51823 * Copyright(c) 2006-2007, Ext JS, LLC.
51825 * Originally Released Under LGPL - original licence link has changed is not relivant.
51828 * <script type="text/javascript">
51832 // This is a support class used internally by the Grid components
51833 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
51835 this.view = grid.getView();
51836 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51837 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
51839 this.setHandleElId(Roo.id(hd));
51840 this.setOuterHandleElId(Roo.id(hd2));
51842 this.scroll = false;
51844 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
51846 getDragData : function(e){
51847 var t = Roo.lib.Event.getTarget(e);
51848 var h = this.view.findHeaderCell(t);
51850 return {ddel: h.firstChild, header:h};
51855 onInitDrag : function(e){
51856 this.view.headersDisabled = true;
51857 var clone = this.dragData.ddel.cloneNode(true);
51858 clone.id = Roo.id();
51859 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
51860 this.proxy.update(clone);
51864 afterValidDrop : function(){
51866 setTimeout(function(){
51867 v.headersDisabled = false;
51871 afterInvalidDrop : function(){
51873 setTimeout(function(){
51874 v.headersDisabled = false;
51880 * Ext JS Library 1.1.1
51881 * Copyright(c) 2006-2007, Ext JS, LLC.
51883 * Originally Released Under LGPL - original licence link has changed is not relivant.
51886 * <script type="text/javascript">
51889 // This is a support class used internally by the Grid components
51890 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
51892 this.view = grid.getView();
51893 // split the proxies so they don't interfere with mouse events
51894 this.proxyTop = Roo.DomHelper.append(document.body, {
51895 cls:"col-move-top", html:" "
51897 this.proxyBottom = Roo.DomHelper.append(document.body, {
51898 cls:"col-move-bottom", html:" "
51900 this.proxyTop.hide = this.proxyBottom.hide = function(){
51901 this.setLeftTop(-100,-100);
51902 this.setStyle("visibility", "hidden");
51904 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
51905 // temporarily disabled
51906 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
51907 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
51909 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
51910 proxyOffsets : [-4, -9],
51911 fly: Roo.Element.fly,
51913 getTargetFromEvent : function(e){
51914 var t = Roo.lib.Event.getTarget(e);
51915 var cindex = this.view.findCellIndex(t);
51916 if(cindex !== false){
51917 return this.view.getHeaderCell(cindex);
51922 nextVisible : function(h){
51923 var v = this.view, cm = this.grid.colModel;
51926 if(!cm.isHidden(v.getCellIndex(h))){
51934 prevVisible : function(h){
51935 var v = this.view, cm = this.grid.colModel;
51938 if(!cm.isHidden(v.getCellIndex(h))){
51946 positionIndicator : function(h, n, e){
51947 var x = Roo.lib.Event.getPageX(e);
51948 var r = Roo.lib.Dom.getRegion(n.firstChild);
51949 var px, pt, py = r.top + this.proxyOffsets[1];
51950 if((r.right - x) <= (r.right-r.left)/2){
51951 px = r.right+this.view.borderWidth;
51957 var oldIndex = this.view.getCellIndex(h);
51958 var newIndex = this.view.getCellIndex(n);
51960 if(this.grid.colModel.isFixed(newIndex)){
51964 var locked = this.grid.colModel.isLocked(newIndex);
51969 if(oldIndex < newIndex){
51972 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
51975 px += this.proxyOffsets[0];
51976 this.proxyTop.setLeftTop(px, py);
51977 this.proxyTop.show();
51978 if(!this.bottomOffset){
51979 this.bottomOffset = this.view.mainHd.getHeight();
51981 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
51982 this.proxyBottom.show();
51986 onNodeEnter : function(n, dd, e, data){
51987 if(data.header != n){
51988 this.positionIndicator(data.header, n, e);
51992 onNodeOver : function(n, dd, e, data){
51993 var result = false;
51994 if(data.header != n){
51995 result = this.positionIndicator(data.header, n, e);
51998 this.proxyTop.hide();
51999 this.proxyBottom.hide();
52001 return result ? this.dropAllowed : this.dropNotAllowed;
52004 onNodeOut : function(n, dd, e, data){
52005 this.proxyTop.hide();
52006 this.proxyBottom.hide();
52009 onNodeDrop : function(n, dd, e, data){
52010 var h = data.header;
52012 var cm = this.grid.colModel;
52013 var x = Roo.lib.Event.getPageX(e);
52014 var r = Roo.lib.Dom.getRegion(n.firstChild);
52015 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52016 var oldIndex = this.view.getCellIndex(h);
52017 var newIndex = this.view.getCellIndex(n);
52018 var locked = cm.isLocked(newIndex);
52022 if(oldIndex < newIndex){
52025 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52028 cm.setLocked(oldIndex, locked, true);
52029 cm.moveColumn(oldIndex, newIndex);
52030 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52038 * Ext JS Library 1.1.1
52039 * Copyright(c) 2006-2007, Ext JS, LLC.
52041 * Originally Released Under LGPL - original licence link has changed is not relivant.
52044 * <script type="text/javascript">
52048 * @class Roo.grid.GridView
52049 * @extends Roo.util.Observable
52052 * @param {Object} config
52054 Roo.grid.GridView = function(config){
52055 Roo.grid.GridView.superclass.constructor.call(this);
52058 Roo.apply(this, config);
52061 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52063 unselectable : 'unselectable="on"',
52064 unselectableCls : 'x-unselectable',
52067 rowClass : "x-grid-row",
52069 cellClass : "x-grid-col",
52071 tdClass : "x-grid-td",
52073 hdClass : "x-grid-hd",
52075 splitClass : "x-grid-split",
52077 sortClasses : ["sort-asc", "sort-desc"],
52079 enableMoveAnim : false,
52083 dh : Roo.DomHelper,
52085 fly : Roo.Element.fly,
52087 css : Roo.util.CSS,
52093 scrollIncrement : 22,
52095 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52097 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52099 bind : function(ds, cm){
52101 this.ds.un("load", this.onLoad, this);
52102 this.ds.un("datachanged", this.onDataChange, this);
52103 this.ds.un("add", this.onAdd, this);
52104 this.ds.un("remove", this.onRemove, this);
52105 this.ds.un("update", this.onUpdate, this);
52106 this.ds.un("clear", this.onClear, this);
52109 ds.on("load", this.onLoad, this);
52110 ds.on("datachanged", this.onDataChange, this);
52111 ds.on("add", this.onAdd, this);
52112 ds.on("remove", this.onRemove, this);
52113 ds.on("update", this.onUpdate, this);
52114 ds.on("clear", this.onClear, this);
52119 this.cm.un("widthchange", this.onColWidthChange, this);
52120 this.cm.un("headerchange", this.onHeaderChange, this);
52121 this.cm.un("hiddenchange", this.onHiddenChange, this);
52122 this.cm.un("columnmoved", this.onColumnMove, this);
52123 this.cm.un("columnlockchange", this.onColumnLock, this);
52126 this.generateRules(cm);
52127 cm.on("widthchange", this.onColWidthChange, this);
52128 cm.on("headerchange", this.onHeaderChange, this);
52129 cm.on("hiddenchange", this.onHiddenChange, this);
52130 cm.on("columnmoved", this.onColumnMove, this);
52131 cm.on("columnlockchange", this.onColumnLock, this);
52136 init: function(grid){
52137 Roo.grid.GridView.superclass.init.call(this, grid);
52139 this.bind(grid.dataSource, grid.colModel);
52141 grid.on("headerclick", this.handleHeaderClick, this);
52143 if(grid.trackMouseOver){
52144 grid.on("mouseover", this.onRowOver, this);
52145 grid.on("mouseout", this.onRowOut, this);
52147 grid.cancelTextSelection = function(){};
52148 this.gridId = grid.id;
52150 var tpls = this.templates || {};
52153 tpls.master = new Roo.Template(
52154 '<div class="x-grid" hidefocus="true">',
52155 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52156 '<div class="x-grid-topbar"></div>',
52157 '<div class="x-grid-scroller"><div></div></div>',
52158 '<div class="x-grid-locked">',
52159 '<div class="x-grid-header">{lockedHeader}</div>',
52160 '<div class="x-grid-body">{lockedBody}</div>',
52162 '<div class="x-grid-viewport">',
52163 '<div class="x-grid-header">{header}</div>',
52164 '<div class="x-grid-body">{body}</div>',
52166 '<div class="x-grid-bottombar"></div>',
52168 '<div class="x-grid-resize-proxy"> </div>',
52171 tpls.master.disableformats = true;
52175 tpls.header = new Roo.Template(
52176 '<table border="0" cellspacing="0" cellpadding="0">',
52177 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52180 tpls.header.disableformats = true;
52182 tpls.header.compile();
52185 tpls.hcell = new Roo.Template(
52186 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52187 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52190 tpls.hcell.disableFormats = true;
52192 tpls.hcell.compile();
52195 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52196 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52197 tpls.hsplit.disableFormats = true;
52199 tpls.hsplit.compile();
52202 tpls.body = new Roo.Template(
52203 '<table border="0" cellspacing="0" cellpadding="0">',
52204 "<tbody>{rows}</tbody>",
52207 tpls.body.disableFormats = true;
52209 tpls.body.compile();
52212 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52213 tpls.row.disableFormats = true;
52215 tpls.row.compile();
52218 tpls.cell = new Roo.Template(
52219 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52220 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52221 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52224 tpls.cell.disableFormats = true;
52226 tpls.cell.compile();
52228 this.templates = tpls;
52231 // remap these for backwards compat
52232 onColWidthChange : function(){
52233 this.updateColumns.apply(this, arguments);
52235 onHeaderChange : function(){
52236 this.updateHeaders.apply(this, arguments);
52238 onHiddenChange : function(){
52239 this.handleHiddenChange.apply(this, arguments);
52241 onColumnMove : function(){
52242 this.handleColumnMove.apply(this, arguments);
52244 onColumnLock : function(){
52245 this.handleLockChange.apply(this, arguments);
52248 onDataChange : function(){
52250 this.updateHeaderSortState();
52253 onClear : function(){
52257 onUpdate : function(ds, record){
52258 this.refreshRow(record);
52261 refreshRow : function(record){
52262 var ds = this.ds, index;
52263 if(typeof record == 'number'){
52265 record = ds.getAt(index);
52267 index = ds.indexOf(record);
52269 this.insertRows(ds, index, index, true);
52270 this.onRemove(ds, record, index+1, true);
52271 this.syncRowHeights(index, index);
52273 this.fireEvent("rowupdated", this, index, record);
52276 onAdd : function(ds, records, index){
52277 this.insertRows(ds, index, index + (records.length-1));
52280 onRemove : function(ds, record, index, isUpdate){
52281 if(isUpdate !== true){
52282 this.fireEvent("beforerowremoved", this, index, record);
52284 var bt = this.getBodyTable(), lt = this.getLockedTable();
52285 if(bt.rows[index]){
52286 bt.firstChild.removeChild(bt.rows[index]);
52288 if(lt.rows[index]){
52289 lt.firstChild.removeChild(lt.rows[index]);
52291 if(isUpdate !== true){
52292 this.stripeRows(index);
52293 this.syncRowHeights(index, index);
52295 this.fireEvent("rowremoved", this, index, record);
52299 onLoad : function(){
52300 this.scrollToTop();
52304 * Scrolls the grid to the top
52306 scrollToTop : function(){
52308 this.scroller.dom.scrollTop = 0;
52314 * Gets a panel in the header of the grid that can be used for toolbars etc.
52315 * After modifying the contents of this panel a call to grid.autoSize() may be
52316 * required to register any changes in size.
52317 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
52318 * @return Roo.Element
52320 getHeaderPanel : function(doShow){
52322 this.headerPanel.show();
52324 return this.headerPanel;
52328 * Gets a panel in the footer of the grid that can be used for toolbars etc.
52329 * After modifying the contents of this panel a call to grid.autoSize() may be
52330 * required to register any changes in size.
52331 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
52332 * @return Roo.Element
52334 getFooterPanel : function(doShow){
52336 this.footerPanel.show();
52338 return this.footerPanel;
52341 initElements : function(){
52342 var E = Roo.Element;
52343 var el = this.grid.getGridEl().dom.firstChild;
52344 var cs = el.childNodes;
52346 this.el = new E(el);
52348 this.focusEl = new E(el.firstChild);
52349 this.focusEl.swallowEvent("click", true);
52351 this.headerPanel = new E(cs[1]);
52352 this.headerPanel.enableDisplayMode("block");
52354 this.scroller = new E(cs[2]);
52355 this.scrollSizer = new E(this.scroller.dom.firstChild);
52357 this.lockedWrap = new E(cs[3]);
52358 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
52359 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
52361 this.mainWrap = new E(cs[4]);
52362 this.mainHd = new E(this.mainWrap.dom.firstChild);
52363 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
52365 this.footerPanel = new E(cs[5]);
52366 this.footerPanel.enableDisplayMode("block");
52368 this.resizeProxy = new E(cs[6]);
52370 this.headerSelector = String.format(
52371 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
52372 this.lockedHd.id, this.mainHd.id
52375 this.splitterSelector = String.format(
52376 '#{0} div.x-grid-split, #{1} div.x-grid-split',
52377 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
52380 idToCssName : function(s)
52382 return s.replace(/[^a-z0-9]+/ig, '-');
52385 getHeaderCell : function(index){
52386 return Roo.DomQuery.select(this.headerSelector)[index];
52389 getHeaderCellMeasure : function(index){
52390 return this.getHeaderCell(index).firstChild;
52393 getHeaderCellText : function(index){
52394 return this.getHeaderCell(index).firstChild.firstChild;
52397 getLockedTable : function(){
52398 return this.lockedBody.dom.firstChild;
52401 getBodyTable : function(){
52402 return this.mainBody.dom.firstChild;
52405 getLockedRow : function(index){
52406 return this.getLockedTable().rows[index];
52409 getRow : function(index){
52410 return this.getBodyTable().rows[index];
52413 getRowComposite : function(index){
52415 this.rowEl = new Roo.CompositeElementLite();
52417 var els = [], lrow, mrow;
52418 if(lrow = this.getLockedRow(index)){
52421 if(mrow = this.getRow(index)){
52424 this.rowEl.elements = els;
52428 * Gets the 'td' of the cell
52430 * @param {Integer} rowIndex row to select
52431 * @param {Integer} colIndex column to select
52435 getCell : function(rowIndex, colIndex){
52436 var locked = this.cm.getLockedCount();
52438 if(colIndex < locked){
52439 source = this.lockedBody.dom.firstChild;
52441 source = this.mainBody.dom.firstChild;
52442 colIndex -= locked;
52444 return source.rows[rowIndex].childNodes[colIndex];
52447 getCellText : function(rowIndex, colIndex){
52448 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
52451 getCellBox : function(cell){
52452 var b = this.fly(cell).getBox();
52453 if(Roo.isOpera){ // opera fails to report the Y
52454 b.y = cell.offsetTop + this.mainBody.getY();
52459 getCellIndex : function(cell){
52460 var id = String(cell.className).match(this.cellRE);
52462 return parseInt(id[1], 10);
52467 findHeaderIndex : function(n){
52468 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52469 return r ? this.getCellIndex(r) : false;
52472 findHeaderCell : function(n){
52473 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52474 return r ? r : false;
52477 findRowIndex : function(n){
52481 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
52482 return r ? r.rowIndex : false;
52485 findCellIndex : function(node){
52486 var stop = this.el.dom;
52487 while(node && node != stop){
52488 if(this.findRE.test(node.className)){
52489 return this.getCellIndex(node);
52491 node = node.parentNode;
52496 getColumnId : function(index){
52497 return this.cm.getColumnId(index);
52500 getSplitters : function()
52502 if(this.splitterSelector){
52503 return Roo.DomQuery.select(this.splitterSelector);
52509 getSplitter : function(index){
52510 return this.getSplitters()[index];
52513 onRowOver : function(e, t){
52515 if((row = this.findRowIndex(t)) !== false){
52516 this.getRowComposite(row).addClass("x-grid-row-over");
52520 onRowOut : function(e, t){
52522 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
52523 this.getRowComposite(row).removeClass("x-grid-row-over");
52527 renderHeaders : function(){
52529 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
52530 var cb = [], lb = [], sb = [], lsb = [], p = {};
52531 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52532 p.cellId = "x-grid-hd-0-" + i;
52533 p.splitId = "x-grid-csplit-0-" + i;
52534 p.id = cm.getColumnId(i);
52535 p.title = cm.getColumnTooltip(i) || "";
52536 p.value = cm.getColumnHeader(i) || "";
52537 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
52538 if(!cm.isLocked(i)){
52539 cb[cb.length] = ct.apply(p);
52540 sb[sb.length] = st.apply(p);
52542 lb[lb.length] = ct.apply(p);
52543 lsb[lsb.length] = st.apply(p);
52546 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
52547 ht.apply({cells: cb.join(""), splits:sb.join("")})];
52550 updateHeaders : function(){
52551 var html = this.renderHeaders();
52552 this.lockedHd.update(html[0]);
52553 this.mainHd.update(html[1]);
52557 * Focuses the specified row.
52558 * @param {Number} row The row index
52560 focusRow : function(row)
52562 //Roo.log('GridView.focusRow');
52563 var x = this.scroller.dom.scrollLeft;
52564 this.focusCell(row, 0, false);
52565 this.scroller.dom.scrollLeft = x;
52569 * Focuses the specified cell.
52570 * @param {Number} row The row index
52571 * @param {Number} col The column index
52572 * @param {Boolean} hscroll false to disable horizontal scrolling
52574 focusCell : function(row, col, hscroll)
52576 //Roo.log('GridView.focusCell');
52577 var el = this.ensureVisible(row, col, hscroll);
52578 this.focusEl.alignTo(el, "tl-tl");
52580 this.focusEl.focus();
52582 this.focusEl.focus.defer(1, this.focusEl);
52587 * Scrolls the specified cell into view
52588 * @param {Number} row The row index
52589 * @param {Number} col The column index
52590 * @param {Boolean} hscroll false to disable horizontal scrolling
52592 ensureVisible : function(row, col, hscroll)
52594 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
52595 //return null; //disable for testing.
52596 if(typeof row != "number"){
52597 row = row.rowIndex;
52599 if(row < 0 && row >= this.ds.getCount()){
52602 col = (col !== undefined ? col : 0);
52603 var cm = this.grid.colModel;
52604 while(cm.isHidden(col)){
52608 var el = this.getCell(row, col);
52612 var c = this.scroller.dom;
52614 var ctop = parseInt(el.offsetTop, 10);
52615 var cleft = parseInt(el.offsetLeft, 10);
52616 var cbot = ctop + el.offsetHeight;
52617 var cright = cleft + el.offsetWidth;
52619 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
52620 var stop = parseInt(c.scrollTop, 10);
52621 var sleft = parseInt(c.scrollLeft, 10);
52622 var sbot = stop + ch;
52623 var sright = sleft + c.clientWidth;
52625 Roo.log('GridView.ensureVisible:' +
52627 ' c.clientHeight:' + c.clientHeight +
52628 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
52636 c.scrollTop = ctop;
52637 //Roo.log("set scrolltop to ctop DISABLE?");
52638 }else if(cbot > sbot){
52639 //Roo.log("set scrolltop to cbot-ch");
52640 c.scrollTop = cbot-ch;
52643 if(hscroll !== false){
52645 c.scrollLeft = cleft;
52646 }else if(cright > sright){
52647 c.scrollLeft = cright-c.clientWidth;
52654 updateColumns : function(){
52655 this.grid.stopEditing();
52656 var cm = this.grid.colModel, colIds = this.getColumnIds();
52657 //var totalWidth = cm.getTotalWidth();
52659 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52660 //if(cm.isHidden(i)) continue;
52661 var w = cm.getColumnWidth(i);
52662 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52663 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
52665 this.updateSplitters();
52668 generateRules : function(cm){
52669 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
52670 Roo.util.CSS.removeStyleSheet(rulesId);
52671 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52672 var cid = cm.getColumnId(i);
52674 if(cm.config[i].align){
52675 align = 'text-align:'+cm.config[i].align+';';
52678 if(cm.isHidden(i)){
52679 hidden = 'display:none;';
52681 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
52683 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
52684 this.hdSelector, cid, " {\n", align, width, "}\n",
52685 this.tdSelector, cid, " {\n",hidden,"\n}\n",
52686 this.splitSelector, cid, " {\n", hidden , "\n}\n");
52688 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52691 updateSplitters : function(){
52692 var cm = this.cm, s = this.getSplitters();
52693 if(s){ // splitters not created yet
52694 var pos = 0, locked = true;
52695 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52696 if(cm.isHidden(i)) continue;
52697 var w = cm.getColumnWidth(i); // make sure it's a number
52698 if(!cm.isLocked(i) && locked){
52703 s[i].style.left = (pos-this.splitOffset) + "px";
52708 handleHiddenChange : function(colModel, colIndex, hidden){
52710 this.hideColumn(colIndex);
52712 this.unhideColumn(colIndex);
52716 hideColumn : function(colIndex){
52717 var cid = this.getColumnId(colIndex);
52718 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
52719 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
52721 this.updateHeaders();
52723 this.updateSplitters();
52727 unhideColumn : function(colIndex){
52728 var cid = this.getColumnId(colIndex);
52729 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
52730 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
52733 this.updateHeaders();
52735 this.updateSplitters();
52739 insertRows : function(dm, firstRow, lastRow, isUpdate){
52740 if(firstRow == 0 && lastRow == dm.getCount()-1){
52744 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
52746 var s = this.getScrollState();
52747 var markup = this.renderRows(firstRow, lastRow);
52748 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
52749 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
52750 this.restoreScroll(s);
52752 this.fireEvent("rowsinserted", this, firstRow, lastRow);
52753 this.syncRowHeights(firstRow, lastRow);
52754 this.stripeRows(firstRow);
52760 bufferRows : function(markup, target, index){
52761 var before = null, trows = target.rows, tbody = target.tBodies[0];
52762 if(index < trows.length){
52763 before = trows[index];
52765 var b = document.createElement("div");
52766 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
52767 var rows = b.firstChild.rows;
52768 for(var i = 0, len = rows.length; i < len; i++){
52770 tbody.insertBefore(rows[0], before);
52772 tbody.appendChild(rows[0]);
52779 deleteRows : function(dm, firstRow, lastRow){
52780 if(dm.getRowCount()<1){
52781 this.fireEvent("beforerefresh", this);
52782 this.mainBody.update("");
52783 this.lockedBody.update("");
52784 this.fireEvent("refresh", this);
52786 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
52787 var bt = this.getBodyTable();
52788 var tbody = bt.firstChild;
52789 var rows = bt.rows;
52790 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
52791 tbody.removeChild(rows[firstRow]);
52793 this.stripeRows(firstRow);
52794 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
52798 updateRows : function(dataSource, firstRow, lastRow){
52799 var s = this.getScrollState();
52801 this.restoreScroll(s);
52804 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
52808 this.updateHeaderSortState();
52811 getScrollState : function(){
52813 var sb = this.scroller.dom;
52814 return {left: sb.scrollLeft, top: sb.scrollTop};
52817 stripeRows : function(startRow){
52818 if(!this.grid.stripeRows || this.ds.getCount() < 1){
52821 startRow = startRow || 0;
52822 var rows = this.getBodyTable().rows;
52823 var lrows = this.getLockedTable().rows;
52824 var cls = ' x-grid-row-alt ';
52825 for(var i = startRow, len = rows.length; i < len; i++){
52826 var row = rows[i], lrow = lrows[i];
52827 var isAlt = ((i+1) % 2 == 0);
52828 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
52829 if(isAlt == hasAlt){
52833 row.className += " x-grid-row-alt";
52835 row.className = row.className.replace("x-grid-row-alt", "");
52838 lrow.className = row.className;
52843 restoreScroll : function(state){
52844 //Roo.log('GridView.restoreScroll');
52845 var sb = this.scroller.dom;
52846 sb.scrollLeft = state.left;
52847 sb.scrollTop = state.top;
52851 syncScroll : function(){
52852 //Roo.log('GridView.syncScroll');
52853 var sb = this.scroller.dom;
52854 var sh = this.mainHd.dom;
52855 var bs = this.mainBody.dom;
52856 var lv = this.lockedBody.dom;
52857 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
52858 lv.scrollTop = bs.scrollTop = sb.scrollTop;
52861 handleScroll : function(e){
52863 var sb = this.scroller.dom;
52864 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
52868 handleWheel : function(e){
52869 var d = e.getWheelDelta();
52870 this.scroller.dom.scrollTop -= d*22;
52871 // set this here to prevent jumpy scrolling on large tables
52872 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
52876 renderRows : function(startRow, endRow){
52877 // pull in all the crap needed to render rows
52878 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
52879 var colCount = cm.getColumnCount();
52881 if(ds.getCount() < 1){
52885 // build a map for all the columns
52887 for(var i = 0; i < colCount; i++){
52888 var name = cm.getDataIndex(i);
52890 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
52891 renderer : cm.getRenderer(i),
52892 id : cm.getColumnId(i),
52893 locked : cm.isLocked(i)
52897 startRow = startRow || 0;
52898 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
52900 // records to render
52901 var rs = ds.getRange(startRow, endRow);
52903 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
52906 // As much as I hate to duplicate code, this was branched because FireFox really hates
52907 // [].join("") on strings. The performance difference was substantial enough to
52908 // branch this function
52909 doRender : Roo.isGecko ?
52910 function(cs, rs, ds, startRow, colCount, stripe){
52911 var ts = this.templates, ct = ts.cell, rt = ts.row;
52913 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52915 var hasListener = this.grid.hasListener('rowclass');
52917 for(var j = 0, len = rs.length; j < len; j++){
52918 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
52919 for(var i = 0; i < colCount; i++){
52921 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52923 p.css = p.attr = "";
52924 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52925 if(p.value == undefined || p.value === "") p.value = " ";
52926 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52927 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52929 var markup = ct.apply(p);
52937 if(stripe && ((rowIndex+1) % 2 == 0)){
52938 alt.push("x-grid-row-alt")
52941 alt.push( " x-grid-dirty-row");
52944 if(this.getRowClass){
52945 alt.push(this.getRowClass(r, rowIndex));
52951 rowIndex : rowIndex,
52954 this.grid.fireEvent('rowclass', this, rowcfg);
52955 alt.push(rowcfg.rowClass);
52957 rp.alt = alt.join(" ");
52958 lbuf+= rt.apply(rp);
52960 buf+= rt.apply(rp);
52962 return [lbuf, buf];
52964 function(cs, rs, ds, startRow, colCount, stripe){
52965 var ts = this.templates, ct = ts.cell, rt = ts.row;
52967 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
52968 var hasListener = this.grid.hasListener('rowclass');
52971 for(var j = 0, len = rs.length; j < len; j++){
52972 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
52973 for(var i = 0; i < colCount; i++){
52975 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
52977 p.css = p.attr = "";
52978 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
52979 if(p.value == undefined || p.value === "") p.value = " ";
52980 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
52981 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
52984 var markup = ct.apply(p);
52986 cb[cb.length] = markup;
52988 lcb[lcb.length] = markup;
52992 if(stripe && ((rowIndex+1) % 2 == 0)){
52993 alt.push( "x-grid-row-alt");
52996 alt.push(" x-grid-dirty-row");
52999 if(this.getRowClass){
53000 alt.push( this.getRowClass(r, rowIndex));
53006 rowIndex : rowIndex,
53009 this.grid.fireEvent('rowclass', this, rowcfg);
53010 alt.push(rowcfg.rowClass);
53012 rp.alt = alt.join(" ");
53013 rp.cells = lcb.join("");
53014 lbuf[lbuf.length] = rt.apply(rp);
53015 rp.cells = cb.join("");
53016 buf[buf.length] = rt.apply(rp);
53018 return [lbuf.join(""), buf.join("")];
53021 renderBody : function(){
53022 var markup = this.renderRows();
53023 var bt = this.templates.body;
53024 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53028 * Refreshes the grid
53029 * @param {Boolean} headersToo
53031 refresh : function(headersToo){
53032 this.fireEvent("beforerefresh", this);
53033 this.grid.stopEditing();
53034 var result = this.renderBody();
53035 this.lockedBody.update(result[0]);
53036 this.mainBody.update(result[1]);
53037 if(headersToo === true){
53038 this.updateHeaders();
53039 this.updateColumns();
53040 this.updateSplitters();
53041 this.updateHeaderSortState();
53043 this.syncRowHeights();
53045 this.fireEvent("refresh", this);
53048 handleColumnMove : function(cm, oldIndex, newIndex){
53049 this.indexMap = null;
53050 var s = this.getScrollState();
53051 this.refresh(true);
53052 this.restoreScroll(s);
53053 this.afterMove(newIndex);
53056 afterMove : function(colIndex){
53057 if(this.enableMoveAnim && Roo.enableFx){
53058 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53060 // if multisort - fix sortOrder, and reload..
53061 if (this.grid.dataSource.multiSort) {
53062 // the we can call sort again..
53063 var dm = this.grid.dataSource;
53064 var cm = this.grid.colModel;
53066 for(var i = 0; i < cm.config.length; i++ ) {
53068 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53069 continue; // dont' bother, it's not in sort list or being set.
53072 so.push(cm.config[i].dataIndex);
53075 dm.load(dm.lastOptions);
53082 updateCell : function(dm, rowIndex, dataIndex){
53083 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53084 if(typeof colIndex == "undefined"){ // not present in grid
53087 var cm = this.grid.colModel;
53088 var cell = this.getCell(rowIndex, colIndex);
53089 var cellText = this.getCellText(rowIndex, colIndex);
53092 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53093 id : cm.getColumnId(colIndex),
53094 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53096 var renderer = cm.getRenderer(colIndex);
53097 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53098 if(typeof val == "undefined" || val === "") val = " ";
53099 cellText.innerHTML = val;
53100 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53101 this.syncRowHeights(rowIndex, rowIndex);
53104 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53106 if(this.grid.autoSizeHeaders){
53107 var h = this.getHeaderCellMeasure(colIndex);
53108 maxWidth = Math.max(maxWidth, h.scrollWidth);
53111 if(this.cm.isLocked(colIndex)){
53112 tb = this.getLockedTable();
53115 tb = this.getBodyTable();
53116 index = colIndex - this.cm.getLockedCount();
53119 var rows = tb.rows;
53120 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53121 for(var i = 0; i < stopIndex; i++){
53122 var cell = rows[i].childNodes[index].firstChild;
53123 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53126 return maxWidth + /*margin for error in IE*/ 5;
53129 * Autofit a column to its content.
53130 * @param {Number} colIndex
53131 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53133 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53134 if(this.cm.isHidden(colIndex)){
53135 return; // can't calc a hidden column
53138 var cid = this.cm.getColumnId(colIndex);
53139 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53140 if(this.grid.autoSizeHeaders){
53141 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53144 var newWidth = this.calcColumnWidth(colIndex);
53145 this.cm.setColumnWidth(colIndex,
53146 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53147 if(!suppressEvent){
53148 this.grid.fireEvent("columnresize", colIndex, newWidth);
53153 * Autofits all columns to their content and then expands to fit any extra space in the grid
53155 autoSizeColumns : function(){
53156 var cm = this.grid.colModel;
53157 var colCount = cm.getColumnCount();
53158 for(var i = 0; i < colCount; i++){
53159 this.autoSizeColumn(i, true, true);
53161 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53164 this.updateColumns();
53170 * Autofits all columns to the grid's width proportionate with their current size
53171 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53173 fitColumns : function(reserveScrollSpace){
53174 var cm = this.grid.colModel;
53175 var colCount = cm.getColumnCount();
53179 for (i = 0; i < colCount; i++){
53180 if(!cm.isHidden(i) && !cm.isFixed(i)){
53181 w = cm.getColumnWidth(i);
53187 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53188 if(reserveScrollSpace){
53191 var frac = (avail - cm.getTotalWidth())/width;
53192 while (cols.length){
53195 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53197 this.updateColumns();
53201 onRowSelect : function(rowIndex){
53202 var row = this.getRowComposite(rowIndex);
53203 row.addClass("x-grid-row-selected");
53206 onRowDeselect : function(rowIndex){
53207 var row = this.getRowComposite(rowIndex);
53208 row.removeClass("x-grid-row-selected");
53211 onCellSelect : function(row, col){
53212 var cell = this.getCell(row, col);
53214 Roo.fly(cell).addClass("x-grid-cell-selected");
53218 onCellDeselect : function(row, col){
53219 var cell = this.getCell(row, col);
53221 Roo.fly(cell).removeClass("x-grid-cell-selected");
53225 updateHeaderSortState : function(){
53227 // sort state can be single { field: xxx, direction : yyy}
53228 // or { xxx=>ASC , yyy : DESC ..... }
53231 if (!this.ds.multiSort) {
53232 var state = this.ds.getSortState();
53236 mstate[state.field] = state.direction;
53237 // FIXME... - this is not used here.. but might be elsewhere..
53238 this.sortState = state;
53241 mstate = this.ds.sortToggle;
53243 //remove existing sort classes..
53245 var sc = this.sortClasses;
53246 var hds = this.el.select(this.headerSelector).removeClass(sc);
53248 for(var f in mstate) {
53250 var sortColumn = this.cm.findColumnIndex(f);
53252 if(sortColumn != -1){
53253 var sortDir = mstate[f];
53254 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53263 handleHeaderClick : function(g, index){
53264 if(this.headersDisabled){
53267 var dm = g.dataSource, cm = g.colModel;
53268 if(!cm.isSortable(index)){
53273 if (dm.multiSort) {
53274 // update the sortOrder
53276 for(var i = 0; i < cm.config.length; i++ ) {
53278 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53279 continue; // dont' bother, it's not in sort list or being set.
53282 so.push(cm.config[i].dataIndex);
53288 dm.sort(cm.getDataIndex(index));
53292 destroy : function(){
53294 this.colMenu.removeAll();
53295 Roo.menu.MenuMgr.unregister(this.colMenu);
53296 this.colMenu.getEl().remove();
53297 delete this.colMenu;
53300 this.hmenu.removeAll();
53301 Roo.menu.MenuMgr.unregister(this.hmenu);
53302 this.hmenu.getEl().remove();
53305 if(this.grid.enableColumnMove){
53306 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53308 for(var dd in dds){
53309 if(!dds[dd].config.isTarget && dds[dd].dragElId){
53310 var elid = dds[dd].dragElId;
53312 Roo.get(elid).remove();
53313 } else if(dds[dd].config.isTarget){
53314 dds[dd].proxyTop.remove();
53315 dds[dd].proxyBottom.remove();
53318 if(Roo.dd.DDM.locationCache[dd]){
53319 delete Roo.dd.DDM.locationCache[dd];
53322 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53325 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
53326 this.bind(null, null);
53327 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
53330 handleLockChange : function(){
53331 this.refresh(true);
53334 onDenyColumnLock : function(){
53338 onDenyColumnHide : function(){
53342 handleHdMenuClick : function(item){
53343 var index = this.hdCtxIndex;
53344 var cm = this.cm, ds = this.ds;
53347 ds.sort(cm.getDataIndex(index), "ASC");
53350 ds.sort(cm.getDataIndex(index), "DESC");
53353 var lc = cm.getLockedCount();
53354 if(cm.getColumnCount(true) <= lc+1){
53355 this.onDenyColumnLock();
53359 cm.setLocked(index, true, true);
53360 cm.moveColumn(index, lc);
53361 this.grid.fireEvent("columnmove", index, lc);
53363 cm.setLocked(index, true);
53367 var lc = cm.getLockedCount();
53368 if((lc-1) != index){
53369 cm.setLocked(index, false, true);
53370 cm.moveColumn(index, lc-1);
53371 this.grid.fireEvent("columnmove", index, lc-1);
53373 cm.setLocked(index, false);
53377 index = cm.getIndexById(item.id.substr(4));
53379 if(item.checked && cm.getColumnCount(true) <= 1){
53380 this.onDenyColumnHide();
53383 cm.setHidden(index, item.checked);
53389 beforeColMenuShow : function(){
53390 var cm = this.cm, colCount = cm.getColumnCount();
53391 this.colMenu.removeAll();
53392 for(var i = 0; i < colCount; i++){
53393 this.colMenu.add(new Roo.menu.CheckItem({
53394 id: "col-"+cm.getColumnId(i),
53395 text: cm.getColumnHeader(i),
53396 checked: !cm.isHidden(i),
53402 handleHdCtx : function(g, index, e){
53404 var hd = this.getHeaderCell(index);
53405 this.hdCtxIndex = index;
53406 var ms = this.hmenu.items, cm = this.cm;
53407 ms.get("asc").setDisabled(!cm.isSortable(index));
53408 ms.get("desc").setDisabled(!cm.isSortable(index));
53409 if(this.grid.enableColLock !== false){
53410 ms.get("lock").setDisabled(cm.isLocked(index));
53411 ms.get("unlock").setDisabled(!cm.isLocked(index));
53413 this.hmenu.show(hd, "tl-bl");
53416 handleHdOver : function(e){
53417 var hd = this.findHeaderCell(e.getTarget());
53418 if(hd && !this.headersDisabled){
53419 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
53420 this.fly(hd).addClass("x-grid-hd-over");
53425 handleHdOut : function(e){
53426 var hd = this.findHeaderCell(e.getTarget());
53428 this.fly(hd).removeClass("x-grid-hd-over");
53432 handleSplitDblClick : function(e, t){
53433 var i = this.getCellIndex(t);
53434 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
53435 this.autoSizeColumn(i, true);
53440 render : function(){
53443 var colCount = cm.getColumnCount();
53445 if(this.grid.monitorWindowResize === true){
53446 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
53448 var header = this.renderHeaders();
53449 var body = this.templates.body.apply({rows:""});
53450 var html = this.templates.master.apply({
53453 lockedHeader: header[0],
53457 //this.updateColumns();
53459 this.grid.getGridEl().dom.innerHTML = html;
53461 this.initElements();
53463 // a kludge to fix the random scolling effect in webkit
53464 this.el.on("scroll", function() {
53465 this.el.dom.scrollTop=0; // hopefully not recursive..
53468 this.scroller.on("scroll", this.handleScroll, this);
53469 this.lockedBody.on("mousewheel", this.handleWheel, this);
53470 this.mainBody.on("mousewheel", this.handleWheel, this);
53472 this.mainHd.on("mouseover", this.handleHdOver, this);
53473 this.mainHd.on("mouseout", this.handleHdOut, this);
53474 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
53475 {delegate: "."+this.splitClass});
53477 this.lockedHd.on("mouseover", this.handleHdOver, this);
53478 this.lockedHd.on("mouseout", this.handleHdOut, this);
53479 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
53480 {delegate: "."+this.splitClass});
53482 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
53483 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53486 this.updateSplitters();
53488 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
53489 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53490 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53493 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
53494 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
53496 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
53497 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
53499 if(this.grid.enableColLock !== false){
53500 this.hmenu.add('-',
53501 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
53502 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
53505 if(this.grid.enableColumnHide !== false){
53507 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
53508 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
53509 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
53511 this.hmenu.add('-',
53512 {id:"columns", text: this.columnsText, menu: this.colMenu}
53515 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
53517 this.grid.on("headercontextmenu", this.handleHdCtx, this);
53520 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
53521 this.dd = new Roo.grid.GridDragZone(this.grid, {
53522 ddGroup : this.grid.ddGroup || 'GridDD'
53528 for(var i = 0; i < colCount; i++){
53529 if(cm.isHidden(i)){
53530 this.hideColumn(i);
53532 if(cm.config[i].align){
53533 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
53534 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
53538 this.updateHeaderSortState();
53540 this.beforeInitialResize();
53543 // two part rendering gives faster view to the user
53544 this.renderPhase2.defer(1, this);
53547 renderPhase2 : function(){
53548 // render the rows now
53550 if(this.grid.autoSizeColumns){
53551 this.autoSizeColumns();
53555 beforeInitialResize : function(){
53559 onColumnSplitterMoved : function(i, w){
53560 this.userResized = true;
53561 var cm = this.grid.colModel;
53562 cm.setColumnWidth(i, w, true);
53563 var cid = cm.getColumnId(i);
53564 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53565 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53566 this.updateSplitters();
53568 this.grid.fireEvent("columnresize", i, w);
53571 syncRowHeights : function(startIndex, endIndex){
53572 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
53573 startIndex = startIndex || 0;
53574 var mrows = this.getBodyTable().rows;
53575 var lrows = this.getLockedTable().rows;
53576 var len = mrows.length-1;
53577 endIndex = Math.min(endIndex || len, len);
53578 for(var i = startIndex; i <= endIndex; i++){
53579 var m = mrows[i], l = lrows[i];
53580 var h = Math.max(m.offsetHeight, l.offsetHeight);
53581 m.style.height = l.style.height = h + "px";
53586 layout : function(initialRender, is2ndPass){
53588 var auto = g.autoHeight;
53589 var scrollOffset = 16;
53590 var c = g.getGridEl(), cm = this.cm,
53591 expandCol = g.autoExpandColumn,
53593 //c.beginMeasure();
53595 if(!c.dom.offsetWidth){ // display:none?
53597 this.lockedWrap.show();
53598 this.mainWrap.show();
53603 var hasLock = this.cm.isLocked(0);
53605 var tbh = this.headerPanel.getHeight();
53606 var bbh = this.footerPanel.getHeight();
53609 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
53610 var newHeight = ch + c.getBorderWidth("tb");
53612 newHeight = Math.min(g.maxHeight, newHeight);
53614 c.setHeight(newHeight);
53618 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
53621 var s = this.scroller;
53623 var csize = c.getSize(true);
53625 this.el.setSize(csize.width, csize.height);
53627 this.headerPanel.setWidth(csize.width);
53628 this.footerPanel.setWidth(csize.width);
53630 var hdHeight = this.mainHd.getHeight();
53631 var vw = csize.width;
53632 var vh = csize.height - (tbh + bbh);
53636 var bt = this.getBodyTable();
53637 var ltWidth = hasLock ?
53638 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
53640 var scrollHeight = bt.offsetHeight;
53641 var scrollWidth = ltWidth + bt.offsetWidth;
53642 var vscroll = false, hscroll = false;
53644 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
53646 var lw = this.lockedWrap, mw = this.mainWrap;
53647 var lb = this.lockedBody, mb = this.mainBody;
53649 setTimeout(function(){
53650 var t = s.dom.offsetTop;
53651 var w = s.dom.clientWidth,
53652 h = s.dom.clientHeight;
53655 lw.setSize(ltWidth, h);
53657 mw.setLeftTop(ltWidth, t);
53658 mw.setSize(w-ltWidth, h);
53660 lb.setHeight(h-hdHeight);
53661 mb.setHeight(h-hdHeight);
53663 if(is2ndPass !== true && !gv.userResized && expandCol){
53664 // high speed resize without full column calculation
53666 var ci = cm.getIndexById(expandCol);
53668 ci = cm.findColumnIndex(expandCol);
53670 ci = Math.max(0, ci); // make sure it's got at least the first col.
53671 var expandId = cm.getColumnId(ci);
53672 var tw = cm.getTotalWidth(false);
53673 var currentWidth = cm.getColumnWidth(ci);
53674 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
53675 if(currentWidth != cw){
53676 cm.setColumnWidth(ci, cw, true);
53677 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53678 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
53679 gv.updateSplitters();
53680 gv.layout(false, true);
53692 onWindowResize : function(){
53693 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
53699 appendFooter : function(parentEl){
53703 sortAscText : "Sort Ascending",
53704 sortDescText : "Sort Descending",
53705 lockText : "Lock Column",
53706 unlockText : "Unlock Column",
53707 columnsText : "Columns"
53711 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
53712 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
53713 this.proxy.el.addClass('x-grid3-col-dd');
53716 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
53717 handleMouseDown : function(e){
53721 callHandleMouseDown : function(e){
53722 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
53727 * Ext JS Library 1.1.1
53728 * Copyright(c) 2006-2007, Ext JS, LLC.
53730 * Originally Released Under LGPL - original licence link has changed is not relivant.
53733 * <script type="text/javascript">
53737 // This is a support class used internally by the Grid components
53738 Roo.grid.SplitDragZone = function(grid, hd, hd2){
53740 this.view = grid.getView();
53741 this.proxy = this.view.resizeProxy;
53742 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
53743 "gridSplitters" + this.grid.getGridEl().id, {
53744 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
53746 this.setHandleElId(Roo.id(hd));
53747 this.setOuterHandleElId(Roo.id(hd2));
53748 this.scroll = false;
53750 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
53751 fly: Roo.Element.fly,
53753 b4StartDrag : function(x, y){
53754 this.view.headersDisabled = true;
53755 this.proxy.setHeight(this.view.mainWrap.getHeight());
53756 var w = this.cm.getColumnWidth(this.cellIndex);
53757 var minw = Math.max(w-this.grid.minColumnWidth, 0);
53758 this.resetConstraints();
53759 this.setXConstraint(minw, 1000);
53760 this.setYConstraint(0, 0);
53761 this.minX = x - minw;
53762 this.maxX = x + 1000;
53764 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
53768 handleMouseDown : function(e){
53769 ev = Roo.EventObject.setEvent(e);
53770 var t = this.fly(ev.getTarget());
53771 if(t.hasClass("x-grid-split")){
53772 this.cellIndex = this.view.getCellIndex(t.dom);
53773 this.split = t.dom;
53774 this.cm = this.grid.colModel;
53775 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
53776 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
53781 endDrag : function(e){
53782 this.view.headersDisabled = false;
53783 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
53784 var diff = endX - this.startPos;
53785 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
53788 autoOffset : function(){
53789 this.setDelta(0,0);
53793 * Ext JS Library 1.1.1
53794 * Copyright(c) 2006-2007, Ext JS, LLC.
53796 * Originally Released Under LGPL - original licence link has changed is not relivant.
53799 * <script type="text/javascript">
53803 // This is a support class used internally by the Grid components
53804 Roo.grid.GridDragZone = function(grid, config){
53805 this.view = grid.getView();
53806 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
53807 if(this.view.lockedBody){
53808 this.setHandleElId(Roo.id(this.view.mainBody.dom));
53809 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
53811 this.scroll = false;
53813 this.ddel = document.createElement('div');
53814 this.ddel.className = 'x-grid-dd-wrap';
53817 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
53818 ddGroup : "GridDD",
53820 getDragData : function(e){
53821 var t = Roo.lib.Event.getTarget(e);
53822 var rowIndex = this.view.findRowIndex(t);
53823 var sm = this.grid.selModel;
53825 //Roo.log(rowIndex);
53827 if (sm.getSelectedCell) {
53828 // cell selection..
53829 if (!sm.getSelectedCell()) {
53832 if (rowIndex != sm.getSelectedCell()[0]) {
53838 if(rowIndex !== false){
53843 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
53845 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
53848 if (e.hasModifier()){
53849 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
53852 Roo.log("getDragData");
53857 rowIndex: rowIndex,
53858 selections:sm.getSelections ? sm.getSelections() : (
53859 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
53866 onInitDrag : function(e){
53867 var data = this.dragData;
53868 this.ddel.innerHTML = this.grid.getDragDropText();
53869 this.proxy.update(this.ddel);
53870 // fire start drag?
53873 afterRepair : function(){
53874 this.dragging = false;
53877 getRepairXY : function(e, data){
53881 onEndDrag : function(data, e){
53885 onValidDrop : function(dd, e, id){
53890 beforeInvalidDrop : function(e, id){
53895 * Ext JS Library 1.1.1
53896 * Copyright(c) 2006-2007, Ext JS, LLC.
53898 * Originally Released Under LGPL - original licence link has changed is not relivant.
53901 * <script type="text/javascript">
53906 * @class Roo.grid.ColumnModel
53907 * @extends Roo.util.Observable
53908 * This is the default implementation of a ColumnModel used by the Grid. It defines
53909 * the columns in the grid.
53912 var colModel = new Roo.grid.ColumnModel([
53913 {header: "Ticker", width: 60, sortable: true, locked: true},
53914 {header: "Company Name", width: 150, sortable: true},
53915 {header: "Market Cap.", width: 100, sortable: true},
53916 {header: "$ Sales", width: 100, sortable: true, renderer: money},
53917 {header: "Employees", width: 100, sortable: true, resizable: false}
53922 * The config options listed for this class are options which may appear in each
53923 * individual column definition.
53924 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
53926 * @param {Object} config An Array of column config objects. See this class's
53927 * config objects for details.
53929 Roo.grid.ColumnModel = function(config){
53931 * The config passed into the constructor
53933 this.config = config;
53936 // if no id, create one
53937 // if the column does not have a dataIndex mapping,
53938 // map it to the order it is in the config
53939 for(var i = 0, len = config.length; i < len; i++){
53941 if(typeof c.dataIndex == "undefined"){
53944 if(typeof c.renderer == "string"){
53945 c.renderer = Roo.util.Format[c.renderer];
53947 if(typeof c.id == "undefined"){
53950 if(c.editor && c.editor.xtype){
53951 c.editor = Roo.factory(c.editor, Roo.grid);
53953 if(c.editor && c.editor.isFormField){
53954 c.editor = new Roo.grid.GridEditor(c.editor);
53956 this.lookup[c.id] = c;
53960 * The width of columns which have no width specified (defaults to 100)
53963 this.defaultWidth = 100;
53966 * Default sortable of columns which have no sortable specified (defaults to false)
53969 this.defaultSortable = false;
53973 * @event widthchange
53974 * Fires when the width of a column changes.
53975 * @param {ColumnModel} this
53976 * @param {Number} columnIndex The column index
53977 * @param {Number} newWidth The new width
53979 "widthchange": true,
53981 * @event headerchange
53982 * Fires when the text of a header changes.
53983 * @param {ColumnModel} this
53984 * @param {Number} columnIndex The column index
53985 * @param {Number} newText The new header text
53987 "headerchange": true,
53989 * @event hiddenchange
53990 * Fires when a column is hidden or "unhidden".
53991 * @param {ColumnModel} this
53992 * @param {Number} columnIndex The column index
53993 * @param {Boolean} hidden true if hidden, false otherwise
53995 "hiddenchange": true,
53997 * @event columnmoved
53998 * Fires when a column is moved.
53999 * @param {ColumnModel} this
54000 * @param {Number} oldIndex
54001 * @param {Number} newIndex
54003 "columnmoved" : true,
54005 * @event columlockchange
54006 * Fires when a column's locked state is changed
54007 * @param {ColumnModel} this
54008 * @param {Number} colIndex
54009 * @param {Boolean} locked true if locked
54011 "columnlockchange" : true
54013 Roo.grid.ColumnModel.superclass.constructor.call(this);
54015 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54017 * @cfg {String} header The header text to display in the Grid view.
54020 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54021 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54022 * specified, the column's index is used as an index into the Record's data Array.
54025 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54026 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54029 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54030 * Defaults to the value of the {@link #defaultSortable} property.
54031 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54034 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54037 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54040 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54043 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54046 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54047 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54048 * default renderer uses the raw data value.
54051 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54054 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54058 * Returns the id of the column at the specified index.
54059 * @param {Number} index The column index
54060 * @return {String} the id
54062 getColumnId : function(index){
54063 return this.config[index].id;
54067 * Returns the column for a specified id.
54068 * @param {String} id The column id
54069 * @return {Object} the column
54071 getColumnById : function(id){
54072 return this.lookup[id];
54077 * Returns the column for a specified dataIndex.
54078 * @param {String} dataIndex The column dataIndex
54079 * @return {Object|Boolean} the column or false if not found
54081 getColumnByDataIndex: function(dataIndex){
54082 var index = this.findColumnIndex(dataIndex);
54083 return index > -1 ? this.config[index] : false;
54087 * Returns the index for a specified column id.
54088 * @param {String} id The column id
54089 * @return {Number} the index, or -1 if not found
54091 getIndexById : function(id){
54092 for(var i = 0, len = this.config.length; i < len; i++){
54093 if(this.config[i].id == id){
54101 * Returns the index for a specified column dataIndex.
54102 * @param {String} dataIndex The column dataIndex
54103 * @return {Number} the index, or -1 if not found
54106 findColumnIndex : function(dataIndex){
54107 for(var i = 0, len = this.config.length; i < len; i++){
54108 if(this.config[i].dataIndex == dataIndex){
54116 moveColumn : function(oldIndex, newIndex){
54117 var c = this.config[oldIndex];
54118 this.config.splice(oldIndex, 1);
54119 this.config.splice(newIndex, 0, c);
54120 this.dataMap = null;
54121 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54124 isLocked : function(colIndex){
54125 return this.config[colIndex].locked === true;
54128 setLocked : function(colIndex, value, suppressEvent){
54129 if(this.isLocked(colIndex) == value){
54132 this.config[colIndex].locked = value;
54133 if(!suppressEvent){
54134 this.fireEvent("columnlockchange", this, colIndex, value);
54138 getTotalLockedWidth : function(){
54139 var totalWidth = 0;
54140 for(var i = 0; i < this.config.length; i++){
54141 if(this.isLocked(i) && !this.isHidden(i)){
54142 this.totalWidth += this.getColumnWidth(i);
54148 getLockedCount : function(){
54149 for(var i = 0, len = this.config.length; i < len; i++){
54150 if(!this.isLocked(i)){
54157 * Returns the number of columns.
54160 getColumnCount : function(visibleOnly){
54161 if(visibleOnly === true){
54163 for(var i = 0, len = this.config.length; i < len; i++){
54164 if(!this.isHidden(i)){
54170 return this.config.length;
54174 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54175 * @param {Function} fn
54176 * @param {Object} scope (optional)
54177 * @return {Array} result
54179 getColumnsBy : function(fn, scope){
54181 for(var i = 0, len = this.config.length; i < len; i++){
54182 var c = this.config[i];
54183 if(fn.call(scope||this, c, i) === true){
54191 * Returns true if the specified column is sortable.
54192 * @param {Number} col The column index
54193 * @return {Boolean}
54195 isSortable : function(col){
54196 if(typeof this.config[col].sortable == "undefined"){
54197 return this.defaultSortable;
54199 return this.config[col].sortable;
54203 * Returns the rendering (formatting) function defined for the column.
54204 * @param {Number} col The column index.
54205 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54207 getRenderer : function(col){
54208 if(!this.config[col].renderer){
54209 return Roo.grid.ColumnModel.defaultRenderer;
54211 return this.config[col].renderer;
54215 * Sets the rendering (formatting) function for a column.
54216 * @param {Number} col The column index
54217 * @param {Function} fn The function to use to process the cell's raw data
54218 * to return HTML markup for the grid view. The render function is called with
54219 * the following parameters:<ul>
54220 * <li>Data value.</li>
54221 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54222 * <li>css A CSS style string to apply to the table cell.</li>
54223 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54224 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54225 * <li>Row index</li>
54226 * <li>Column index</li>
54227 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54229 setRenderer : function(col, fn){
54230 this.config[col].renderer = fn;
54234 * Returns the width for the specified column.
54235 * @param {Number} col The column index
54238 getColumnWidth : function(col){
54239 return this.config[col].width * 1 || this.defaultWidth;
54243 * Sets the width for a column.
54244 * @param {Number} col The column index
54245 * @param {Number} width The new width
54247 setColumnWidth : function(col, width, suppressEvent){
54248 this.config[col].width = width;
54249 this.totalWidth = null;
54250 if(!suppressEvent){
54251 this.fireEvent("widthchange", this, col, width);
54256 * Returns the total width of all columns.
54257 * @param {Boolean} includeHidden True to include hidden column widths
54260 getTotalWidth : function(includeHidden){
54261 if(!this.totalWidth){
54262 this.totalWidth = 0;
54263 for(var i = 0, len = this.config.length; i < len; i++){
54264 if(includeHidden || !this.isHidden(i)){
54265 this.totalWidth += this.getColumnWidth(i);
54269 return this.totalWidth;
54273 * Returns the header for the specified column.
54274 * @param {Number} col The column index
54277 getColumnHeader : function(col){
54278 return this.config[col].header;
54282 * Sets the header for a column.
54283 * @param {Number} col The column index
54284 * @param {String} header The new header
54286 setColumnHeader : function(col, header){
54287 this.config[col].header = header;
54288 this.fireEvent("headerchange", this, col, header);
54292 * Returns the tooltip for the specified column.
54293 * @param {Number} col The column index
54296 getColumnTooltip : function(col){
54297 return this.config[col].tooltip;
54300 * Sets the tooltip for a column.
54301 * @param {Number} col The column index
54302 * @param {String} tooltip The new tooltip
54304 setColumnTooltip : function(col, tooltip){
54305 this.config[col].tooltip = tooltip;
54309 * Returns the dataIndex for the specified column.
54310 * @param {Number} col The column index
54313 getDataIndex : function(col){
54314 return this.config[col].dataIndex;
54318 * Sets the dataIndex for a column.
54319 * @param {Number} col The column index
54320 * @param {Number} dataIndex The new dataIndex
54322 setDataIndex : function(col, dataIndex){
54323 this.config[col].dataIndex = dataIndex;
54329 * Returns true if the cell is editable.
54330 * @param {Number} colIndex The column index
54331 * @param {Number} rowIndex The row index
54332 * @return {Boolean}
54334 isCellEditable : function(colIndex, rowIndex){
54335 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
54339 * Returns the editor defined for the cell/column.
54340 * return false or null to disable editing.
54341 * @param {Number} colIndex The column index
54342 * @param {Number} rowIndex The row index
54345 getCellEditor : function(colIndex, rowIndex){
54346 return this.config[colIndex].editor;
54350 * Sets if a column is editable.
54351 * @param {Number} col The column index
54352 * @param {Boolean} editable True if the column is editable
54354 setEditable : function(col, editable){
54355 this.config[col].editable = editable;
54360 * Returns true if the column is hidden.
54361 * @param {Number} colIndex The column index
54362 * @return {Boolean}
54364 isHidden : function(colIndex){
54365 return this.config[colIndex].hidden;
54370 * Returns true if the column width cannot be changed
54372 isFixed : function(colIndex){
54373 return this.config[colIndex].fixed;
54377 * Returns true if the column can be resized
54378 * @return {Boolean}
54380 isResizable : function(colIndex){
54381 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
54384 * Sets if a column is hidden.
54385 * @param {Number} colIndex The column index
54386 * @param {Boolean} hidden True if the column is hidden
54388 setHidden : function(colIndex, hidden){
54389 this.config[colIndex].hidden = hidden;
54390 this.totalWidth = null;
54391 this.fireEvent("hiddenchange", this, colIndex, hidden);
54395 * Sets the editor for a column.
54396 * @param {Number} col The column index
54397 * @param {Object} editor The editor object
54399 setEditor : function(col, editor){
54400 this.config[col].editor = editor;
54404 Roo.grid.ColumnModel.defaultRenderer = function(value){
54405 if(typeof value == "string" && value.length < 1){
54411 // Alias for backwards compatibility
54412 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
54415 * Ext JS Library 1.1.1
54416 * Copyright(c) 2006-2007, Ext JS, LLC.
54418 * Originally Released Under LGPL - original licence link has changed is not relivant.
54421 * <script type="text/javascript">
54425 * @class Roo.grid.AbstractSelectionModel
54426 * @extends Roo.util.Observable
54427 * Abstract base class for grid SelectionModels. It provides the interface that should be
54428 * implemented by descendant classes. This class should not be directly instantiated.
54431 Roo.grid.AbstractSelectionModel = function(){
54432 this.locked = false;
54433 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
54436 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
54437 /** @ignore Called by the grid automatically. Do not call directly. */
54438 init : function(grid){
54444 * Locks the selections.
54447 this.locked = true;
54451 * Unlocks the selections.
54453 unlock : function(){
54454 this.locked = false;
54458 * Returns true if the selections are locked.
54459 * @return {Boolean}
54461 isLocked : function(){
54462 return this.locked;
54466 * Ext JS Library 1.1.1
54467 * Copyright(c) 2006-2007, Ext JS, LLC.
54469 * Originally Released Under LGPL - original licence link has changed is not relivant.
54472 * <script type="text/javascript">
54475 * @extends Roo.grid.AbstractSelectionModel
54476 * @class Roo.grid.RowSelectionModel
54477 * The default SelectionModel used by {@link Roo.grid.Grid}.
54478 * It supports multiple selections and keyboard selection/navigation.
54480 * @param {Object} config
54482 Roo.grid.RowSelectionModel = function(config){
54483 Roo.apply(this, config);
54484 this.selections = new Roo.util.MixedCollection(false, function(o){
54489 this.lastActive = false;
54493 * @event selectionchange
54494 * Fires when the selection changes
54495 * @param {SelectionModel} this
54497 "selectionchange" : true,
54499 * @event afterselectionchange
54500 * Fires after the selection changes (eg. by key press or clicking)
54501 * @param {SelectionModel} this
54503 "afterselectionchange" : true,
54505 * @event beforerowselect
54506 * Fires when a row is selected being selected, return false to cancel.
54507 * @param {SelectionModel} this
54508 * @param {Number} rowIndex The selected index
54509 * @param {Boolean} keepExisting False if other selections will be cleared
54511 "beforerowselect" : true,
54514 * Fires when a row is selected.
54515 * @param {SelectionModel} this
54516 * @param {Number} rowIndex The selected index
54517 * @param {Roo.data.Record} r The record
54519 "rowselect" : true,
54521 * @event rowdeselect
54522 * Fires when a row is deselected.
54523 * @param {SelectionModel} this
54524 * @param {Number} rowIndex The selected index
54526 "rowdeselect" : true
54528 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
54529 this.locked = false;
54532 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
54534 * @cfg {Boolean} singleSelect
54535 * True to allow selection of only one row at a time (defaults to false)
54537 singleSelect : false,
54540 initEvents : function(){
54542 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
54543 this.grid.on("mousedown", this.handleMouseDown, this);
54544 }else{ // allow click to work like normal
54545 this.grid.on("rowclick", this.handleDragableRowClick, this);
54548 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
54549 "up" : function(e){
54551 this.selectPrevious(e.shiftKey);
54552 }else if(this.last !== false && this.lastActive !== false){
54553 var last = this.last;
54554 this.selectRange(this.last, this.lastActive-1);
54555 this.grid.getView().focusRow(this.lastActive);
54556 if(last !== false){
54560 this.selectFirstRow();
54562 this.fireEvent("afterselectionchange", this);
54564 "down" : function(e){
54566 this.selectNext(e.shiftKey);
54567 }else if(this.last !== false && this.lastActive !== false){
54568 var last = this.last;
54569 this.selectRange(this.last, this.lastActive+1);
54570 this.grid.getView().focusRow(this.lastActive);
54571 if(last !== false){
54575 this.selectFirstRow();
54577 this.fireEvent("afterselectionchange", this);
54582 var view = this.grid.view;
54583 view.on("refresh", this.onRefresh, this);
54584 view.on("rowupdated", this.onRowUpdated, this);
54585 view.on("rowremoved", this.onRemove, this);
54589 onRefresh : function(){
54590 var ds = this.grid.dataSource, i, v = this.grid.view;
54591 var s = this.selections;
54592 s.each(function(r){
54593 if((i = ds.indexOfId(r.id)) != -1){
54602 onRemove : function(v, index, r){
54603 this.selections.remove(r);
54607 onRowUpdated : function(v, index, r){
54608 if(this.isSelected(r)){
54609 v.onRowSelect(index);
54615 * @param {Array} records The records to select
54616 * @param {Boolean} keepExisting (optional) True to keep existing selections
54618 selectRecords : function(records, keepExisting){
54620 this.clearSelections();
54622 var ds = this.grid.dataSource;
54623 for(var i = 0, len = records.length; i < len; i++){
54624 this.selectRow(ds.indexOf(records[i]), true);
54629 * Gets the number of selected rows.
54632 getCount : function(){
54633 return this.selections.length;
54637 * Selects the first row in the grid.
54639 selectFirstRow : function(){
54644 * Select the last row.
54645 * @param {Boolean} keepExisting (optional) True to keep existing selections
54647 selectLastRow : function(keepExisting){
54648 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
54652 * Selects the row immediately following the last selected row.
54653 * @param {Boolean} keepExisting (optional) True to keep existing selections
54655 selectNext : function(keepExisting){
54656 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
54657 this.selectRow(this.last+1, keepExisting);
54658 this.grid.getView().focusRow(this.last);
54663 * Selects the row that precedes the last selected row.
54664 * @param {Boolean} keepExisting (optional) True to keep existing selections
54666 selectPrevious : function(keepExisting){
54668 this.selectRow(this.last-1, keepExisting);
54669 this.grid.getView().focusRow(this.last);
54674 * Returns the selected records
54675 * @return {Array} Array of selected records
54677 getSelections : function(){
54678 return [].concat(this.selections.items);
54682 * Returns the first selected record.
54685 getSelected : function(){
54686 return this.selections.itemAt(0);
54691 * Clears all selections.
54693 clearSelections : function(fast){
54694 if(this.locked) return;
54696 var ds = this.grid.dataSource;
54697 var s = this.selections;
54698 s.each(function(r){
54699 this.deselectRow(ds.indexOfId(r.id));
54703 this.selections.clear();
54710 * Selects all rows.
54712 selectAll : function(){
54713 if(this.locked) return;
54714 this.selections.clear();
54715 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
54716 this.selectRow(i, true);
54721 * Returns True if there is a selection.
54722 * @return {Boolean}
54724 hasSelection : function(){
54725 return this.selections.length > 0;
54729 * Returns True if the specified row is selected.
54730 * @param {Number/Record} record The record or index of the record to check
54731 * @return {Boolean}
54733 isSelected : function(index){
54734 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
54735 return (r && this.selections.key(r.id) ? true : false);
54739 * Returns True if the specified record id is selected.
54740 * @param {String} id The id of record to check
54741 * @return {Boolean}
54743 isIdSelected : function(id){
54744 return (this.selections.key(id) ? true : false);
54748 handleMouseDown : function(e, t){
54749 var view = this.grid.getView(), rowIndex;
54750 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
54753 if(e.shiftKey && this.last !== false){
54754 var last = this.last;
54755 this.selectRange(last, rowIndex, e.ctrlKey);
54756 this.last = last; // reset the last
54757 view.focusRow(rowIndex);
54759 var isSelected = this.isSelected(rowIndex);
54760 if(e.button !== 0 && isSelected){
54761 view.focusRow(rowIndex);
54762 }else if(e.ctrlKey && isSelected){
54763 this.deselectRow(rowIndex);
54764 }else if(!isSelected){
54765 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
54766 view.focusRow(rowIndex);
54769 this.fireEvent("afterselectionchange", this);
54772 handleDragableRowClick : function(grid, rowIndex, e)
54774 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
54775 this.selectRow(rowIndex, false);
54776 grid.view.focusRow(rowIndex);
54777 this.fireEvent("afterselectionchange", this);
54782 * Selects multiple rows.
54783 * @param {Array} rows Array of the indexes of the row to select
54784 * @param {Boolean} keepExisting (optional) True to keep existing selections
54786 selectRows : function(rows, keepExisting){
54788 this.clearSelections();
54790 for(var i = 0, len = rows.length; i < len; i++){
54791 this.selectRow(rows[i], true);
54796 * Selects a range of rows. All rows in between startRow and endRow are also selected.
54797 * @param {Number} startRow The index of the first row in the range
54798 * @param {Number} endRow The index of the last row in the range
54799 * @param {Boolean} keepExisting (optional) True to retain existing selections
54801 selectRange : function(startRow, endRow, keepExisting){
54802 if(this.locked) return;
54804 this.clearSelections();
54806 if(startRow <= endRow){
54807 for(var i = startRow; i <= endRow; i++){
54808 this.selectRow(i, true);
54811 for(var i = startRow; i >= endRow; i--){
54812 this.selectRow(i, true);
54818 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
54819 * @param {Number} startRow The index of the first row in the range
54820 * @param {Number} endRow The index of the last row in the range
54822 deselectRange : function(startRow, endRow, preventViewNotify){
54823 if(this.locked) return;
54824 for(var i = startRow; i <= endRow; i++){
54825 this.deselectRow(i, preventViewNotify);
54831 * @param {Number} row The index of the row to select
54832 * @param {Boolean} keepExisting (optional) True to keep existing selections
54834 selectRow : function(index, keepExisting, preventViewNotify){
54835 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
54836 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
54837 if(!keepExisting || this.singleSelect){
54838 this.clearSelections();
54840 var r = this.grid.dataSource.getAt(index);
54841 this.selections.add(r);
54842 this.last = this.lastActive = index;
54843 if(!preventViewNotify){
54844 this.grid.getView().onRowSelect(index);
54846 this.fireEvent("rowselect", this, index, r);
54847 this.fireEvent("selectionchange", this);
54853 * @param {Number} row The index of the row to deselect
54855 deselectRow : function(index, preventViewNotify){
54856 if(this.locked) return;
54857 if(this.last == index){
54860 if(this.lastActive == index){
54861 this.lastActive = false;
54863 var r = this.grid.dataSource.getAt(index);
54864 this.selections.remove(r);
54865 if(!preventViewNotify){
54866 this.grid.getView().onRowDeselect(index);
54868 this.fireEvent("rowdeselect", this, index);
54869 this.fireEvent("selectionchange", this);
54873 restoreLast : function(){
54875 this.last = this._last;
54880 acceptsNav : function(row, col, cm){
54881 return !cm.isHidden(col) && cm.isCellEditable(col, row);
54885 onEditorKey : function(field, e){
54886 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
54891 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
54893 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
54895 }else if(k == e.ENTER && !e.ctrlKey){
54899 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
54901 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
54903 }else if(k == e.ESC){
54907 g.startEditing(newCell[0], newCell[1]);
54912 * Ext JS Library 1.1.1
54913 * Copyright(c) 2006-2007, Ext JS, LLC.
54915 * Originally Released Under LGPL - original licence link has changed is not relivant.
54918 * <script type="text/javascript">
54921 * @class Roo.grid.CellSelectionModel
54922 * @extends Roo.grid.AbstractSelectionModel
54923 * This class provides the basic implementation for cell selection in a grid.
54925 * @param {Object} config The object containing the configuration of this model.
54926 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
54928 Roo.grid.CellSelectionModel = function(config){
54929 Roo.apply(this, config);
54931 this.selection = null;
54935 * @event beforerowselect
54936 * Fires before a cell is selected.
54937 * @param {SelectionModel} this
54938 * @param {Number} rowIndex The selected row index
54939 * @param {Number} colIndex The selected cell index
54941 "beforecellselect" : true,
54943 * @event cellselect
54944 * Fires when a cell is selected.
54945 * @param {SelectionModel} this
54946 * @param {Number} rowIndex The selected row index
54947 * @param {Number} colIndex The selected cell index
54949 "cellselect" : true,
54951 * @event selectionchange
54952 * Fires when the active selection changes.
54953 * @param {SelectionModel} this
54954 * @param {Object} selection null for no selection or an object (o) with two properties
54956 <li>o.record: the record object for the row the selection is in</li>
54957 <li>o.cell: An array of [rowIndex, columnIndex]</li>
54960 "selectionchange" : true,
54963 * Fires when the tab (or enter) was pressed on the last editable cell
54964 * You can use this to trigger add new row.
54965 * @param {SelectionModel} this
54969 * @event beforeeditnext
54970 * Fires before the next editable sell is made active
54971 * You can use this to skip to another cell or fire the tabend
54972 * if you set cell to false
54973 * @param {Object} eventdata object : { cell : [ row, col ] }
54975 "beforeeditnext" : true
54977 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
54980 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
54982 enter_is_tab: false,
54985 initEvents : function(){
54986 this.grid.on("mousedown", this.handleMouseDown, this);
54987 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
54988 var view = this.grid.view;
54989 view.on("refresh", this.onViewChange, this);
54990 view.on("rowupdated", this.onRowUpdated, this);
54991 view.on("beforerowremoved", this.clearSelections, this);
54992 view.on("beforerowsinserted", this.clearSelections, this);
54993 if(this.grid.isEditor){
54994 this.grid.on("beforeedit", this.beforeEdit, this);
54999 beforeEdit : function(e){
55000 this.select(e.row, e.column, false, true, e.record);
55004 onRowUpdated : function(v, index, r){
55005 if(this.selection && this.selection.record == r){
55006 v.onCellSelect(index, this.selection.cell[1]);
55011 onViewChange : function(){
55012 this.clearSelections(true);
55016 * Returns the currently selected cell,.
55017 * @return {Array} The selected cell (row, column) or null if none selected.
55019 getSelectedCell : function(){
55020 return this.selection ? this.selection.cell : null;
55024 * Clears all selections.
55025 * @param {Boolean} true to prevent the gridview from being notified about the change.
55027 clearSelections : function(preventNotify){
55028 var s = this.selection;
55030 if(preventNotify !== true){
55031 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55033 this.selection = null;
55034 this.fireEvent("selectionchange", this, null);
55039 * Returns true if there is a selection.
55040 * @return {Boolean}
55042 hasSelection : function(){
55043 return this.selection ? true : false;
55047 handleMouseDown : function(e, t){
55048 var v = this.grid.getView();
55049 if(this.isLocked()){
55052 var row = v.findRowIndex(t);
55053 var cell = v.findCellIndex(t);
55054 if(row !== false && cell !== false){
55055 this.select(row, cell);
55061 * @param {Number} rowIndex
55062 * @param {Number} collIndex
55064 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55065 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55066 this.clearSelections();
55067 r = r || this.grid.dataSource.getAt(rowIndex);
55070 cell : [rowIndex, colIndex]
55072 if(!preventViewNotify){
55073 var v = this.grid.getView();
55074 v.onCellSelect(rowIndex, colIndex);
55075 if(preventFocus !== true){
55076 v.focusCell(rowIndex, colIndex);
55079 this.fireEvent("cellselect", this, rowIndex, colIndex);
55080 this.fireEvent("selectionchange", this, this.selection);
55085 isSelectable : function(rowIndex, colIndex, cm){
55086 return !cm.isHidden(colIndex);
55090 handleKeyDown : function(e){
55091 //Roo.log('Cell Sel Model handleKeyDown');
55092 if(!e.isNavKeyPress()){
55095 var g = this.grid, s = this.selection;
55098 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55100 this.select(cell[0], cell[1]);
55105 var walk = function(row, col, step){
55106 return g.walkCells(row, col, step, sm.isSelectable, sm);
55108 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55115 // handled by onEditorKey
55116 if (g.isEditor && g.editing) {
55120 newCell = walk(r, c-1, -1);
55122 newCell = walk(r, c+1, 1);
55127 newCell = walk(r+1, c, 1);
55131 newCell = walk(r-1, c, -1);
55135 newCell = walk(r, c+1, 1);
55139 newCell = walk(r, c-1, -1);
55144 if(g.isEditor && !g.editing){
55145 g.startEditing(r, c);
55154 this.select(newCell[0], newCell[1]);
55160 acceptsNav : function(row, col, cm){
55161 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55165 * @param {Number} field (not used) - as it's normally used as a listener
55166 * @param {Number} e - event - fake it by using
55168 * var e = Roo.EventObjectImpl.prototype;
55169 * e.keyCode = e.TAB
55173 onEditorKey : function(field, e){
55175 var k = e.getKey(),
55178 ed = g.activeEditor,
55180 ///Roo.log('onEditorKey' + k);
55183 if (this.enter_is_tab && k == e.ENTER) {
55189 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55191 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55197 } else if(k == e.ENTER && !e.ctrlKey){
55200 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55202 } else if(k == e.ESC){
55207 var ecall = { cell : newCell, forward : forward };
55208 this.fireEvent('beforeeditnext', ecall );
55209 newCell = ecall.cell;
55210 forward = ecall.forward;
55214 //Roo.log('next cell after edit');
55215 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55216 } else if (forward) {
55217 // tabbed past last
55218 this.fireEvent.defer(100, this, ['tabend',this]);
55223 * Ext JS Library 1.1.1
55224 * Copyright(c) 2006-2007, Ext JS, LLC.
55226 * Originally Released Under LGPL - original licence link has changed is not relivant.
55229 * <script type="text/javascript">
55233 * @class Roo.grid.EditorGrid
55234 * @extends Roo.grid.Grid
55235 * Class for creating and editable grid.
55236 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55237 * The container MUST have some type of size defined for the grid to fill. The container will be
55238 * automatically set to position relative if it isn't already.
55239 * @param {Object} dataSource The data model to bind to
55240 * @param {Object} colModel The column model with info about this grid's columns
55242 Roo.grid.EditorGrid = function(container, config){
55243 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55244 this.getGridEl().addClass("xedit-grid");
55246 if(!this.selModel){
55247 this.selModel = new Roo.grid.CellSelectionModel();
55250 this.activeEditor = null;
55254 * @event beforeedit
55255 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55256 * <ul style="padding:5px;padding-left:16px;">
55257 * <li>grid - This grid</li>
55258 * <li>record - The record being edited</li>
55259 * <li>field - The field name being edited</li>
55260 * <li>value - The value for the field being edited.</li>
55261 * <li>row - The grid row index</li>
55262 * <li>column - The grid column index</li>
55263 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55265 * @param {Object} e An edit event (see above for description)
55267 "beforeedit" : true,
55270 * Fires after a cell is edited. <br />
55271 * <ul style="padding:5px;padding-left:16px;">
55272 * <li>grid - This grid</li>
55273 * <li>record - The record being edited</li>
55274 * <li>field - The field name being edited</li>
55275 * <li>value - The value being set</li>
55276 * <li>originalValue - The original value for the field, before the edit.</li>
55277 * <li>row - The grid row index</li>
55278 * <li>column - The grid column index</li>
55280 * @param {Object} e An edit event (see above for description)
55282 "afteredit" : true,
55284 * @event validateedit
55285 * Fires after a cell is edited, but before the value is set in the record.
55286 * You can use this to modify the value being set in the field, Return false
55287 * to cancel the change. The edit event object has the following properties <br />
55288 * <ul style="padding:5px;padding-left:16px;">
55289 * <li>editor - This editor</li>
55290 * <li>grid - This grid</li>
55291 * <li>record - The record being edited</li>
55292 * <li>field - The field name being edited</li>
55293 * <li>value - The value being set</li>
55294 * <li>originalValue - The original value for the field, before the edit.</li>
55295 * <li>row - The grid row index</li>
55296 * <li>column - The grid column index</li>
55297 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55299 * @param {Object} e An edit event (see above for description)
55301 "validateedit" : true
55303 this.on("bodyscroll", this.stopEditing, this);
55304 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
55307 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
55309 * @cfg {Number} clicksToEdit
55310 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
55317 trackMouseOver: false, // causes very odd FF errors
55319 onCellDblClick : function(g, row, col){
55320 this.startEditing(row, col);
55323 onEditComplete : function(ed, value, startValue){
55324 this.editing = false;
55325 this.activeEditor = null;
55326 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
55328 var field = this.colModel.getDataIndex(ed.col);
55333 originalValue: startValue,
55340 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
55343 if(String(value) !== String(startValue)){
55345 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
55346 r.set(field, e.value);
55347 // if we are dealing with a combo box..
55348 // then we also set the 'name' colum to be the displayField
55349 if (ed.field.displayField && ed.field.name) {
55350 r.set(ed.field.name, ed.field.el.dom.value);
55353 delete e.cancel; //?? why!!!
55354 this.fireEvent("afteredit", e);
55357 this.fireEvent("afteredit", e); // always fire it!
55359 this.view.focusCell(ed.row, ed.col);
55363 * Starts editing the specified for the specified row/column
55364 * @param {Number} rowIndex
55365 * @param {Number} colIndex
55367 startEditing : function(row, col){
55368 this.stopEditing();
55369 if(this.colModel.isCellEditable(col, row)){
55370 this.view.ensureVisible(row, col, true);
55372 var r = this.dataSource.getAt(row);
55373 var field = this.colModel.getDataIndex(col);
55374 var cell = Roo.get(this.view.getCell(row,col));
55379 value: r.data[field],
55384 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
55385 this.editing = true;
55386 var ed = this.colModel.getCellEditor(col, row);
55392 ed.render(ed.parentEl || document.body);
55398 (function(){ // complex but required for focus issues in safari, ie and opera
55402 ed.on("complete", this.onEditComplete, this, {single: true});
55403 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
55404 this.activeEditor = ed;
55405 var v = r.data[field];
55406 ed.startEdit(this.view.getCell(row, col), v);
55407 // combo's with 'displayField and name set
55408 if (ed.field.displayField && ed.field.name) {
55409 ed.field.el.dom.value = r.data[ed.field.name];
55413 }).defer(50, this);
55419 * Stops any active editing
55421 stopEditing : function(){
55422 if(this.activeEditor){
55423 this.activeEditor.completeEdit();
55425 this.activeEditor = null;
55429 * Called to get grid's drag proxy text, by default returns this.ddText.
55432 getDragDropText : function(){
55433 var count = this.selModel.getSelectedCell() ? 1 : 0;
55434 return String.format(this.ddText, count, count == 1 ? '' : 's');
55439 * Ext JS Library 1.1.1
55440 * Copyright(c) 2006-2007, Ext JS, LLC.
55442 * Originally Released Under LGPL - original licence link has changed is not relivant.
55445 * <script type="text/javascript">
55448 // private - not really -- you end up using it !
55449 // This is a support class used internally by the Grid components
55452 * @class Roo.grid.GridEditor
55453 * @extends Roo.Editor
55454 * Class for creating and editable grid elements.
55455 * @param {Object} config any settings (must include field)
55457 Roo.grid.GridEditor = function(field, config){
55458 if (!config && field.field) {
55460 field = Roo.factory(config.field, Roo.form);
55462 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
55463 field.monitorTab = false;
55466 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
55469 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
55472 alignment: "tl-tl",
55475 cls: "x-small-editor x-grid-editor",
55480 * Ext JS Library 1.1.1
55481 * Copyright(c) 2006-2007, Ext JS, LLC.
55483 * Originally Released Under LGPL - original licence link has changed is not relivant.
55486 * <script type="text/javascript">
55491 Roo.grid.PropertyRecord = Roo.data.Record.create([
55492 {name:'name',type:'string'}, 'value'
55496 Roo.grid.PropertyStore = function(grid, source){
55498 this.store = new Roo.data.Store({
55499 recordType : Roo.grid.PropertyRecord
55501 this.store.on('update', this.onUpdate, this);
55503 this.setSource(source);
55505 Roo.grid.PropertyStore.superclass.constructor.call(this);
55510 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
55511 setSource : function(o){
55513 this.store.removeAll();
55516 if(this.isEditableValue(o[k])){
55517 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
55520 this.store.loadRecords({records: data}, {}, true);
55523 onUpdate : function(ds, record, type){
55524 if(type == Roo.data.Record.EDIT){
55525 var v = record.data['value'];
55526 var oldValue = record.modified['value'];
55527 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
55528 this.source[record.id] = v;
55530 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
55537 getProperty : function(row){
55538 return this.store.getAt(row);
55541 isEditableValue: function(val){
55542 if(val && val instanceof Date){
55544 }else if(typeof val == 'object' || typeof val == 'function'){
55550 setValue : function(prop, value){
55551 this.source[prop] = value;
55552 this.store.getById(prop).set('value', value);
55555 getSource : function(){
55556 return this.source;
55560 Roo.grid.PropertyColumnModel = function(grid, store){
55563 g.PropertyColumnModel.superclass.constructor.call(this, [
55564 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
55565 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
55567 this.store = store;
55568 this.bselect = Roo.DomHelper.append(document.body, {
55569 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
55570 {tag: 'option', value: 'true', html: 'true'},
55571 {tag: 'option', value: 'false', html: 'false'}
55574 Roo.id(this.bselect);
55577 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
55578 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
55579 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
55580 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
55581 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
55583 this.renderCellDelegate = this.renderCell.createDelegate(this);
55584 this.renderPropDelegate = this.renderProp.createDelegate(this);
55587 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
55591 valueText : 'Value',
55593 dateFormat : 'm/j/Y',
55596 renderDate : function(dateVal){
55597 return dateVal.dateFormat(this.dateFormat);
55600 renderBool : function(bVal){
55601 return bVal ? 'true' : 'false';
55604 isCellEditable : function(colIndex, rowIndex){
55605 return colIndex == 1;
55608 getRenderer : function(col){
55610 this.renderCellDelegate : this.renderPropDelegate;
55613 renderProp : function(v){
55614 return this.getPropertyName(v);
55617 renderCell : function(val){
55619 if(val instanceof Date){
55620 rv = this.renderDate(val);
55621 }else if(typeof val == 'boolean'){
55622 rv = this.renderBool(val);
55624 return Roo.util.Format.htmlEncode(rv);
55627 getPropertyName : function(name){
55628 var pn = this.grid.propertyNames;
55629 return pn && pn[name] ? pn[name] : name;
55632 getCellEditor : function(colIndex, rowIndex){
55633 var p = this.store.getProperty(rowIndex);
55634 var n = p.data['name'], val = p.data['value'];
55636 if(typeof(this.grid.customEditors[n]) == 'string'){
55637 return this.editors[this.grid.customEditors[n]];
55639 if(typeof(this.grid.customEditors[n]) != 'undefined'){
55640 return this.grid.customEditors[n];
55642 if(val instanceof Date){
55643 return this.editors['date'];
55644 }else if(typeof val == 'number'){
55645 return this.editors['number'];
55646 }else if(typeof val == 'boolean'){
55647 return this.editors['boolean'];
55649 return this.editors['string'];
55655 * @class Roo.grid.PropertyGrid
55656 * @extends Roo.grid.EditorGrid
55657 * This class represents the interface of a component based property grid control.
55658 * <br><br>Usage:<pre><code>
55659 var grid = new Roo.grid.PropertyGrid("my-container-id", {
55667 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55668 * The container MUST have some type of size defined for the grid to fill. The container will be
55669 * automatically set to position relative if it isn't already.
55670 * @param {Object} config A config object that sets properties on this grid.
55672 Roo.grid.PropertyGrid = function(container, config){
55673 config = config || {};
55674 var store = new Roo.grid.PropertyStore(this);
55675 this.store = store;
55676 var cm = new Roo.grid.PropertyColumnModel(this, store);
55677 store.store.sort('name', 'ASC');
55678 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
55681 enableColLock:false,
55682 enableColumnMove:false,
55684 trackMouseOver: false,
55687 this.getGridEl().addClass('x-props-grid');
55688 this.lastEditRow = null;
55689 this.on('columnresize', this.onColumnResize, this);
55692 * @event beforepropertychange
55693 * Fires before a property changes (return false to stop?)
55694 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55695 * @param {String} id Record Id
55696 * @param {String} newval New Value
55697 * @param {String} oldval Old Value
55699 "beforepropertychange": true,
55701 * @event propertychange
55702 * Fires after a property changes
55703 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
55704 * @param {String} id Record Id
55705 * @param {String} newval New Value
55706 * @param {String} oldval Old Value
55708 "propertychange": true
55710 this.customEditors = this.customEditors || {};
55712 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
55715 * @cfg {Object} customEditors map of colnames=> custom editors.
55716 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
55717 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
55718 * false disables editing of the field.
55722 * @cfg {Object} propertyNames map of property Names to their displayed value
55725 render : function(){
55726 Roo.grid.PropertyGrid.superclass.render.call(this);
55727 this.autoSize.defer(100, this);
55730 autoSize : function(){
55731 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
55733 this.view.fitColumns();
55737 onColumnResize : function(){
55738 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
55742 * Sets the data for the Grid
55743 * accepts a Key => Value object of all the elements avaiable.
55744 * @param {Object} data to appear in grid.
55746 setSource : function(source){
55747 this.store.setSource(source);
55751 * Gets all the data from the grid.
55752 * @return {Object} data data stored in grid
55754 getSource : function(){
55755 return this.store.getSource();
55764 * @class Roo.grid.Calendar
55765 * @extends Roo.util.Grid
55766 * This class extends the Grid to provide a calendar widget
55767 * <br><br>Usage:<pre><code>
55768 var grid = new Roo.grid.Calendar("my-container-id", {
55771 selModel: mySelectionModel,
55772 autoSizeColumns: true,
55773 monitorWindowResize: false,
55774 trackMouseOver: true
55775 eventstore : real data store..
55781 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55782 * The container MUST have some type of size defined for the grid to fill. The container will be
55783 * automatically set to position relative if it isn't already.
55784 * @param {Object} config A config object that sets properties on this grid.
55786 Roo.grid.Calendar = function(container, config){
55787 // initialize the container
55788 this.container = Roo.get(container);
55789 this.container.update("");
55790 this.container.setStyle("overflow", "hidden");
55791 this.container.addClass('x-grid-container');
55793 this.id = this.container.id;
55795 Roo.apply(this, config);
55796 // check and correct shorthanded configs
55800 for (var r = 0;r < 6;r++) {
55803 for (var c =0;c < 7;c++) {
55807 if (this.eventStore) {
55808 this.eventStore= Roo.factory(this.eventStore, Roo.data);
55809 this.eventStore.on('load',this.onLoad, this);
55810 this.eventStore.on('beforeload',this.clearEvents, this);
55814 this.dataSource = new Roo.data.Store({
55815 proxy: new Roo.data.MemoryProxy(rows),
55816 reader: new Roo.data.ArrayReader({}, [
55817 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
55820 this.dataSource.load();
55821 this.ds = this.dataSource;
55822 this.ds.xmodule = this.xmodule || false;
55825 var cellRender = function(v,x,r)
55827 return String.format(
55828 '<div class="fc-day fc-widget-content"><div>' +
55829 '<div class="fc-event-container"></div>' +
55830 '<div class="fc-day-number">{0}</div>'+
55832 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
55833 '</div></div>', v);
55838 this.colModel = new Roo.grid.ColumnModel( [
55840 xtype: 'ColumnModel',
55842 dataIndex : 'weekday0',
55844 renderer : cellRender
55847 xtype: 'ColumnModel',
55849 dataIndex : 'weekday1',
55851 renderer : cellRender
55854 xtype: 'ColumnModel',
55856 dataIndex : 'weekday2',
55857 header : 'Tuesday',
55858 renderer : cellRender
55861 xtype: 'ColumnModel',
55863 dataIndex : 'weekday3',
55864 header : 'Wednesday',
55865 renderer : cellRender
55868 xtype: 'ColumnModel',
55870 dataIndex : 'weekday4',
55871 header : 'Thursday',
55872 renderer : cellRender
55875 xtype: 'ColumnModel',
55877 dataIndex : 'weekday5',
55879 renderer : cellRender
55882 xtype: 'ColumnModel',
55884 dataIndex : 'weekday6',
55885 header : 'Saturday',
55886 renderer : cellRender
55889 this.cm = this.colModel;
55890 this.cm.xmodule = this.xmodule || false;
55894 //this.selModel = new Roo.grid.CellSelectionModel();
55895 //this.sm = this.selModel;
55896 //this.selModel.init(this);
55900 this.container.setWidth(this.width);
55904 this.container.setHeight(this.height);
55911 * The raw click event for the entire grid.
55912 * @param {Roo.EventObject} e
55917 * The raw dblclick event for the entire grid.
55918 * @param {Roo.EventObject} e
55922 * @event contextmenu
55923 * The raw contextmenu event for the entire grid.
55924 * @param {Roo.EventObject} e
55926 "contextmenu" : true,
55929 * The raw mousedown event for the entire grid.
55930 * @param {Roo.EventObject} e
55932 "mousedown" : true,
55935 * The raw mouseup event for the entire grid.
55936 * @param {Roo.EventObject} e
55941 * The raw mouseover event for the entire grid.
55942 * @param {Roo.EventObject} e
55944 "mouseover" : true,
55947 * The raw mouseout event for the entire grid.
55948 * @param {Roo.EventObject} e
55953 * The raw keypress event for the entire grid.
55954 * @param {Roo.EventObject} e
55959 * The raw keydown event for the entire grid.
55960 * @param {Roo.EventObject} e
55968 * Fires when a cell is clicked
55969 * @param {Grid} this
55970 * @param {Number} rowIndex
55971 * @param {Number} columnIndex
55972 * @param {Roo.EventObject} e
55974 "cellclick" : true,
55976 * @event celldblclick
55977 * Fires when a cell is double clicked
55978 * @param {Grid} this
55979 * @param {Number} rowIndex
55980 * @param {Number} columnIndex
55981 * @param {Roo.EventObject} e
55983 "celldblclick" : true,
55986 * Fires when a row is clicked
55987 * @param {Grid} this
55988 * @param {Number} rowIndex
55989 * @param {Roo.EventObject} e
55993 * @event rowdblclick
55994 * Fires when a row is double clicked
55995 * @param {Grid} this
55996 * @param {Number} rowIndex
55997 * @param {Roo.EventObject} e
55999 "rowdblclick" : true,
56001 * @event headerclick
56002 * Fires when a header is clicked
56003 * @param {Grid} this
56004 * @param {Number} columnIndex
56005 * @param {Roo.EventObject} e
56007 "headerclick" : true,
56009 * @event headerdblclick
56010 * Fires when a header cell is double clicked
56011 * @param {Grid} this
56012 * @param {Number} columnIndex
56013 * @param {Roo.EventObject} e
56015 "headerdblclick" : true,
56017 * @event rowcontextmenu
56018 * Fires when a row is right clicked
56019 * @param {Grid} this
56020 * @param {Number} rowIndex
56021 * @param {Roo.EventObject} e
56023 "rowcontextmenu" : true,
56025 * @event cellcontextmenu
56026 * Fires when a cell is right clicked
56027 * @param {Grid} this
56028 * @param {Number} rowIndex
56029 * @param {Number} cellIndex
56030 * @param {Roo.EventObject} e
56032 "cellcontextmenu" : true,
56034 * @event headercontextmenu
56035 * Fires when a header is right clicked
56036 * @param {Grid} this
56037 * @param {Number} columnIndex
56038 * @param {Roo.EventObject} e
56040 "headercontextmenu" : true,
56042 * @event bodyscroll
56043 * Fires when the body element is scrolled
56044 * @param {Number} scrollLeft
56045 * @param {Number} scrollTop
56047 "bodyscroll" : true,
56049 * @event columnresize
56050 * Fires when the user resizes a column
56051 * @param {Number} columnIndex
56052 * @param {Number} newSize
56054 "columnresize" : true,
56056 * @event columnmove
56057 * Fires when the user moves a column
56058 * @param {Number} oldIndex
56059 * @param {Number} newIndex
56061 "columnmove" : true,
56064 * Fires when row(s) start being dragged
56065 * @param {Grid} this
56066 * @param {Roo.GridDD} dd The drag drop object
56067 * @param {event} e The raw browser event
56069 "startdrag" : true,
56072 * Fires when a drag operation is complete
56073 * @param {Grid} this
56074 * @param {Roo.GridDD} dd The drag drop object
56075 * @param {event} e The raw browser event
56080 * Fires when dragged row(s) are dropped on a valid DD target
56081 * @param {Grid} this
56082 * @param {Roo.GridDD} dd The drag drop object
56083 * @param {String} targetId The target drag drop object
56084 * @param {event} e The raw browser event
56089 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56090 * @param {Grid} this
56091 * @param {Roo.GridDD} dd The drag drop object
56092 * @param {String} targetId The target drag drop object
56093 * @param {event} e The raw browser event
56098 * Fires when the dragged row(s) first cross another DD target while being dragged
56099 * @param {Grid} this
56100 * @param {Roo.GridDD} dd The drag drop object
56101 * @param {String} targetId The target drag drop object
56102 * @param {event} e The raw browser event
56104 "dragenter" : true,
56107 * Fires when the dragged row(s) leave another DD target while being dragged
56108 * @param {Grid} this
56109 * @param {Roo.GridDD} dd The drag drop object
56110 * @param {String} targetId The target drag drop object
56111 * @param {event} e The raw browser event
56116 * Fires when a row is rendered, so you can change add a style to it.
56117 * @param {GridView} gridview The grid view
56118 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56124 * Fires when the grid is rendered
56125 * @param {Grid} grid
56130 * Fires when a date is selected
56131 * @param {DatePicker} this
56132 * @param {Date} date The selected date
56136 * @event monthchange
56137 * Fires when the displayed month changes
56138 * @param {DatePicker} this
56139 * @param {Date} date The selected month
56141 'monthchange': true,
56143 * @event evententer
56144 * Fires when mouse over an event
56145 * @param {Calendar} this
56146 * @param {event} Event
56148 'evententer': true,
56150 * @event eventleave
56151 * Fires when the mouse leaves an
56152 * @param {Calendar} this
56155 'eventleave': true,
56157 * @event eventclick
56158 * Fires when the mouse click an
56159 * @param {Calendar} this
56162 'eventclick': true,
56164 * @event eventrender
56165 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
56166 * @param {Calendar} this
56167 * @param {data} data to be modified
56169 'eventrender': true
56173 Roo.grid.Grid.superclass.constructor.call(this);
56174 this.on('render', function() {
56175 this.view.el.addClass('x-grid-cal');
56177 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
56181 if (!Roo.grid.Calendar.style) {
56182 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
56185 '.x-grid-cal .x-grid-col' : {
56186 height: 'auto !important',
56187 'vertical-align': 'top'
56189 '.x-grid-cal .fc-event-hori' : {
56200 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
56202 * @cfg {Store} eventStore The store that loads events.
56207 activeDate : false,
56210 monitorWindowResize : false,
56213 resizeColumns : function() {
56214 var col = (this.view.el.getWidth() / 7) - 3;
56215 // loop through cols, and setWidth
56216 for(var i =0 ; i < 7 ; i++){
56217 this.cm.setColumnWidth(i, col);
56220 setDate :function(date) {
56222 Roo.log('setDate?');
56224 this.resizeColumns();
56225 var vd = this.activeDate;
56226 this.activeDate = date;
56227 // if(vd && this.el){
56228 // var t = date.getTime();
56229 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
56230 // Roo.log('using add remove');
56232 // this.fireEvent('monthchange', this, date);
56234 // this.cells.removeClass("fc-state-highlight");
56235 // this.cells.each(function(c){
56236 // if(c.dateValue == t){
56237 // c.addClass("fc-state-highlight");
56238 // setTimeout(function(){
56239 // try{c.dom.firstChild.focus();}catch(e){}
56249 var days = date.getDaysInMonth();
56251 var firstOfMonth = date.getFirstDateOfMonth();
56252 var startingPos = firstOfMonth.getDay()-this.startDay;
56254 if(startingPos < this.startDay){
56258 var pm = date.add(Date.MONTH, -1);
56259 var prevStart = pm.getDaysInMonth()-startingPos;
56263 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
56265 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
56266 //this.cells.addClassOnOver('fc-state-hover');
56268 var cells = this.cells.elements;
56269 var textEls = this.textNodes;
56271 //Roo.each(cells, function(cell){
56272 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
56275 days += startingPos;
56277 // convert everything to numbers so it's fast
56278 var day = 86400000;
56279 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
56282 //Roo.log(prevStart);
56284 var today = new Date().clearTime().getTime();
56285 var sel = date.clearTime().getTime();
56286 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
56287 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
56288 var ddMatch = this.disabledDatesRE;
56289 var ddText = this.disabledDatesText;
56290 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
56291 var ddaysText = this.disabledDaysText;
56292 var format = this.format;
56294 var setCellClass = function(cal, cell){
56296 //Roo.log('set Cell Class');
56298 var t = d.getTime();
56303 cell.dateValue = t;
56305 cell.className += " fc-today";
56306 cell.className += " fc-state-highlight";
56307 cell.title = cal.todayText;
56310 // disable highlight in other month..
56311 cell.className += " fc-state-highlight";
56316 //cell.className = " fc-state-disabled";
56317 cell.title = cal.minText;
56321 //cell.className = " fc-state-disabled";
56322 cell.title = cal.maxText;
56326 if(ddays.indexOf(d.getDay()) != -1){
56327 // cell.title = ddaysText;
56328 // cell.className = " fc-state-disabled";
56331 if(ddMatch && format){
56332 var fvalue = d.dateFormat(format);
56333 if(ddMatch.test(fvalue)){
56334 cell.title = ddText.replace("%0", fvalue);
56335 cell.className = " fc-state-disabled";
56339 if (!cell.initialClassName) {
56340 cell.initialClassName = cell.dom.className;
56343 cell.dom.className = cell.initialClassName + ' ' + cell.className;
56348 for(; i < startingPos; i++) {
56349 cells[i].dayName = (++prevStart);
56350 Roo.log(textEls[i]);
56351 d.setDate(d.getDate()+1);
56353 //cells[i].className = "fc-past fc-other-month";
56354 setCellClass(this, cells[i]);
56359 for(; i < days; i++){
56360 intDay = i - startingPos + 1;
56361 cells[i].dayName = (intDay);
56362 d.setDate(d.getDate()+1);
56364 cells[i].className = ''; // "x-date-active";
56365 setCellClass(this, cells[i]);
56369 for(; i < 42; i++) {
56370 //textEls[i].innerHTML = (++extraDays);
56372 d.setDate(d.getDate()+1);
56373 cells[i].dayName = (++extraDays);
56374 cells[i].className = "fc-future fc-other-month";
56375 setCellClass(this, cells[i]);
56378 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
56380 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
56382 // this will cause all the cells to mis
56385 for (var r = 0;r < 6;r++) {
56386 for (var c =0;c < 7;c++) {
56387 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
56391 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
56392 for(i=0;i<cells.length;i++) {
56394 this.cells.elements[i].dayName = cells[i].dayName ;
56395 this.cells.elements[i].className = cells[i].className;
56396 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
56397 this.cells.elements[i].title = cells[i].title ;
56398 this.cells.elements[i].dateValue = cells[i].dateValue ;
56404 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
56405 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
56407 ////if(totalRows != 6){
56408 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
56409 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
56412 this.fireEvent('monthchange', this, date);
56417 * Returns the grid's SelectionModel.
56418 * @return {SelectionModel}
56420 getSelectionModel : function(){
56421 if(!this.selModel){
56422 this.selModel = new Roo.grid.CellSelectionModel();
56424 return this.selModel;
56428 this.eventStore.load()
56434 findCell : function(dt) {
56435 dt = dt.clearTime().getTime();
56437 this.cells.each(function(c){
56438 //Roo.log("check " +c.dateValue + '?=' + dt);
56439 if(c.dateValue == dt){
56449 findCells : function(rec) {
56450 var s = rec.data.start_dt.clone().clearTime().getTime();
56452 var e= rec.data.end_dt.clone().clearTime().getTime();
56455 this.cells.each(function(c){
56456 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
56458 if(c.dateValue > e){
56461 if(c.dateValue < s){
56470 findBestRow: function(cells)
56474 for (var i =0 ; i < cells.length;i++) {
56475 ret = Math.max(cells[i].rows || 0,ret);
56482 addItem : function(rec)
56484 // look for vertical location slot in
56485 var cells = this.findCells(rec);
56487 rec.row = this.findBestRow(cells);
56489 // work out the location.
56493 for(var i =0; i < cells.length; i++) {
56501 if (crow.start.getY() == cells[i].getY()) {
56503 crow.end = cells[i];
56519 for (var i = 0; i < cells.length;i++) {
56520 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
56527 clearEvents: function() {
56529 if (!this.eventStore.getCount()) {
56532 // reset number of rows in cells.
56533 Roo.each(this.cells.elements, function(c){
56537 this.eventStore.each(function(e) {
56538 this.clearEvent(e);
56543 clearEvent : function(ev)
56546 Roo.each(ev.els, function(el) {
56547 el.un('mouseenter' ,this.onEventEnter, this);
56548 el.un('mouseleave' ,this.onEventLeave, this);
56556 renderEvent : function(ev,ctr) {
56558 ctr = this.view.el.select('.fc-event-container',true).first();
56562 this.clearEvent(ev);
56568 var cells = ev.cells;
56569 var rows = ev.rows;
56570 this.fireEvent('eventrender', this, ev);
56572 for(var i =0; i < rows.length; i++) {
56576 cls += ' fc-event-start';
56578 if ((i+1) == rows.length) {
56579 cls += ' fc-event-end';
56582 //Roo.log(ev.data);
56583 // how many rows should it span..
56584 var cg = this.eventTmpl.append(ctr,Roo.apply({
56587 }, ev.data) , true);
56590 cg.on('mouseenter' ,this.onEventEnter, this, ev);
56591 cg.on('mouseleave' ,this.onEventLeave, this, ev);
56592 cg.on('click', this.onEventClick, this, ev);
56596 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
56597 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
56600 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
56601 cg.setWidth(ebox.right - sbox.x -2);
56605 renderEvents: function()
56607 // first make sure there is enough space..
56609 if (!this.eventTmpl) {
56610 this.eventTmpl = new Roo.Template(
56611 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
56612 '<div class="fc-event-inner">' +
56613 '<span class="fc-event-time">{time}</span>' +
56614 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
56616 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
56624 this.cells.each(function(c) {
56625 //Roo.log(c.select('.fc-day-content div',true).first());
56626 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
56629 var ctr = this.view.el.select('.fc-event-container',true).first();
56632 this.eventStore.each(function(ev){
56634 this.renderEvent(ev);
56638 this.view.layout();
56642 onEventEnter: function (e, el,event,d) {
56643 this.fireEvent('evententer', this, el, event);
56646 onEventLeave: function (e, el,event,d) {
56647 this.fireEvent('eventleave', this, el, event);
56650 onEventClick: function (e, el,event,d) {
56651 this.fireEvent('eventclick', this, el, event);
56654 onMonthChange: function () {
56658 onLoad: function () {
56660 //Roo.log('calendar onload');
56662 if(this.eventStore.getCount() > 0){
56666 this.eventStore.each(function(d){
56671 if (typeof(add.end_dt) == 'undefined') {
56672 Roo.log("Missing End time in calendar data: ");
56676 if (typeof(add.start_dt) == 'undefined') {
56677 Roo.log("Missing Start time in calendar data: ");
56681 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
56682 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
56683 add.id = add.id || d.id;
56684 add.title = add.title || '??';
56692 this.renderEvents();
56702 render : function ()
56706 if (!this.view.el.hasClass('course-timesheet')) {
56707 this.view.el.addClass('course-timesheet');
56709 if (this.tsStyle) {
56714 Roo.log(_this.grid.view.el.getWidth());
56717 this.tsStyle = Roo.util.CSS.createStyleSheet({
56718 '.course-timesheet .x-grid-row' : {
56721 '.x-grid-row td' : {
56722 'vertical-align' : 0
56724 '.course-edit-link' : {
56726 'text-overflow' : 'ellipsis',
56727 'overflow' : 'hidden',
56728 'white-space' : 'nowrap',
56729 'cursor' : 'pointer'
56734 '.de-act-sup-link' : {
56735 'color' : 'purple',
56736 'text-decoration' : 'line-through'
56740 'text-decoration' : 'line-through'
56742 '.course-timesheet .course-highlight' : {
56743 'border-top-style': 'dashed !important',
56744 'border-bottom-bottom': 'dashed !important'
56746 '.course-timesheet .course-item' : {
56747 'font-family' : 'tahoma, arial, helvetica',
56748 'font-size' : '11px',
56749 'overflow' : 'hidden',
56750 'padding-left' : '10px',
56751 'padding-right' : '10px',
56752 'padding-top' : '10px'
56760 monitorWindowResize : false,
56761 cellrenderer : function(v,x,r)
56766 xtype: 'CellSelectionModel',
56773 beforeload : function (_self, options)
56775 options.params = options.params || {};
56776 options.params._month = _this.monthField.getValue();
56777 options.params.limit = 9999;
56778 options.params['sort'] = 'when_dt';
56779 options.params['dir'] = 'ASC';
56780 this.proxy.loadResponse = this.loadResponse;
56782 //this.addColumns();
56784 load : function (_self, records, options)
56786 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
56787 // if you click on the translation.. you can edit it...
56788 var el = Roo.get(this);
56789 var id = el.dom.getAttribute('data-id');
56790 var d = el.dom.getAttribute('data-date');
56791 var t = el.dom.getAttribute('data-time');
56792 //var id = this.child('span').dom.textContent;
56795 Pman.Dialog.CourseCalendar.show({
56799 productitem_active : id ? 1 : 0
56801 _this.grid.ds.load({});
56806 _this.panel.fireEvent('resize', [ '', '' ]);
56809 loadResponse : function(o, success, response){
56810 // this is overridden on before load..
56812 Roo.log("our code?");
56813 //Roo.log(success);
56814 //Roo.log(response)
56815 delete this.activeRequest;
56817 this.fireEvent("loadexception", this, o, response);
56818 o.request.callback.call(o.request.scope, null, o.request.arg, false);
56823 result = o.reader.read(response);
56825 Roo.log("load exception?");
56826 this.fireEvent("loadexception", this, o, response, e);
56827 o.request.callback.call(o.request.scope, null, o.request.arg, false);
56830 Roo.log("ready...");
56831 // loop through result.records;
56832 // and set this.tdate[date] = [] << array of records..
56834 Roo.each(result.records, function(r){
56836 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
56837 _this.tdata[r.data.when_dt.format('j')] = [];
56839 _this.tdata[r.data.when_dt.format('j')].push(r.data);
56842 //Roo.log(_this.tdata);
56844 result.records = [];
56845 result.totalRecords = 6;
56847 // let's generate some duumy records for the rows.
56848 //var st = _this.dateField.getValue();
56850 // work out monday..
56851 //st = st.add(Date.DAY, -1 * st.format('w'));
56853 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
56855 var firstOfMonth = date.getFirstDayOfMonth();
56856 var days = date.getDaysInMonth();
56858 var firstAdded = false;
56859 for (var i = 0; i < result.totalRecords ; i++) {
56860 //var d= st.add(Date.DAY, i);
56863 for(var w = 0 ; w < 7 ; w++){
56864 if(!firstAdded && firstOfMonth != w){
56871 var dd = (d > 0 && d < 10) ? "0"+d : d;
56872 row['weekday'+w] = String.format(
56873 '<span style="font-size: 16px;"><b>{0}</b></span>'+
56874 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
56876 date.format('Y-m-')+dd
56879 if(typeof(_this.tdata[d]) != 'undefined'){
56880 Roo.each(_this.tdata[d], function(r){
56884 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
56885 if(r.parent_id*1>0){
56886 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
56889 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
56890 deactive = 'de-act-link';
56893 row['weekday'+w] += String.format(
56894 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
56896 r.product_id_name, //1
56897 r.when_dt.format('h:ia'), //2
56907 // only do this if something added..
56909 result.records.push(_this.grid.dataSource.reader.newRow(row));
56913 // push it twice. (second one with an hour..
56917 this.fireEvent("load", this, o, o.request.arg);
56918 o.request.callback.call(o.request.scope, result, o.request.arg, true);
56920 sortInfo : {field: 'when_dt', direction : 'ASC' },
56922 xtype: 'HttpProxy',
56925 url : baseURL + '/Roo/Shop_course.php'
56928 xtype: 'JsonReader',
56945 'name': 'parent_id',
56949 'name': 'product_id',
56953 'name': 'productitem_id',
56971 click : function (_self, e)
56973 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
56974 sd.setMonth(sd.getMonth()-1);
56975 _this.monthField.setValue(sd.format('Y-m-d'));
56976 _this.grid.ds.load({});
56982 xtype: 'Separator',
56986 xtype: 'MonthField',
56989 render : function (_self)
56991 _this.monthField = _self;
56992 // _this.monthField.set today
56994 select : function (combo, date)
56996 _this.grid.ds.load({});
56999 value : (function() { return new Date(); })()
57002 xtype: 'Separator',
57008 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57018 click : function (_self, e)
57020 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57021 sd.setMonth(sd.getMonth()+1);
57022 _this.monthField.setValue(sd.format('Y-m-d'));
57023 _this.grid.ds.load({});
57036 * Ext JS Library 1.1.1
57037 * Copyright(c) 2006-2007, Ext JS, LLC.
57039 * Originally Released Under LGPL - original licence link has changed is not relivant.
57042 * <script type="text/javascript">
57046 * @class Roo.LoadMask
57047 * A simple utility class for generically masking elements while loading data. If the element being masked has
57048 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57049 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57050 * element's UpdateManager load indicator and will be destroyed after the initial load.
57052 * Create a new LoadMask
57053 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57054 * @param {Object} config The config object
57056 Roo.LoadMask = function(el, config){
57057 this.el = Roo.get(el);
57058 Roo.apply(this, config);
57060 this.store.on('beforeload', this.onBeforeLoad, this);
57061 this.store.on('load', this.onLoad, this);
57062 this.store.on('loadexception', this.onLoadException, this);
57063 this.removeMask = false;
57065 var um = this.el.getUpdateManager();
57066 um.showLoadIndicator = false; // disable the default indicator
57067 um.on('beforeupdate', this.onBeforeLoad, this);
57068 um.on('update', this.onLoad, this);
57069 um.on('failure', this.onLoad, this);
57070 this.removeMask = true;
57074 Roo.LoadMask.prototype = {
57076 * @cfg {Boolean} removeMask
57077 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
57078 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
57081 * @cfg {String} msg
57082 * The text to display in a centered loading message box (defaults to 'Loading...')
57084 msg : 'Loading...',
57086 * @cfg {String} msgCls
57087 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
57089 msgCls : 'x-mask-loading',
57092 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
57098 * Disables the mask to prevent it from being displayed
57100 disable : function(){
57101 this.disabled = true;
57105 * Enables the mask so that it can be displayed
57107 enable : function(){
57108 this.disabled = false;
57111 onLoadException : function()
57113 Roo.log(arguments);
57115 if (typeof(arguments[3]) != 'undefined') {
57116 Roo.MessageBox.alert("Error loading",arguments[3]);
57120 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
57121 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
57130 this.el.unmask(this.removeMask);
57133 onLoad : function()
57135 this.el.unmask(this.removeMask);
57139 onBeforeLoad : function(){
57140 if(!this.disabled){
57141 this.el.mask(this.msg, this.msgCls);
57146 destroy : function(){
57148 this.store.un('beforeload', this.onBeforeLoad, this);
57149 this.store.un('load', this.onLoad, this);
57150 this.store.un('loadexception', this.onLoadException, this);
57152 var um = this.el.getUpdateManager();
57153 um.un('beforeupdate', this.onBeforeLoad, this);
57154 um.un('update', this.onLoad, this);
57155 um.un('failure', this.onLoad, this);
57160 * Ext JS Library 1.1.1
57161 * Copyright(c) 2006-2007, Ext JS, LLC.
57163 * Originally Released Under LGPL - original licence link has changed is not relivant.
57166 * <script type="text/javascript">
57171 * @class Roo.XTemplate
57172 * @extends Roo.Template
57173 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
57175 var t = new Roo.XTemplate(
57176 '<select name="{name}">',
57177 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
57181 // then append, applying the master template values
57184 * Supported features:
57189 {a_variable} - output encoded.
57190 {a_variable.format:("Y-m-d")} - call a method on the variable
57191 {a_variable:raw} - unencoded output
57192 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
57193 {a_variable:this.method_on_template(...)} - call a method on the template object.
57198 <tpl for="a_variable or condition.."></tpl>
57199 <tpl if="a_variable or condition"></tpl>
57200 <tpl exec="some javascript"></tpl>
57201 <tpl name="named_template"></tpl> (experimental)
57203 <tpl for="."></tpl> - just iterate the property..
57204 <tpl for=".."></tpl> - iterates with the parent (probably the template)
57208 Roo.XTemplate = function()
57210 Roo.XTemplate.superclass.constructor.apply(this, arguments);
57217 Roo.extend(Roo.XTemplate, Roo.Template, {
57220 * The various sub templates
57225 * basic tag replacing syntax
57228 * // you can fake an object call by doing this
57232 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
57235 * compile the template
57237 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
57240 compile: function()
57244 s = ['<tpl>', s, '</tpl>'].join('');
57246 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
57247 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
57248 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
57249 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
57250 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
57255 while(true == !!(m = s.match(re))){
57256 var forMatch = m[0].match(nameRe),
57257 ifMatch = m[0].match(ifRe),
57258 execMatch = m[0].match(execRe),
57259 namedMatch = m[0].match(namedRe),
57264 name = forMatch && forMatch[1] ? forMatch[1] : '';
57267 // if - puts fn into test..
57268 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
57270 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
57275 // exec - calls a function... returns empty if true is returned.
57276 exp = execMatch && execMatch[1] ? execMatch[1] : null;
57278 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
57286 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
57287 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
57288 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
57291 var uid = namedMatch ? namedMatch[1] : id;
57295 id: namedMatch ? namedMatch[1] : id,
57302 s = s.replace(m[0], '');
57304 s = s.replace(m[0], '{xtpl'+ id + '}');
57309 for(var i = tpls.length-1; i >= 0; --i){
57310 this.compileTpl(tpls[i]);
57311 this.tpls[tpls[i].id] = tpls[i];
57313 this.master = tpls[tpls.length-1];
57317 * same as applyTemplate, except it's done to one of the subTemplates
57318 * when using named templates, you can do:
57320 * var str = pl.applySubTemplate('your-name', values);
57323 * @param {Number} id of the template
57324 * @param {Object} values to apply to template
57325 * @param {Object} parent (normaly the instance of this object)
57327 applySubTemplate : function(id, values, parent)
57331 var t = this.tpls[id];
57335 if(t.test && !t.test.call(this, values, parent)){
57339 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
57340 Roo.log(e.toString());
57346 if(t.exec && t.exec.call(this, values, parent)){
57350 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
57351 Roo.log(e.toString());
57356 var vs = t.target ? t.target.call(this, values, parent) : values;
57357 parent = t.target ? values : parent;
57358 if(t.target && vs instanceof Array){
57360 for(var i = 0, len = vs.length; i < len; i++){
57361 buf[buf.length] = t.compiled.call(this, vs[i], parent);
57363 return buf.join('');
57365 return t.compiled.call(this, vs, parent);
57367 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
57368 Roo.log(e.toString());
57369 Roo.log(t.compiled);
57374 compileTpl : function(tpl)
57376 var fm = Roo.util.Format;
57377 var useF = this.disableFormats !== true;
57378 var sep = Roo.isGecko ? "+" : ",";
57379 var undef = function(str) {
57380 Roo.log("Property not found :" + str);
57384 var fn = function(m, name, format, args)
57386 //Roo.log(arguments);
57387 args = args ? args.replace(/\\'/g,"'") : args;
57388 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
57389 if (typeof(format) == 'undefined') {
57390 format= 'htmlEncode';
57392 if (format == 'raw' ) {
57396 if(name.substr(0, 4) == 'xtpl'){
57397 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
57400 // build an array of options to determine if value is undefined..
57402 // basically get 'xxxx.yyyy' then do
57403 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
57404 // (function () { Roo.log("Property not found"); return ''; })() :
57409 Roo.each(name.split('.'), function(st) {
57410 lookfor += (lookfor.length ? '.': '') + st;
57411 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
57414 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
57417 if(format && useF){
57419 args = args ? ',' + args : "";
57421 if(format.substr(0, 5) != "this."){
57422 format = "fm." + format + '(';
57424 format = 'this.call("'+ format.substr(5) + '", ';
57428 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
57432 // called with xxyx.yuu:(test,test)
57434 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
57436 // raw.. - :raw modifier..
57437 return "'"+ sep + udef_st + name + ")"+sep+"'";
57441 // branched to use + in gecko and [].join() in others
57443 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
57444 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
57447 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
57448 body.push(tpl.body.replace(/(\r\n|\n)/g,
57449 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
57450 body.push("'].join('');};};");
57451 body = body.join('');
57454 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
57456 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
57462 applyTemplate : function(values){
57463 return this.master.compiled.call(this, values, {});
57464 //var s = this.subs;
57467 apply : function(){
57468 return this.applyTemplate.apply(this, arguments);
57473 Roo.XTemplate.from = function(el){
57474 el = Roo.getDom(el);
57475 return new Roo.XTemplate(el.value || el.innerHTML);