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 * @param {Boolean} inverse return inverse filter (not matches)
10950 * @return {CompositeElement} this
10952 filter : function(selector, inverse){
10954 inverse = inverse || false;
10955 this.each(function(el){
10956 var match = inverse ? !el.is(selector) : el.is(selector);
10958 els[els.length] = el.dom;
10965 invoke : function(fn, args){
10966 var els = this.elements;
10967 for(var i = 0, len = els.length; i < len; i++) {
10968 Roo.Element.prototype[fn].apply(els[i], args);
10973 * Adds elements to this composite.
10974 * @param {String/Array} els A string CSS selector, an array of elements or an element
10975 * @return {CompositeElement} this
10977 add : function(els){
10978 if(typeof els == "string"){
10979 this.addElements(Roo.Element.selectorFunction(els));
10980 }else if(els.length !== undefined){
10981 this.addElements(els);
10983 this.addElements([els]);
10988 * Calls the passed function passing (el, this, index) for each element in this composite.
10989 * @param {Function} fn The function to call
10990 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10991 * @return {CompositeElement} this
10993 each : function(fn, scope){
10994 var els = this.elements;
10995 for(var i = 0, len = els.length; i < len; i++){
10996 if(fn.call(scope || els[i], els[i], this, i) === false) {
11004 * Returns the Element object at the specified index
11005 * @param {Number} index
11006 * @return {Roo.Element}
11008 item : function(index){
11009 return this.elements[index] || null;
11013 * Returns the first Element
11014 * @return {Roo.Element}
11016 first : function(){
11017 return this.item(0);
11021 * Returns the last Element
11022 * @return {Roo.Element}
11025 return this.item(this.elements.length-1);
11029 * Returns the number of elements in this composite
11032 getCount : function(){
11033 return this.elements.length;
11037 * Returns true if this composite contains the passed element
11040 contains : function(el){
11041 return this.indexOf(el) !== -1;
11045 * Returns true if this composite contains the passed element
11048 indexOf : function(el){
11049 return this.elements.indexOf(Roo.get(el));
11054 * Removes the specified element(s).
11055 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11056 * or an array of any of those.
11057 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11058 * @return {CompositeElement} this
11060 removeElement : function(el, removeDom){
11061 if(el instanceof Array){
11062 for(var i = 0, len = el.length; i < len; i++){
11063 this.removeElement(el[i]);
11067 var index = typeof el == 'number' ? el : this.indexOf(el);
11070 var d = this.elements[index];
11074 d.parentNode.removeChild(d);
11077 this.elements.splice(index, 1);
11083 * Replaces the specified element with the passed element.
11084 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11086 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11087 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11088 * @return {CompositeElement} this
11090 replaceElement : function(el, replacement, domReplace){
11091 var index = typeof el == 'number' ? el : this.indexOf(el);
11094 this.elements[index].replaceWith(replacement);
11096 this.elements.splice(index, 1, Roo.get(replacement))
11103 * Removes all elements.
11105 clear : function(){
11106 this.elements = [];
11110 Roo.CompositeElement.createCall = function(proto, fnName){
11111 if(!proto[fnName]){
11112 proto[fnName] = function(){
11113 return this.invoke(fnName, arguments);
11117 for(var fnName in Roo.Element.prototype){
11118 if(typeof Roo.Element.prototype[fnName] == "function"){
11119 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11125 * Ext JS Library 1.1.1
11126 * Copyright(c) 2006-2007, Ext JS, LLC.
11128 * Originally Released Under LGPL - original licence link has changed is not relivant.
11131 * <script type="text/javascript">
11135 * @class Roo.CompositeElementLite
11136 * @extends Roo.CompositeElement
11137 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11139 var els = Roo.select("#some-el div.some-class");
11140 // or select directly from an existing element
11141 var el = Roo.get('some-el');
11142 el.select('div.some-class');
11144 els.setWidth(100); // all elements become 100 width
11145 els.hide(true); // all elements fade out and hide
11147 els.setWidth(100).hide(true);
11148 </code></pre><br><br>
11149 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11150 * actions will be performed on all the elements in this collection.</b>
11152 Roo.CompositeElementLite = function(els){
11153 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11154 this.el = new Roo.Element.Flyweight();
11156 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11157 addElements : function(els){
11159 if(els instanceof Array){
11160 this.elements = this.elements.concat(els);
11162 var yels = this.elements;
11163 var index = yels.length-1;
11164 for(var i = 0, len = els.length; i < len; i++) {
11165 yels[++index] = els[i];
11171 invoke : function(fn, args){
11172 var els = this.elements;
11174 for(var i = 0, len = els.length; i < len; i++) {
11176 Roo.Element.prototype[fn].apply(el, args);
11181 * Returns a flyweight Element of the dom element object at the specified index
11182 * @param {Number} index
11183 * @return {Roo.Element}
11185 item : function(index){
11186 if(!this.elements[index]){
11189 this.el.dom = this.elements[index];
11193 // fixes scope with flyweight
11194 addListener : function(eventName, handler, scope, opt){
11195 var els = this.elements;
11196 for(var i = 0, len = els.length; i < len; i++) {
11197 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11203 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11204 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11205 * a reference to the dom node, use el.dom.</b>
11206 * @param {Function} fn The function to call
11207 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11208 * @return {CompositeElement} this
11210 each : function(fn, scope){
11211 var els = this.elements;
11213 for(var i = 0, len = els.length; i < len; i++){
11215 if(fn.call(scope || el, el, this, i) === false){
11222 indexOf : function(el){
11223 return this.elements.indexOf(Roo.getDom(el));
11226 replaceElement : function(el, replacement, domReplace){
11227 var index = typeof el == 'number' ? el : this.indexOf(el);
11229 replacement = Roo.getDom(replacement);
11231 var d = this.elements[index];
11232 d.parentNode.insertBefore(replacement, d);
11233 d.parentNode.removeChild(d);
11235 this.elements.splice(index, 1, replacement);
11240 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11244 * Ext JS Library 1.1.1
11245 * Copyright(c) 2006-2007, Ext JS, LLC.
11247 * Originally Released Under LGPL - original licence link has changed is not relivant.
11250 * <script type="text/javascript">
11256 * @class Roo.data.Connection
11257 * @extends Roo.util.Observable
11258 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11259 * either to a configured URL, or to a URL specified at request time.<br><br>
11261 * Requests made by this class are asynchronous, and will return immediately. No data from
11262 * the server will be available to the statement immediately following the {@link #request} call.
11263 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11265 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11266 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11267 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11268 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11269 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11270 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11271 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11272 * standard DOM methods.
11274 * @param {Object} config a configuration object.
11276 Roo.data.Connection = function(config){
11277 Roo.apply(this, config);
11280 * @event beforerequest
11281 * Fires before a network request is made to retrieve a data object.
11282 * @param {Connection} conn This Connection object.
11283 * @param {Object} options The options config object passed to the {@link #request} method.
11285 "beforerequest" : true,
11287 * @event requestcomplete
11288 * Fires if the request was successfully completed.
11289 * @param {Connection} conn This Connection object.
11290 * @param {Object} response The XHR object containing the response data.
11291 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11292 * @param {Object} options The options config object passed to the {@link #request} method.
11294 "requestcomplete" : true,
11296 * @event requestexception
11297 * Fires if an error HTTP status was returned from the server.
11298 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11299 * @param {Connection} conn This Connection object.
11300 * @param {Object} response The XHR object containing the response data.
11301 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11302 * @param {Object} options The options config object passed to the {@link #request} method.
11304 "requestexception" : true
11306 Roo.data.Connection.superclass.constructor.call(this);
11309 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11311 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11314 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11315 * extra parameters to each request made by this object. (defaults to undefined)
11318 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11319 * to each request made by this object. (defaults to undefined)
11322 * @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)
11325 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11329 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11335 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11338 disableCaching: true,
11341 * Sends an HTTP request to a remote server.
11342 * @param {Object} options An object which may contain the following properties:<ul>
11343 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11344 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11345 * request, a url encoded string or a function to call to get either.</li>
11346 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11347 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11348 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11349 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11350 * <li>options {Object} The parameter to the request call.</li>
11351 * <li>success {Boolean} True if the request succeeded.</li>
11352 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11354 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11355 * The callback is passed the following parameters:<ul>
11356 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11357 * <li>options {Object} The parameter to the request call.</li>
11359 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11360 * The callback is passed the following parameters:<ul>
11361 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11362 * <li>options {Object} The parameter to the request call.</li>
11364 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11365 * for the callback function. Defaults to the browser window.</li>
11366 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11367 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11368 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11369 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11370 * params for the post data. Any params will be appended to the URL.</li>
11371 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11373 * @return {Number} transactionId
11375 request : function(o){
11376 if(this.fireEvent("beforerequest", this, o) !== false){
11379 if(typeof p == "function"){
11380 p = p.call(o.scope||window, o);
11382 if(typeof p == "object"){
11383 p = Roo.urlEncode(o.params);
11385 if(this.extraParams){
11386 var extras = Roo.urlEncode(this.extraParams);
11387 p = p ? (p + '&' + extras) : extras;
11390 var url = o.url || this.url;
11391 if(typeof url == 'function'){
11392 url = url.call(o.scope||window, o);
11396 var form = Roo.getDom(o.form);
11397 url = url || form.action;
11399 var enctype = form.getAttribute("enctype");
11400 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11401 return this.doFormUpload(o, p, url);
11403 var f = Roo.lib.Ajax.serializeForm(form);
11404 p = p ? (p + '&' + f) : f;
11407 var hs = o.headers;
11408 if(this.defaultHeaders){
11409 hs = Roo.apply(hs || {}, this.defaultHeaders);
11416 success: this.handleResponse,
11417 failure: this.handleFailure,
11419 argument: {options: o},
11420 timeout : o.timeout || this.timeout
11423 var method = o.method||this.method||(p ? "POST" : "GET");
11425 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11426 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11429 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11433 }else if(this.autoAbort !== false){
11437 if((method == 'GET' && p) || o.xmlData){
11438 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11441 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11442 return this.transId;
11444 Roo.callback(o.callback, o.scope, [o, null, null]);
11450 * Determine whether this object has a request outstanding.
11451 * @param {Number} transactionId (Optional) defaults to the last transaction
11452 * @return {Boolean} True if there is an outstanding request.
11454 isLoading : function(transId){
11456 return Roo.lib.Ajax.isCallInProgress(transId);
11458 return this.transId ? true : false;
11463 * Aborts any outstanding request.
11464 * @param {Number} transactionId (Optional) defaults to the last transaction
11466 abort : function(transId){
11467 if(transId || this.isLoading()){
11468 Roo.lib.Ajax.abort(transId || this.transId);
11473 handleResponse : function(response){
11474 this.transId = false;
11475 var options = response.argument.options;
11476 response.argument = options ? options.argument : null;
11477 this.fireEvent("requestcomplete", this, response, options);
11478 Roo.callback(options.success, options.scope, [response, options]);
11479 Roo.callback(options.callback, options.scope, [options, true, response]);
11483 handleFailure : function(response, e){
11484 this.transId = false;
11485 var options = response.argument.options;
11486 response.argument = options ? options.argument : null;
11487 this.fireEvent("requestexception", this, response, options, e);
11488 Roo.callback(options.failure, options.scope, [response, options]);
11489 Roo.callback(options.callback, options.scope, [options, false, response]);
11493 doFormUpload : function(o, ps, url){
11495 var frame = document.createElement('iframe');
11498 frame.className = 'x-hidden';
11500 frame.src = Roo.SSL_SECURE_URL;
11502 document.body.appendChild(frame);
11505 document.frames[id].name = id;
11508 var form = Roo.getDom(o.form);
11510 form.method = 'POST';
11511 form.enctype = form.encoding = 'multipart/form-data';
11517 if(ps){ // add dynamic params
11519 ps = Roo.urlDecode(ps, false);
11521 if(ps.hasOwnProperty(k)){
11522 hd = document.createElement('input');
11523 hd.type = 'hidden';
11526 form.appendChild(hd);
11533 var r = { // bogus response object
11538 r.argument = o ? o.argument : null;
11543 doc = frame.contentWindow.document;
11545 doc = (frame.contentDocument || window.frames[id].document);
11547 if(doc && doc.body){
11548 r.responseText = doc.body.innerHTML;
11550 if(doc && doc.XMLDocument){
11551 r.responseXML = doc.XMLDocument;
11553 r.responseXML = doc;
11560 Roo.EventManager.removeListener(frame, 'load', cb, this);
11562 this.fireEvent("requestcomplete", this, r, o);
11563 Roo.callback(o.success, o.scope, [r, o]);
11564 Roo.callback(o.callback, o.scope, [o, true, r]);
11566 setTimeout(function(){document.body.removeChild(frame);}, 100);
11569 Roo.EventManager.on(frame, 'load', cb, this);
11572 if(hiddens){ // remove dynamic params
11573 for(var i = 0, len = hiddens.length; i < len; i++){
11574 form.removeChild(hiddens[i]);
11581 * Ext JS Library 1.1.1
11582 * Copyright(c) 2006-2007, Ext JS, LLC.
11584 * Originally Released Under LGPL - original licence link has changed is not relivant.
11587 * <script type="text/javascript">
11591 * Global Ajax request class.
11594 * @extends Roo.data.Connection
11597 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11598 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11599 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11600 * @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)
11601 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11602 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11603 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11605 Roo.Ajax = new Roo.data.Connection({
11614 * Serialize the passed form into a url encoded string
11616 * @param {String/HTMLElement} form
11619 serializeForm : function(form){
11620 return Roo.lib.Ajax.serializeForm(form);
11624 * Ext JS Library 1.1.1
11625 * Copyright(c) 2006-2007, Ext JS, LLC.
11627 * Originally Released Under LGPL - original licence link has changed is not relivant.
11630 * <script type="text/javascript">
11635 * @class Roo.UpdateManager
11636 * @extends Roo.util.Observable
11637 * Provides AJAX-style update for Element object.<br><br>
11640 * // Get it from a Roo.Element object
11641 * var el = Roo.get("foo");
11642 * var mgr = el.getUpdateManager();
11643 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11645 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11647 * // or directly (returns the same UpdateManager instance)
11648 * var mgr = new Roo.UpdateManager("myElementId");
11649 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11650 * mgr.on("update", myFcnNeedsToKnow);
11652 // short handed call directly from the element object
11653 Roo.get("foo").load({
11657 text: "Loading Foo..."
11661 * Create new UpdateManager directly.
11662 * @param {String/HTMLElement/Roo.Element} el The element to update
11663 * @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).
11665 Roo.UpdateManager = function(el, forceNew){
11667 if(!forceNew && el.updateManager){
11668 return el.updateManager;
11671 * The Element object
11672 * @type Roo.Element
11676 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11679 this.defaultUrl = null;
11683 * @event beforeupdate
11684 * Fired before an update is made, return false from your handler and the update is cancelled.
11685 * @param {Roo.Element} el
11686 * @param {String/Object/Function} url
11687 * @param {String/Object} params
11689 "beforeupdate": true,
11692 * Fired after successful update is made.
11693 * @param {Roo.Element} el
11694 * @param {Object} oResponseObject The response Object
11699 * Fired on update failure.
11700 * @param {Roo.Element} el
11701 * @param {Object} oResponseObject The response Object
11705 var d = Roo.UpdateManager.defaults;
11707 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11710 this.sslBlankUrl = d.sslBlankUrl;
11712 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11715 this.disableCaching = d.disableCaching;
11717 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11720 this.indicatorText = d.indicatorText;
11722 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11725 this.showLoadIndicator = d.showLoadIndicator;
11727 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11730 this.timeout = d.timeout;
11733 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11736 this.loadScripts = d.loadScripts;
11739 * Transaction object of current executing transaction
11741 this.transaction = null;
11746 this.autoRefreshProcId = null;
11748 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11751 this.refreshDelegate = this.refresh.createDelegate(this);
11753 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11756 this.updateDelegate = this.update.createDelegate(this);
11758 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11761 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11765 this.successDelegate = this.processSuccess.createDelegate(this);
11769 this.failureDelegate = this.processFailure.createDelegate(this);
11771 if(!this.renderer){
11773 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11775 this.renderer = new Roo.UpdateManager.BasicRenderer();
11778 Roo.UpdateManager.superclass.constructor.call(this);
11781 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11783 * Get the Element this UpdateManager is bound to
11784 * @return {Roo.Element} The element
11786 getEl : function(){
11790 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11791 * @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:
11794 url: "your-url.php",<br/>
11795 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11796 callback: yourFunction,<br/>
11797 scope: yourObject, //(optional scope) <br/>
11798 discardUrl: false, <br/>
11799 nocache: false,<br/>
11800 text: "Loading...",<br/>
11802 scripts: false<br/>
11805 * The only required property is url. The optional properties nocache, text and scripts
11806 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11807 * @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}
11808 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11809 * @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.
11811 update : function(url, params, callback, discardUrl){
11812 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11813 var method = this.method,
11815 if(typeof url == "object"){ // must be config object
11818 params = params || cfg.params;
11819 callback = callback || cfg.callback;
11820 discardUrl = discardUrl || cfg.discardUrl;
11821 if(callback && cfg.scope){
11822 callback = callback.createDelegate(cfg.scope);
11824 if(typeof cfg.method != "undefined"){method = cfg.method;};
11825 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11826 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11827 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11828 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11830 this.showLoading();
11832 this.defaultUrl = url;
11834 if(typeof url == "function"){
11835 url = url.call(this);
11838 method = method || (params ? "POST" : "GET");
11839 if(method == "GET"){
11840 url = this.prepareUrl(url);
11843 var o = Roo.apply(cfg ||{}, {
11846 success: this.successDelegate,
11847 failure: this.failureDelegate,
11848 callback: undefined,
11849 timeout: (this.timeout*1000),
11850 argument: {"url": url, "form": null, "callback": callback, "params": params}
11852 Roo.log("updated manager called with timeout of " + o.timeout);
11853 this.transaction = Roo.Ajax.request(o);
11858 * 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.
11859 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11860 * @param {String/HTMLElement} form The form Id or form element
11861 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11862 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11863 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11865 formUpdate : function(form, url, reset, callback){
11866 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11867 if(typeof url == "function"){
11868 url = url.call(this);
11870 form = Roo.getDom(form);
11871 this.transaction = Roo.Ajax.request({
11874 success: this.successDelegate,
11875 failure: this.failureDelegate,
11876 timeout: (this.timeout*1000),
11877 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11879 this.showLoading.defer(1, this);
11884 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11885 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11887 refresh : function(callback){
11888 if(this.defaultUrl == null){
11891 this.update(this.defaultUrl, null, callback, true);
11895 * Set this element to auto refresh.
11896 * @param {Number} interval How often to update (in seconds).
11897 * @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)
11898 * @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}
11899 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11900 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11902 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11904 this.update(url || this.defaultUrl, params, callback, true);
11906 if(this.autoRefreshProcId){
11907 clearInterval(this.autoRefreshProcId);
11909 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11913 * Stop auto refresh on this element.
11915 stopAutoRefresh : function(){
11916 if(this.autoRefreshProcId){
11917 clearInterval(this.autoRefreshProcId);
11918 delete this.autoRefreshProcId;
11922 isAutoRefreshing : function(){
11923 return this.autoRefreshProcId ? true : false;
11926 * Called to update the element to "Loading" state. Override to perform custom action.
11928 showLoading : function(){
11929 if(this.showLoadIndicator){
11930 this.el.update(this.indicatorText);
11935 * Adds unique parameter to query string if disableCaching = true
11938 prepareUrl : function(url){
11939 if(this.disableCaching){
11940 var append = "_dc=" + (new Date().getTime());
11941 if(url.indexOf("?") !== -1){
11942 url += "&" + append;
11944 url += "?" + append;
11953 processSuccess : function(response){
11954 this.transaction = null;
11955 if(response.argument.form && response.argument.reset){
11956 try{ // put in try/catch since some older FF releases had problems with this
11957 response.argument.form.reset();
11960 if(this.loadScripts){
11961 this.renderer.render(this.el, response, this,
11962 this.updateComplete.createDelegate(this, [response]));
11964 this.renderer.render(this.el, response, this);
11965 this.updateComplete(response);
11969 updateComplete : function(response){
11970 this.fireEvent("update", this.el, response);
11971 if(typeof response.argument.callback == "function"){
11972 response.argument.callback(this.el, true, response);
11979 processFailure : function(response){
11980 this.transaction = null;
11981 this.fireEvent("failure", this.el, response);
11982 if(typeof response.argument.callback == "function"){
11983 response.argument.callback(this.el, false, response);
11988 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11989 * @param {Object} renderer The object implementing the render() method
11991 setRenderer : function(renderer){
11992 this.renderer = renderer;
11995 getRenderer : function(){
11996 return this.renderer;
12000 * Set the defaultUrl used for updates
12001 * @param {String/Function} defaultUrl The url or a function to call to get the url
12003 setDefaultUrl : function(defaultUrl){
12004 this.defaultUrl = defaultUrl;
12008 * Aborts the executing transaction
12010 abort : function(){
12011 if(this.transaction){
12012 Roo.Ajax.abort(this.transaction);
12017 * Returns true if an update is in progress
12018 * @return {Boolean}
12020 isUpdating : function(){
12021 if(this.transaction){
12022 return Roo.Ajax.isLoading(this.transaction);
12029 * @class Roo.UpdateManager.defaults
12030 * @static (not really - but it helps the doc tool)
12031 * The defaults collection enables customizing the default properties of UpdateManager
12033 Roo.UpdateManager.defaults = {
12035 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12041 * True to process scripts by default (Defaults to false).
12044 loadScripts : false,
12047 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12050 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12052 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12055 disableCaching : false,
12057 * Whether to show indicatorText when loading (Defaults to true).
12060 showLoadIndicator : true,
12062 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12065 indicatorText : '<div class="loading-indicator">Loading...</div>'
12069 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12071 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12072 * @param {String/HTMLElement/Roo.Element} el The element to update
12073 * @param {String} url The url
12074 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12075 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12078 * @member Roo.UpdateManager
12080 Roo.UpdateManager.updateElement = function(el, url, params, options){
12081 var um = Roo.get(el, true).getUpdateManager();
12082 Roo.apply(um, options);
12083 um.update(url, params, options ? options.callback : null);
12085 // alias for backwards compat
12086 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12088 * @class Roo.UpdateManager.BasicRenderer
12089 * Default Content renderer. Updates the elements innerHTML with the responseText.
12091 Roo.UpdateManager.BasicRenderer = function(){};
12093 Roo.UpdateManager.BasicRenderer.prototype = {
12095 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12096 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12097 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12098 * @param {Roo.Element} el The element being rendered
12099 * @param {Object} response The YUI Connect response object
12100 * @param {UpdateManager} updateManager The calling update manager
12101 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12103 render : function(el, response, updateManager, callback){
12104 el.update(response.responseText, updateManager.loadScripts, callback);
12110 * (c)) Alan Knowles
12116 * @class Roo.DomTemplate
12117 * @extends Roo.Template
12118 * An effort at a dom based template engine..
12120 * Similar to XTemplate, except it uses dom parsing to create the template..
12122 * Supported features:
12127 {a_variable} - output encoded.
12128 {a_variable.format:("Y-m-d")} - call a method on the variable
12129 {a_variable:raw} - unencoded output
12130 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12131 {a_variable:this.method_on_template(...)} - call a method on the template object.
12136 <div roo-for="a_variable or condition.."></div>
12137 <div roo-if="a_variable or condition"></div>
12138 <div roo-exec="some javascript"></div>
12139 <div roo-name="named_template"></div>
12144 Roo.DomTemplate = function()
12146 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12153 Roo.extend(Roo.DomTemplate, Roo.Template, {
12155 * id counter for sub templates.
12159 * flag to indicate if dom parser is inside a pre,
12160 * it will strip whitespace if not.
12165 * The various sub templates
12173 * basic tag replacing syntax
12176 * // you can fake an object call by doing this
12180 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12181 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12183 iterChild : function (node, method) {
12185 var oldPre = this.inPre;
12186 if (node.tagName == 'PRE') {
12189 for( var i = 0; i < node.childNodes.length; i++) {
12190 method.call(this, node.childNodes[i]);
12192 this.inPre = oldPre;
12198 * compile the template
12200 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12203 compile: function()
12207 // covert the html into DOM...
12211 doc = document.implementation.createHTMLDocument("");
12212 doc.documentElement.innerHTML = this.html ;
12213 div = doc.documentElement;
12215 // old IE... - nasty -- it causes all sorts of issues.. with
12216 // images getting pulled from server..
12217 div = document.createElement('div');
12218 div.innerHTML = this.html;
12220 //doc.documentElement.innerHTML = htmlBody
12226 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12228 var tpls = this.tpls;
12230 // create a top level template from the snippet..
12232 //Roo.log(div.innerHTML);
12239 body : div.innerHTML,
12252 Roo.each(tpls, function(tp){
12253 this.compileTpl(tp);
12254 this.tpls[tp.id] = tp;
12257 this.master = tpls[0];
12263 compileNode : function(node, istop) {
12268 // skip anything not a tag..
12269 if (node.nodeType != 1) {
12270 if (node.nodeType == 3 && !this.inPre) {
12271 // reduce white space..
12272 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12295 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12296 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12297 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12298 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12304 // just itterate children..
12305 this.iterChild(node,this.compileNode);
12308 tpl.uid = this.id++;
12309 tpl.value = node.getAttribute('roo-' + tpl.attr);
12310 node.removeAttribute('roo-'+ tpl.attr);
12311 if (tpl.attr != 'name') {
12312 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12313 node.parentNode.replaceChild(placeholder, node);
12316 var placeholder = document.createElement('span');
12317 placeholder.className = 'roo-tpl-' + tpl.value;
12318 node.parentNode.replaceChild(placeholder, node);
12321 // parent now sees '{domtplXXXX}
12322 this.iterChild(node,this.compileNode);
12324 // we should now have node body...
12325 var div = document.createElement('div');
12326 div.appendChild(node);
12328 // this has the unfortunate side effect of converting tagged attributes
12329 // eg. href="{...}" into %7C...%7D
12330 // this has been fixed by searching for those combo's although it's a bit hacky..
12333 tpl.body = div.innerHTML;
12340 switch (tpl.value) {
12341 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12342 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12343 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12348 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12352 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12356 tpl.id = tpl.value; // replace non characters???
12362 this.tpls.push(tpl);
12372 * Compile a segment of the template into a 'sub-template'
12378 compileTpl : function(tpl)
12380 var fm = Roo.util.Format;
12381 var useF = this.disableFormats !== true;
12383 var sep = Roo.isGecko ? "+\n" : ",\n";
12385 var undef = function(str) {
12386 Roo.debug && Roo.log("Property not found :" + str);
12390 //Roo.log(tpl.body);
12394 var fn = function(m, lbrace, name, format, args)
12397 //Roo.log(arguments);
12398 args = args ? args.replace(/\\'/g,"'") : args;
12399 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12400 if (typeof(format) == 'undefined') {
12401 format = 'htmlEncode';
12403 if (format == 'raw' ) {
12407 if(name.substr(0, 6) == 'domtpl'){
12408 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12411 // build an array of options to determine if value is undefined..
12413 // basically get 'xxxx.yyyy' then do
12414 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12415 // (function () { Roo.log("Property not found"); return ''; })() :
12420 Roo.each(name.split('.'), function(st) {
12421 lookfor += (lookfor.length ? '.': '') + st;
12422 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12425 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12428 if(format && useF){
12430 args = args ? ',' + args : "";
12432 if(format.substr(0, 5) != "this."){
12433 format = "fm." + format + '(';
12435 format = 'this.call("'+ format.substr(5) + '", ';
12439 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12442 if (args && args.length) {
12443 // called with xxyx.yuu:(test,test)
12445 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12447 // raw.. - :raw modifier..
12448 return "'"+ sep + udef_st + name + ")"+sep+"'";
12452 // branched to use + in gecko and [].join() in others
12454 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12455 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12458 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12459 body.push(tpl.body.replace(/(\r\n|\n)/g,
12460 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12461 body.push("'].join('');};};");
12462 body = body.join('');
12465 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12467 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12474 * same as applyTemplate, except it's done to one of the subTemplates
12475 * when using named templates, you can do:
12477 * var str = pl.applySubTemplate('your-name', values);
12480 * @param {Number} id of the template
12481 * @param {Object} values to apply to template
12482 * @param {Object} parent (normaly the instance of this object)
12484 applySubTemplate : function(id, values, parent)
12488 var t = this.tpls[id];
12492 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12493 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12497 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12504 if(t.execCall && t.execCall.call(this, values, parent)){
12508 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12514 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12515 parent = t.target ? values : parent;
12516 if(t.forCall && vs instanceof Array){
12518 for(var i = 0, len = vs.length; i < len; i++){
12520 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12522 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12524 //Roo.log(t.compiled);
12528 return buf.join('');
12531 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12536 return t.compiled.call(this, vs, parent);
12538 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12540 //Roo.log(t.compiled);
12548 applyTemplate : function(values){
12549 return this.master.compiled.call(this, values, {});
12550 //var s = this.subs;
12553 apply : function(){
12554 return this.applyTemplate.apply(this, arguments);
12559 Roo.DomTemplate.from = function(el){
12560 el = Roo.getDom(el);
12561 return new Roo.Domtemplate(el.value || el.innerHTML);
12564 * Ext JS Library 1.1.1
12565 * Copyright(c) 2006-2007, Ext JS, LLC.
12567 * Originally Released Under LGPL - original licence link has changed is not relivant.
12570 * <script type="text/javascript">
12574 * @class Roo.util.DelayedTask
12575 * Provides a convenient method of performing setTimeout where a new
12576 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12577 * You can use this class to buffer
12578 * the keypress events for a certain number of milliseconds, and perform only if they stop
12579 * for that amount of time.
12580 * @constructor The parameters to this constructor serve as defaults and are not required.
12581 * @param {Function} fn (optional) The default function to timeout
12582 * @param {Object} scope (optional) The default scope of that timeout
12583 * @param {Array} args (optional) The default Array of arguments
12585 Roo.util.DelayedTask = function(fn, scope, args){
12586 var id = null, d, t;
12588 var call = function(){
12589 var now = new Date().getTime();
12593 fn.apply(scope, args || []);
12597 * Cancels any pending timeout and queues a new one
12598 * @param {Number} delay The milliseconds to delay
12599 * @param {Function} newFn (optional) Overrides function passed to constructor
12600 * @param {Object} newScope (optional) Overrides scope passed to constructor
12601 * @param {Array} newArgs (optional) Overrides args passed to constructor
12603 this.delay = function(delay, newFn, newScope, newArgs){
12604 if(id && delay != d){
12608 t = new Date().getTime();
12610 scope = newScope || scope;
12611 args = newArgs || args;
12613 id = setInterval(call, d);
12618 * Cancel the last queued timeout
12620 this.cancel = function(){
12628 * Ext JS Library 1.1.1
12629 * Copyright(c) 2006-2007, Ext JS, LLC.
12631 * Originally Released Under LGPL - original licence link has changed is not relivant.
12634 * <script type="text/javascript">
12638 Roo.util.TaskRunner = function(interval){
12639 interval = interval || 10;
12640 var tasks = [], removeQueue = [];
12642 var running = false;
12644 var stopThread = function(){
12650 var startThread = function(){
12653 id = setInterval(runTasks, interval);
12657 var removeTask = function(task){
12658 removeQueue.push(task);
12664 var runTasks = function(){
12665 if(removeQueue.length > 0){
12666 for(var i = 0, len = removeQueue.length; i < len; i++){
12667 tasks.remove(removeQueue[i]);
12670 if(tasks.length < 1){
12675 var now = new Date().getTime();
12676 for(var i = 0, len = tasks.length; i < len; ++i){
12678 var itime = now - t.taskRunTime;
12679 if(t.interval <= itime){
12680 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12681 t.taskRunTime = now;
12682 if(rt === false || t.taskRunCount === t.repeat){
12687 if(t.duration && t.duration <= (now - t.taskStartTime)){
12694 * Queues a new task.
12695 * @param {Object} task
12697 this.start = function(task){
12699 task.taskStartTime = new Date().getTime();
12700 task.taskRunTime = 0;
12701 task.taskRunCount = 0;
12706 this.stop = function(task){
12711 this.stopAll = function(){
12713 for(var i = 0, len = tasks.length; i < len; i++){
12714 if(tasks[i].onStop){
12723 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12725 * Ext JS Library 1.1.1
12726 * Copyright(c) 2006-2007, Ext JS, LLC.
12728 * Originally Released Under LGPL - original licence link has changed is not relivant.
12731 * <script type="text/javascript">
12736 * @class Roo.util.MixedCollection
12737 * @extends Roo.util.Observable
12738 * A Collection class that maintains both numeric indexes and keys and exposes events.
12740 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12741 * collection (defaults to false)
12742 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12743 * and return the key value for that item. This is used when available to look up the key on items that
12744 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12745 * equivalent to providing an implementation for the {@link #getKey} method.
12747 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12755 * Fires when the collection is cleared.
12760 * Fires when an item is added to the collection.
12761 * @param {Number} index The index at which the item was added.
12762 * @param {Object} o The item added.
12763 * @param {String} key The key associated with the added item.
12768 * Fires when an item is replaced in the collection.
12769 * @param {String} key he key associated with the new added.
12770 * @param {Object} old The item being replaced.
12771 * @param {Object} new The new item.
12776 * Fires when an item is removed from the collection.
12777 * @param {Object} o The item being removed.
12778 * @param {String} key (optional) The key associated with the removed item.
12783 this.allowFunctions = allowFunctions === true;
12785 this.getKey = keyFn;
12787 Roo.util.MixedCollection.superclass.constructor.call(this);
12790 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12791 allowFunctions : false,
12794 * Adds an item to the collection.
12795 * @param {String} key The key to associate with the item
12796 * @param {Object} o The item to add.
12797 * @return {Object} The item added.
12799 add : function(key, o){
12800 if(arguments.length == 1){
12802 key = this.getKey(o);
12804 if(typeof key == "undefined" || key === null){
12806 this.items.push(o);
12807 this.keys.push(null);
12809 var old = this.map[key];
12811 return this.replace(key, o);
12814 this.items.push(o);
12816 this.keys.push(key);
12818 this.fireEvent("add", this.length-1, o, key);
12823 * MixedCollection has a generic way to fetch keys if you implement getKey.
12826 var mc = new Roo.util.MixedCollection();
12827 mc.add(someEl.dom.id, someEl);
12828 mc.add(otherEl.dom.id, otherEl);
12832 var mc = new Roo.util.MixedCollection();
12833 mc.getKey = function(el){
12839 // or via the constructor
12840 var mc = new Roo.util.MixedCollection(false, function(el){
12846 * @param o {Object} The item for which to find the key.
12847 * @return {Object} The key for the passed item.
12849 getKey : function(o){
12854 * Replaces an item in the collection.
12855 * @param {String} key The key associated with the item to replace, or the item to replace.
12856 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12857 * @return {Object} The new item.
12859 replace : function(key, o){
12860 if(arguments.length == 1){
12862 key = this.getKey(o);
12864 var old = this.item(key);
12865 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12866 return this.add(key, o);
12868 var index = this.indexOfKey(key);
12869 this.items[index] = o;
12871 this.fireEvent("replace", key, old, o);
12876 * Adds all elements of an Array or an Object to the collection.
12877 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12878 * an Array of values, each of which are added to the collection.
12880 addAll : function(objs){
12881 if(arguments.length > 1 || objs instanceof Array){
12882 var args = arguments.length > 1 ? arguments : objs;
12883 for(var i = 0, len = args.length; i < len; i++){
12887 for(var key in objs){
12888 if(this.allowFunctions || typeof objs[key] != "function"){
12889 this.add(key, objs[key]);
12896 * Executes the specified function once for every item in the collection, passing each
12897 * item as the first and only parameter. returning false from the function will stop the iteration.
12898 * @param {Function} fn The function to execute for each item.
12899 * @param {Object} scope (optional) The scope in which to execute the function.
12901 each : function(fn, scope){
12902 var items = [].concat(this.items); // each safe for removal
12903 for(var i = 0, len = items.length; i < len; i++){
12904 if(fn.call(scope || items[i], items[i], i, len) === false){
12911 * Executes the specified function once for every key in the collection, passing each
12912 * key, and its associated item as the first two parameters.
12913 * @param {Function} fn The function to execute for each item.
12914 * @param {Object} scope (optional) The scope in which to execute the function.
12916 eachKey : function(fn, scope){
12917 for(var i = 0, len = this.keys.length; i < len; i++){
12918 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12923 * Returns the first item in the collection which elicits a true return value from the
12924 * passed selection function.
12925 * @param {Function} fn The selection function to execute for each item.
12926 * @param {Object} scope (optional) The scope in which to execute the function.
12927 * @return {Object} The first item in the collection which returned true from the selection function.
12929 find : function(fn, scope){
12930 for(var i = 0, len = this.items.length; i < len; i++){
12931 if(fn.call(scope || window, this.items[i], this.keys[i])){
12932 return this.items[i];
12939 * Inserts an item at the specified index in the collection.
12940 * @param {Number} index The index to insert the item at.
12941 * @param {String} key The key to associate with the new item, or the item itself.
12942 * @param {Object} o (optional) If the second parameter was a key, the new item.
12943 * @return {Object} The item inserted.
12945 insert : function(index, key, o){
12946 if(arguments.length == 2){
12948 key = this.getKey(o);
12950 if(index >= this.length){
12951 return this.add(key, o);
12954 this.items.splice(index, 0, o);
12955 if(typeof key != "undefined" && key != null){
12958 this.keys.splice(index, 0, key);
12959 this.fireEvent("add", index, o, key);
12964 * Removed an item from the collection.
12965 * @param {Object} o The item to remove.
12966 * @return {Object} The item removed.
12968 remove : function(o){
12969 return this.removeAt(this.indexOf(o));
12973 * Remove an item from a specified index in the collection.
12974 * @param {Number} index The index within the collection of the item to remove.
12976 removeAt : function(index){
12977 if(index < this.length && index >= 0){
12979 var o = this.items[index];
12980 this.items.splice(index, 1);
12981 var key = this.keys[index];
12982 if(typeof key != "undefined"){
12983 delete this.map[key];
12985 this.keys.splice(index, 1);
12986 this.fireEvent("remove", o, key);
12991 * Removed an item associated with the passed key fom the collection.
12992 * @param {String} key The key of the item to remove.
12994 removeKey : function(key){
12995 return this.removeAt(this.indexOfKey(key));
12999 * Returns the number of items in the collection.
13000 * @return {Number} the number of items in the collection.
13002 getCount : function(){
13003 return this.length;
13007 * Returns index within the collection of the passed Object.
13008 * @param {Object} o The item to find the index of.
13009 * @return {Number} index of the item.
13011 indexOf : function(o){
13012 if(!this.items.indexOf){
13013 for(var i = 0, len = this.items.length; i < len; i++){
13014 if(this.items[i] == o) return i;
13018 return this.items.indexOf(o);
13023 * Returns index within the collection of the passed key.
13024 * @param {String} key The key to find the index of.
13025 * @return {Number} index of the key.
13027 indexOfKey : function(key){
13028 if(!this.keys.indexOf){
13029 for(var i = 0, len = this.keys.length; i < len; i++){
13030 if(this.keys[i] == key) return i;
13034 return this.keys.indexOf(key);
13039 * Returns the item associated with the passed key OR index. Key has priority over index.
13040 * @param {String/Number} key The key or index of the item.
13041 * @return {Object} The item associated with the passed key.
13043 item : function(key){
13044 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13045 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13049 * Returns the item at the specified index.
13050 * @param {Number} index The index of the item.
13053 itemAt : function(index){
13054 return this.items[index];
13058 * Returns the item associated with the passed key.
13059 * @param {String/Number} key The key of the item.
13060 * @return {Object} The item associated with the passed key.
13062 key : function(key){
13063 return this.map[key];
13067 * Returns true if the collection contains the passed Object as an item.
13068 * @param {Object} o The Object to look for in the collection.
13069 * @return {Boolean} True if the collection contains the Object as an item.
13071 contains : function(o){
13072 return this.indexOf(o) != -1;
13076 * Returns true if the collection contains the passed Object as a key.
13077 * @param {String} key The key to look for in the collection.
13078 * @return {Boolean} True if the collection contains the Object as a key.
13080 containsKey : function(key){
13081 return typeof this.map[key] != "undefined";
13085 * Removes all items from the collection.
13087 clear : function(){
13092 this.fireEvent("clear");
13096 * Returns the first item in the collection.
13097 * @return {Object} the first item in the collection..
13099 first : function(){
13100 return this.items[0];
13104 * Returns the last item in the collection.
13105 * @return {Object} the last item in the collection..
13108 return this.items[this.length-1];
13111 _sort : function(property, dir, fn){
13112 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13113 fn = fn || function(a, b){
13116 var c = [], k = this.keys, items = this.items;
13117 for(var i = 0, len = items.length; i < len; i++){
13118 c[c.length] = {key: k[i], value: items[i], index: i};
13120 c.sort(function(a, b){
13121 var v = fn(a[property], b[property]) * dsc;
13123 v = (a.index < b.index ? -1 : 1);
13127 for(var i = 0, len = c.length; i < len; i++){
13128 items[i] = c[i].value;
13131 this.fireEvent("sort", this);
13135 * Sorts this collection with the passed comparison function
13136 * @param {String} direction (optional) "ASC" or "DESC"
13137 * @param {Function} fn (optional) comparison function
13139 sort : function(dir, fn){
13140 this._sort("value", dir, fn);
13144 * Sorts this collection by keys
13145 * @param {String} direction (optional) "ASC" or "DESC"
13146 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13148 keySort : function(dir, fn){
13149 this._sort("key", dir, fn || function(a, b){
13150 return String(a).toUpperCase()-String(b).toUpperCase();
13155 * Returns a range of items in this collection
13156 * @param {Number} startIndex (optional) defaults to 0
13157 * @param {Number} endIndex (optional) default to the last item
13158 * @return {Array} An array of items
13160 getRange : function(start, end){
13161 var items = this.items;
13162 if(items.length < 1){
13165 start = start || 0;
13166 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13169 for(var i = start; i <= end; i++) {
13170 r[r.length] = items[i];
13173 for(var i = start; i >= end; i--) {
13174 r[r.length] = items[i];
13181 * Filter the <i>objects</i> in this collection by a specific property.
13182 * Returns a new collection that has been filtered.
13183 * @param {String} property A property on your objects
13184 * @param {String/RegExp} value Either string that the property values
13185 * should start with or a RegExp to test against the property
13186 * @return {MixedCollection} The new filtered collection
13188 filter : function(property, value){
13189 if(!value.exec){ // not a regex
13190 value = String(value);
13191 if(value.length == 0){
13192 return this.clone();
13194 value = new RegExp("^" + Roo.escapeRe(value), "i");
13196 return this.filterBy(function(o){
13197 return o && value.test(o[property]);
13202 * Filter by a function. * Returns a new collection that has been filtered.
13203 * The passed function will be called with each
13204 * object in the collection. If the function returns true, the value is included
13205 * otherwise it is filtered.
13206 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13207 * @param {Object} scope (optional) The scope of the function (defaults to this)
13208 * @return {MixedCollection} The new filtered collection
13210 filterBy : function(fn, scope){
13211 var r = new Roo.util.MixedCollection();
13212 r.getKey = this.getKey;
13213 var k = this.keys, it = this.items;
13214 for(var i = 0, len = it.length; i < len; i++){
13215 if(fn.call(scope||this, it[i], k[i])){
13216 r.add(k[i], it[i]);
13223 * Creates a duplicate of this collection
13224 * @return {MixedCollection}
13226 clone : function(){
13227 var r = new Roo.util.MixedCollection();
13228 var k = this.keys, it = this.items;
13229 for(var i = 0, len = it.length; i < len; i++){
13230 r.add(k[i], it[i]);
13232 r.getKey = this.getKey;
13237 * Returns the item associated with the passed key or index.
13239 * @param {String/Number} key The key or index of the item.
13240 * @return {Object} The item associated with the passed key.
13242 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13244 * Ext JS Library 1.1.1
13245 * Copyright(c) 2006-2007, Ext JS, LLC.
13247 * Originally Released Under LGPL - original licence link has changed is not relivant.
13250 * <script type="text/javascript">
13253 * @class Roo.util.JSON
13254 * Modified version of Douglas Crockford"s json.js that doesn"t
13255 * mess with the Object prototype
13256 * http://www.json.org/js.html
13259 Roo.util.JSON = new (function(){
13260 var useHasOwn = {}.hasOwnProperty ? true : false;
13262 // crashes Safari in some instances
13263 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13265 var pad = function(n) {
13266 return n < 10 ? "0" + n : n;
13279 var encodeString = function(s){
13280 if (/["\\\x00-\x1f]/.test(s)) {
13281 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13286 c = b.charCodeAt();
13288 Math.floor(c / 16).toString(16) +
13289 (c % 16).toString(16);
13292 return '"' + s + '"';
13295 var encodeArray = function(o){
13296 var a = ["["], b, i, l = o.length, v;
13297 for (i = 0; i < l; i += 1) {
13299 switch (typeof v) {
13308 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13316 var encodeDate = function(o){
13317 return '"' + o.getFullYear() + "-" +
13318 pad(o.getMonth() + 1) + "-" +
13319 pad(o.getDate()) + "T" +
13320 pad(o.getHours()) + ":" +
13321 pad(o.getMinutes()) + ":" +
13322 pad(o.getSeconds()) + '"';
13326 * Encodes an Object, Array or other value
13327 * @param {Mixed} o The variable to encode
13328 * @return {String} The JSON string
13330 this.encode = function(o)
13332 // should this be extended to fully wrap stringify..
13334 if(typeof o == "undefined" || o === null){
13336 }else if(o instanceof Array){
13337 return encodeArray(o);
13338 }else if(o instanceof Date){
13339 return encodeDate(o);
13340 }else if(typeof o == "string"){
13341 return encodeString(o);
13342 }else if(typeof o == "number"){
13343 return isFinite(o) ? String(o) : "null";
13344 }else if(typeof o == "boolean"){
13347 var a = ["{"], b, i, v;
13349 if(!useHasOwn || o.hasOwnProperty(i)) {
13351 switch (typeof v) {
13360 a.push(this.encode(i), ":",
13361 v === null ? "null" : this.encode(v));
13372 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13373 * @param {String} json The JSON string
13374 * @return {Object} The resulting object
13376 this.decode = function(json){
13378 return /** eval:var:json */ eval("(" + json + ')');
13382 * Shorthand for {@link Roo.util.JSON#encode}
13383 * @member Roo encode
13385 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13387 * Shorthand for {@link Roo.util.JSON#decode}
13388 * @member Roo decode
13390 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13393 * Ext JS Library 1.1.1
13394 * Copyright(c) 2006-2007, Ext JS, LLC.
13396 * Originally Released Under LGPL - original licence link has changed is not relivant.
13399 * <script type="text/javascript">
13403 * @class Roo.util.Format
13404 * Reusable data formatting functions
13407 Roo.util.Format = function(){
13408 var trimRe = /^\s+|\s+$/g;
13411 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13412 * @param {String} value The string to truncate
13413 * @param {Number} length The maximum length to allow before truncating
13414 * @return {String} The converted text
13416 ellipsis : function(value, len){
13417 if(value && value.length > len){
13418 return value.substr(0, len-3)+"...";
13424 * Checks a reference and converts it to empty string if it is undefined
13425 * @param {Mixed} value Reference to check
13426 * @return {Mixed} Empty string if converted, otherwise the original value
13428 undef : function(value){
13429 return typeof value != "undefined" ? value : "";
13433 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13434 * @param {String} value The string to encode
13435 * @return {String} The encoded text
13437 htmlEncode : function(value){
13438 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13442 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13443 * @param {String} value The string to decode
13444 * @return {String} The decoded text
13446 htmlDecode : function(value){
13447 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13451 * Trims any whitespace from either side of a string
13452 * @param {String} value The text to trim
13453 * @return {String} The trimmed text
13455 trim : function(value){
13456 return String(value).replace(trimRe, "");
13460 * Returns a substring from within an original string
13461 * @param {String} value The original text
13462 * @param {Number} start The start index of the substring
13463 * @param {Number} length The length of the substring
13464 * @return {String} The substring
13466 substr : function(value, start, length){
13467 return String(value).substr(start, length);
13471 * Converts a string to all lower case letters
13472 * @param {String} value The text to convert
13473 * @return {String} The converted text
13475 lowercase : function(value){
13476 return String(value).toLowerCase();
13480 * Converts a string to all upper case letters
13481 * @param {String} value The text to convert
13482 * @return {String} The converted text
13484 uppercase : function(value){
13485 return String(value).toUpperCase();
13489 * Converts the first character only of a string to upper case
13490 * @param {String} value The text to convert
13491 * @return {String} The converted text
13493 capitalize : function(value){
13494 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13498 call : function(value, fn){
13499 if(arguments.length > 2){
13500 var args = Array.prototype.slice.call(arguments, 2);
13501 args.unshift(value);
13503 return /** eval:var:value */ eval(fn).apply(window, args);
13505 /** eval:var:value */
13506 return /** eval:var:value */ eval(fn).call(window, value);
13512 * safer version of Math.toFixed..??/
13513 * @param {Number/String} value The numeric value to format
13514 * @param {Number/String} value Decimal places
13515 * @return {String} The formatted currency string
13517 toFixed : function(v, n)
13519 // why not use to fixed - precision is buggered???
13521 return Math.round(v-0);
13523 var fact = Math.pow(10,n+1);
13524 v = (Math.round((v-0)*fact))/fact;
13525 var z = (''+fact).substring(2);
13526 if (v == Math.floor(v)) {
13527 return Math.floor(v) + '.' + z;
13530 // now just padd decimals..
13531 var ps = String(v).split('.');
13532 var fd = (ps[1] + z);
13533 var r = fd.substring(0,n);
13534 var rm = fd.substring(n);
13536 return ps[0] + '.' + r;
13538 r*=1; // turn it into a number;
13540 if (String(r).length != n) {
13543 r = String(r).substring(1); // chop the end off.
13546 return ps[0] + '.' + r;
13551 * Format a number as US currency
13552 * @param {Number/String} value The numeric value to format
13553 * @return {String} The formatted currency string
13555 usMoney : function(v){
13556 return '$' + Roo.util.Format.number(v);
13561 * eventually this should probably emulate php's number_format
13562 * @param {Number/String} value The numeric value to format
13563 * @param {Number} decimals number of decimal places
13564 * @return {String} The formatted currency string
13566 number : function(v,decimals)
13568 // multiply and round.
13569 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13570 var mul = Math.pow(10, decimals);
13571 var zero = String(mul).substring(1);
13572 v = (Math.round((v-0)*mul))/mul;
13574 // if it's '0' number.. then
13576 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13578 var ps = v.split('.');
13582 var r = /(\d+)(\d{3})/;
13584 while (r.test(whole)) {
13585 whole = whole.replace(r, '$1' + ',' + '$2');
13591 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13592 // does not have decimals
13593 (decimals ? ('.' + zero) : '');
13596 return whole + sub ;
13600 * Parse a value into a formatted date using the specified format pattern.
13601 * @param {Mixed} value The value to format
13602 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13603 * @return {String} The formatted date string
13605 date : function(v, format){
13609 if(!(v instanceof Date)){
13610 v = new Date(Date.parse(v));
13612 return v.dateFormat(format || Roo.util.Format.defaults.date);
13616 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13617 * @param {String} format Any valid date format string
13618 * @return {Function} The date formatting function
13620 dateRenderer : function(format){
13621 return function(v){
13622 return Roo.util.Format.date(v, format);
13627 stripTagsRE : /<\/?[^>]+>/gi,
13630 * Strips all HTML tags
13631 * @param {Mixed} value The text from which to strip tags
13632 * @return {String} The stripped text
13634 stripTags : function(v){
13635 return !v ? v : String(v).replace(this.stripTagsRE, "");
13639 Roo.util.Format.defaults = {
13643 * Ext JS Library 1.1.1
13644 * Copyright(c) 2006-2007, Ext JS, LLC.
13646 * Originally Released Under LGPL - original licence link has changed is not relivant.
13649 * <script type="text/javascript">
13656 * @class Roo.MasterTemplate
13657 * @extends Roo.Template
13658 * Provides a template that can have child templates. The syntax is:
13660 var t = new Roo.MasterTemplate(
13661 '<select name="{name}">',
13662 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13665 t.add('options', {value: 'foo', text: 'bar'});
13666 // or you can add multiple child elements in one shot
13667 t.addAll('options', [
13668 {value: 'foo', text: 'bar'},
13669 {value: 'foo2', text: 'bar2'},
13670 {value: 'foo3', text: 'bar3'}
13672 // then append, applying the master template values
13673 t.append('my-form', {name: 'my-select'});
13675 * A name attribute for the child template is not required if you have only one child
13676 * template or you want to refer to them by index.
13678 Roo.MasterTemplate = function(){
13679 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13680 this.originalHtml = this.html;
13682 var m, re = this.subTemplateRe;
13685 while(m = re.exec(this.html)){
13686 var name = m[1], content = m[2];
13691 tpl : new Roo.Template(content)
13694 st[name] = st[subIndex];
13696 st[subIndex].tpl.compile();
13697 st[subIndex].tpl.call = this.call.createDelegate(this);
13700 this.subCount = subIndex;
13703 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13705 * The regular expression used to match sub templates
13709 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13712 * Applies the passed values to a child template.
13713 * @param {String/Number} name (optional) The name or index of the child template
13714 * @param {Array/Object} values The values to be applied to the template
13715 * @return {MasterTemplate} this
13717 add : function(name, values){
13718 if(arguments.length == 1){
13719 values = arguments[0];
13722 var s = this.subs[name];
13723 s.buffer[s.buffer.length] = s.tpl.apply(values);
13728 * Applies all the passed values to a child template.
13729 * @param {String/Number} name (optional) The name or index of the child template
13730 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13731 * @param {Boolean} reset (optional) True to reset the template first
13732 * @return {MasterTemplate} this
13734 fill : function(name, values, reset){
13736 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13744 for(var i = 0, len = values.length; i < len; i++){
13745 this.add(name, values[i]);
13751 * Resets the template for reuse
13752 * @return {MasterTemplate} this
13754 reset : function(){
13756 for(var i = 0; i < this.subCount; i++){
13762 applyTemplate : function(values){
13764 var replaceIndex = -1;
13765 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13766 return s[++replaceIndex].buffer.join("");
13768 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13771 apply : function(){
13772 return this.applyTemplate.apply(this, arguments);
13775 compile : function(){return this;}
13779 * Alias for fill().
13782 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13784 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13785 * var tpl = Roo.MasterTemplate.from('element-id');
13786 * @param {String/HTMLElement} el
13787 * @param {Object} config
13790 Roo.MasterTemplate.from = function(el, config){
13791 el = Roo.getDom(el);
13792 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13795 * Ext JS Library 1.1.1
13796 * Copyright(c) 2006-2007, Ext JS, LLC.
13798 * Originally Released Under LGPL - original licence link has changed is not relivant.
13801 * <script type="text/javascript">
13806 * @class Roo.util.CSS
13807 * Utility class for manipulating CSS rules
13810 Roo.util.CSS = function(){
13812 var doc = document;
13814 var camelRe = /(-[a-z])/gi;
13815 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13819 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13820 * tag and appended to the HEAD of the document.
13821 * @param {String|Object} cssText The text containing the css rules
13822 * @param {String} id An id to add to the stylesheet for later removal
13823 * @return {StyleSheet}
13825 createStyleSheet : function(cssText, id){
13827 var head = doc.getElementsByTagName("head")[0];
13828 var nrules = doc.createElement("style");
13829 nrules.setAttribute("type", "text/css");
13831 nrules.setAttribute("id", id);
13833 if (typeof(cssText) != 'string') {
13834 // support object maps..
13835 // not sure if this a good idea..
13836 // perhaps it should be merged with the general css handling
13837 // and handle js style props.
13838 var cssTextNew = [];
13839 for(var n in cssText) {
13841 for(var k in cssText[n]) {
13842 citems.push( k + ' : ' +cssText[n][k] + ';' );
13844 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13847 cssText = cssTextNew.join("\n");
13853 head.appendChild(nrules);
13854 ss = nrules.styleSheet;
13855 ss.cssText = cssText;
13858 nrules.appendChild(doc.createTextNode(cssText));
13860 nrules.cssText = cssText;
13862 head.appendChild(nrules);
13863 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13865 this.cacheStyleSheet(ss);
13870 * Removes a style or link tag by id
13871 * @param {String} id The id of the tag
13873 removeStyleSheet : function(id){
13874 var existing = doc.getElementById(id);
13876 existing.parentNode.removeChild(existing);
13881 * Dynamically swaps an existing stylesheet reference for a new one
13882 * @param {String} id The id of an existing link tag to remove
13883 * @param {String} url The href of the new stylesheet to include
13885 swapStyleSheet : function(id, url){
13886 this.removeStyleSheet(id);
13887 var ss = doc.createElement("link");
13888 ss.setAttribute("rel", "stylesheet");
13889 ss.setAttribute("type", "text/css");
13890 ss.setAttribute("id", id);
13891 ss.setAttribute("href", url);
13892 doc.getElementsByTagName("head")[0].appendChild(ss);
13896 * Refresh the rule cache if you have dynamically added stylesheets
13897 * @return {Object} An object (hash) of rules indexed by selector
13899 refreshCache : function(){
13900 return this.getRules(true);
13904 cacheStyleSheet : function(stylesheet){
13908 try{// try catch for cross domain access issue
13909 var ssRules = stylesheet.cssRules || stylesheet.rules;
13910 for(var j = ssRules.length-1; j >= 0; --j){
13911 rules[ssRules[j].selectorText] = ssRules[j];
13917 * Gets all css rules for the document
13918 * @param {Boolean} refreshCache true to refresh the internal cache
13919 * @return {Object} An object (hash) of rules indexed by selector
13921 getRules : function(refreshCache){
13922 if(rules == null || refreshCache){
13924 var ds = doc.styleSheets;
13925 for(var i =0, len = ds.length; i < len; i++){
13927 this.cacheStyleSheet(ds[i]);
13935 * Gets an an individual CSS rule by selector(s)
13936 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13937 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13938 * @return {CSSRule} The CSS rule or null if one is not found
13940 getRule : function(selector, refreshCache){
13941 var rs = this.getRules(refreshCache);
13942 if(!(selector instanceof Array)){
13943 return rs[selector];
13945 for(var i = 0; i < selector.length; i++){
13946 if(rs[selector[i]]){
13947 return rs[selector[i]];
13955 * Updates a rule property
13956 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13957 * @param {String} property The css property
13958 * @param {String} value The new value for the property
13959 * @return {Boolean} true If a rule was found and updated
13961 updateRule : function(selector, property, value){
13962 if(!(selector instanceof Array)){
13963 var rule = this.getRule(selector);
13965 rule.style[property.replace(camelRe, camelFn)] = value;
13969 for(var i = 0; i < selector.length; i++){
13970 if(this.updateRule(selector[i], property, value)){
13980 * Ext JS Library 1.1.1
13981 * Copyright(c) 2006-2007, Ext JS, LLC.
13983 * Originally Released Under LGPL - original licence link has changed is not relivant.
13986 * <script type="text/javascript">
13992 * @class Roo.util.ClickRepeater
13993 * @extends Roo.util.Observable
13995 * A wrapper class which can be applied to any element. Fires a "click" event while the
13996 * mouse is pressed. The interval between firings may be specified in the config but
13997 * defaults to 10 milliseconds.
13999 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14001 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14002 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14003 * Similar to an autorepeat key delay.
14004 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14005 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14006 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14007 * "interval" and "delay" are ignored. "immediate" is honored.
14008 * @cfg {Boolean} preventDefault True to prevent the default click event
14009 * @cfg {Boolean} stopDefault True to stop the default click event
14012 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14013 * 2007-02-02 jvs Renamed to ClickRepeater
14014 * 2007-02-03 jvs Modifications for FF Mac and Safari
14017 * @param {String/HTMLElement/Element} el The element to listen on
14018 * @param {Object} config
14020 Roo.util.ClickRepeater = function(el, config)
14022 this.el = Roo.get(el);
14023 this.el.unselectable();
14025 Roo.apply(this, config);
14030 * Fires when the mouse button is depressed.
14031 * @param {Roo.util.ClickRepeater} this
14033 "mousedown" : true,
14036 * Fires on a specified interval during the time the element is pressed.
14037 * @param {Roo.util.ClickRepeater} this
14042 * Fires when the mouse key is released.
14043 * @param {Roo.util.ClickRepeater} this
14048 this.el.on("mousedown", this.handleMouseDown, this);
14049 if(this.preventDefault || this.stopDefault){
14050 this.el.on("click", function(e){
14051 if(this.preventDefault){
14052 e.preventDefault();
14054 if(this.stopDefault){
14060 // allow inline handler
14062 this.on("click", this.handler, this.scope || this);
14065 Roo.util.ClickRepeater.superclass.constructor.call(this);
14068 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14071 preventDefault : true,
14072 stopDefault : false,
14076 handleMouseDown : function(){
14077 clearTimeout(this.timer);
14079 if(this.pressClass){
14080 this.el.addClass(this.pressClass);
14082 this.mousedownTime = new Date();
14084 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14085 this.el.on("mouseout", this.handleMouseOut, this);
14087 this.fireEvent("mousedown", this);
14088 this.fireEvent("click", this);
14090 this.timer = this.click.defer(this.delay || this.interval, this);
14094 click : function(){
14095 this.fireEvent("click", this);
14096 this.timer = this.click.defer(this.getInterval(), this);
14100 getInterval: function(){
14101 if(!this.accelerate){
14102 return this.interval;
14104 var pressTime = this.mousedownTime.getElapsed();
14105 if(pressTime < 500){
14107 }else if(pressTime < 1700){
14109 }else if(pressTime < 2600){
14111 }else if(pressTime < 3500){
14113 }else if(pressTime < 4400){
14115 }else if(pressTime < 5300){
14117 }else if(pressTime < 6200){
14125 handleMouseOut : function(){
14126 clearTimeout(this.timer);
14127 if(this.pressClass){
14128 this.el.removeClass(this.pressClass);
14130 this.el.on("mouseover", this.handleMouseReturn, this);
14134 handleMouseReturn : function(){
14135 this.el.un("mouseover", this.handleMouseReturn);
14136 if(this.pressClass){
14137 this.el.addClass(this.pressClass);
14143 handleMouseUp : function(){
14144 clearTimeout(this.timer);
14145 this.el.un("mouseover", this.handleMouseReturn);
14146 this.el.un("mouseout", this.handleMouseOut);
14147 Roo.get(document).un("mouseup", this.handleMouseUp);
14148 this.el.removeClass(this.pressClass);
14149 this.fireEvent("mouseup", this);
14153 * Ext JS Library 1.1.1
14154 * Copyright(c) 2006-2007, Ext JS, LLC.
14156 * Originally Released Under LGPL - original licence link has changed is not relivant.
14159 * <script type="text/javascript">
14164 * @class Roo.KeyNav
14165 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14166 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14167 * way to implement custom navigation schemes for any UI component.</p>
14168 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14169 * pageUp, pageDown, del, home, end. Usage:</p>
14171 var nav = new Roo.KeyNav("my-element", {
14172 "left" : function(e){
14173 this.moveLeft(e.ctrlKey);
14175 "right" : function(e){
14176 this.moveRight(e.ctrlKey);
14178 "enter" : function(e){
14185 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14186 * @param {Object} config The config
14188 Roo.KeyNav = function(el, config){
14189 this.el = Roo.get(el);
14190 Roo.apply(this, config);
14191 if(!this.disabled){
14192 this.disabled = true;
14197 Roo.KeyNav.prototype = {
14199 * @cfg {Boolean} disabled
14200 * True to disable this KeyNav instance (defaults to false)
14204 * @cfg {String} defaultEventAction
14205 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14206 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14207 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14209 defaultEventAction: "stopEvent",
14211 * @cfg {Boolean} forceKeyDown
14212 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14213 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14214 * handle keydown instead of keypress.
14216 forceKeyDown : false,
14219 prepareEvent : function(e){
14220 var k = e.getKey();
14221 var h = this.keyToHandler[k];
14222 //if(h && this[h]){
14223 // e.stopPropagation();
14225 if(Roo.isSafari && h && k >= 37 && k <= 40){
14231 relay : function(e){
14232 var k = e.getKey();
14233 var h = this.keyToHandler[k];
14235 if(this.doRelay(e, this[h], h) !== true){
14236 e[this.defaultEventAction]();
14242 doRelay : function(e, h, hname){
14243 return h.call(this.scope || this, e);
14246 // possible handlers
14260 // quick lookup hash
14277 * Enable this KeyNav
14279 enable: function(){
14281 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14282 // the EventObject will normalize Safari automatically
14283 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14284 this.el.on("keydown", this.relay, this);
14286 this.el.on("keydown", this.prepareEvent, this);
14287 this.el.on("keypress", this.relay, this);
14289 this.disabled = false;
14294 * Disable this KeyNav
14296 disable: function(){
14297 if(!this.disabled){
14298 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14299 this.el.un("keydown", this.relay);
14301 this.el.un("keydown", this.prepareEvent);
14302 this.el.un("keypress", this.relay);
14304 this.disabled = true;
14309 * Ext JS Library 1.1.1
14310 * Copyright(c) 2006-2007, Ext JS, LLC.
14312 * Originally Released Under LGPL - original licence link has changed is not relivant.
14315 * <script type="text/javascript">
14320 * @class Roo.KeyMap
14321 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14322 * The constructor accepts the same config object as defined by {@link #addBinding}.
14323 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14324 * combination it will call the function with this signature (if the match is a multi-key
14325 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14326 * A KeyMap can also handle a string representation of keys.<br />
14329 // map one key by key code
14330 var map = new Roo.KeyMap("my-element", {
14331 key: 13, // or Roo.EventObject.ENTER
14336 // map multiple keys to one action by string
14337 var map = new Roo.KeyMap("my-element", {
14343 // map multiple keys to multiple actions by strings and array of codes
14344 var map = new Roo.KeyMap("my-element", [
14347 fn: function(){ alert("Return was pressed"); }
14350 fn: function(){ alert('a, b or c was pressed'); }
14355 fn: function(){ alert('Control + shift + tab was pressed.'); }
14359 * <b>Note: A KeyMap starts enabled</b>
14361 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14362 * @param {Object} config The config (see {@link #addBinding})
14363 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14365 Roo.KeyMap = function(el, config, eventName){
14366 this.el = Roo.get(el);
14367 this.eventName = eventName || "keydown";
14368 this.bindings = [];
14370 this.addBinding(config);
14375 Roo.KeyMap.prototype = {
14377 * True to stop the event from bubbling and prevent the default browser action if the
14378 * key was handled by the KeyMap (defaults to false)
14384 * Add a new binding to this KeyMap. The following config object properties are supported:
14386 Property Type Description
14387 ---------- --------------- ----------------------------------------------------------------------
14388 key String/Array A single keycode or an array of keycodes to handle
14389 shift Boolean True to handle key only when shift is pressed (defaults to false)
14390 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14391 alt Boolean True to handle key only when alt is pressed (defaults to false)
14392 fn Function The function to call when KeyMap finds the expected key combination
14393 scope Object The scope of the callback function
14399 var map = new Roo.KeyMap(document, {
14400 key: Roo.EventObject.ENTER,
14405 //Add a new binding to the existing KeyMap later
14413 * @param {Object/Array} config A single KeyMap config or an array of configs
14415 addBinding : function(config){
14416 if(config instanceof Array){
14417 for(var i = 0, len = config.length; i < len; i++){
14418 this.addBinding(config[i]);
14422 var keyCode = config.key,
14423 shift = config.shift,
14424 ctrl = config.ctrl,
14427 scope = config.scope;
14428 if(typeof keyCode == "string"){
14430 var keyString = keyCode.toUpperCase();
14431 for(var j = 0, len = keyString.length; j < len; j++){
14432 ks.push(keyString.charCodeAt(j));
14436 var keyArray = keyCode instanceof Array;
14437 var handler = function(e){
14438 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14439 var k = e.getKey();
14441 for(var i = 0, len = keyCode.length; i < len; i++){
14442 if(keyCode[i] == k){
14443 if(this.stopEvent){
14446 fn.call(scope || window, k, e);
14452 if(this.stopEvent){
14455 fn.call(scope || window, k, e);
14460 this.bindings.push(handler);
14464 * Shorthand for adding a single key listener
14465 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14466 * following options:
14467 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14468 * @param {Function} fn The function to call
14469 * @param {Object} scope (optional) The scope of the function
14471 on : function(key, fn, scope){
14472 var keyCode, shift, ctrl, alt;
14473 if(typeof key == "object" && !(key instanceof Array)){
14492 handleKeyDown : function(e){
14493 if(this.enabled){ //just in case
14494 var b = this.bindings;
14495 for(var i = 0, len = b.length; i < len; i++){
14496 b[i].call(this, e);
14502 * Returns true if this KeyMap is enabled
14503 * @return {Boolean}
14505 isEnabled : function(){
14506 return this.enabled;
14510 * Enables this KeyMap
14512 enable: function(){
14514 this.el.on(this.eventName, this.handleKeyDown, this);
14515 this.enabled = true;
14520 * Disable this KeyMap
14522 disable: function(){
14524 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14525 this.enabled = false;
14530 * Ext JS Library 1.1.1
14531 * Copyright(c) 2006-2007, Ext JS, LLC.
14533 * Originally Released Under LGPL - original licence link has changed is not relivant.
14536 * <script type="text/javascript">
14541 * @class Roo.util.TextMetrics
14542 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14543 * wide, in pixels, a given block of text will be.
14546 Roo.util.TextMetrics = function(){
14550 * Measures the size of the specified text
14551 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14552 * that can affect the size of the rendered text
14553 * @param {String} text The text to measure
14554 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14555 * in order to accurately measure the text height
14556 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14558 measure : function(el, text, fixedWidth){
14560 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14563 shared.setFixedWidth(fixedWidth || 'auto');
14564 return shared.getSize(text);
14568 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14569 * the overhead of multiple calls to initialize the style properties on each measurement.
14570 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14571 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14572 * in order to accurately measure the text height
14573 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14575 createInstance : function(el, fixedWidth){
14576 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14583 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14584 var ml = new Roo.Element(document.createElement('div'));
14585 document.body.appendChild(ml.dom);
14586 ml.position('absolute');
14587 ml.setLeftTop(-1000, -1000);
14591 ml.setWidth(fixedWidth);
14596 * Returns the size of the specified text based on the internal element's style and width properties
14597 * @memberOf Roo.util.TextMetrics.Instance#
14598 * @param {String} text The text to measure
14599 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14601 getSize : function(text){
14603 var s = ml.getSize();
14609 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14610 * that can affect the size of the rendered text
14611 * @memberOf Roo.util.TextMetrics.Instance#
14612 * @param {String/HTMLElement} el The element, dom node or id
14614 bind : function(el){
14616 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14621 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14622 * to set a fixed width in order to accurately measure the text height.
14623 * @memberOf Roo.util.TextMetrics.Instance#
14624 * @param {Number} width The width to set on the element
14626 setFixedWidth : function(width){
14627 ml.setWidth(width);
14631 * Returns the measured width of the specified text
14632 * @memberOf Roo.util.TextMetrics.Instance#
14633 * @param {String} text The text to measure
14634 * @return {Number} width The width in pixels
14636 getWidth : function(text){
14637 ml.dom.style.width = 'auto';
14638 return this.getSize(text).width;
14642 * Returns the measured height of the specified text. For multiline text, be sure to call
14643 * {@link #setFixedWidth} if necessary.
14644 * @memberOf Roo.util.TextMetrics.Instance#
14645 * @param {String} text The text to measure
14646 * @return {Number} height The height in pixels
14648 getHeight : function(text){
14649 return this.getSize(text).height;
14653 instance.bind(bindTo);
14658 // backwards compat
14659 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14661 * Ext JS Library 1.1.1
14662 * Copyright(c) 2006-2007, Ext JS, LLC.
14664 * Originally Released Under LGPL - original licence link has changed is not relivant.
14667 * <script type="text/javascript">
14671 * @class Roo.state.Provider
14672 * Abstract base class for state provider implementations. This class provides methods
14673 * for encoding and decoding <b>typed</b> variables including dates and defines the
14674 * Provider interface.
14676 Roo.state.Provider = function(){
14678 * @event statechange
14679 * Fires when a state change occurs.
14680 * @param {Provider} this This state provider
14681 * @param {String} key The state key which was changed
14682 * @param {String} value The encoded value for the state
14685 "statechange": true
14688 Roo.state.Provider.superclass.constructor.call(this);
14690 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14692 * Returns the current value for a key
14693 * @param {String} name The key name
14694 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14695 * @return {Mixed} The state data
14697 get : function(name, defaultValue){
14698 return typeof this.state[name] == "undefined" ?
14699 defaultValue : this.state[name];
14703 * Clears a value from the state
14704 * @param {String} name The key name
14706 clear : function(name){
14707 delete this.state[name];
14708 this.fireEvent("statechange", this, name, null);
14712 * Sets the value for a key
14713 * @param {String} name The key name
14714 * @param {Mixed} value The value to set
14716 set : function(name, value){
14717 this.state[name] = value;
14718 this.fireEvent("statechange", this, name, value);
14722 * Decodes a string previously encoded with {@link #encodeValue}.
14723 * @param {String} value The value to decode
14724 * @return {Mixed} The decoded value
14726 decodeValue : function(cookie){
14727 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14728 var matches = re.exec(unescape(cookie));
14729 if(!matches || !matches[1]) return; // non state cookie
14730 var type = matches[1];
14731 var v = matches[2];
14734 return parseFloat(v);
14736 return new Date(Date.parse(v));
14741 var values = v.split("^");
14742 for(var i = 0, len = values.length; i < len; i++){
14743 all.push(this.decodeValue(values[i]));
14748 var values = v.split("^");
14749 for(var i = 0, len = values.length; i < len; i++){
14750 var kv = values[i].split("=");
14751 all[kv[0]] = this.decodeValue(kv[1]);
14760 * Encodes a value including type information. Decode with {@link #decodeValue}.
14761 * @param {Mixed} value The value to encode
14762 * @return {String} The encoded value
14764 encodeValue : function(v){
14766 if(typeof v == "number"){
14768 }else if(typeof v == "boolean"){
14769 enc = "b:" + (v ? "1" : "0");
14770 }else if(v instanceof Date){
14771 enc = "d:" + v.toGMTString();
14772 }else if(v instanceof Array){
14774 for(var i = 0, len = v.length; i < len; i++){
14775 flat += this.encodeValue(v[i]);
14776 if(i != len-1) flat += "^";
14779 }else if(typeof v == "object"){
14782 if(typeof v[key] != "function"){
14783 flat += key + "=" + this.encodeValue(v[key]) + "^";
14786 enc = "o:" + flat.substring(0, flat.length-1);
14790 return escape(enc);
14796 * Ext JS Library 1.1.1
14797 * Copyright(c) 2006-2007, Ext JS, LLC.
14799 * Originally Released Under LGPL - original licence link has changed is not relivant.
14802 * <script type="text/javascript">
14805 * @class Roo.state.Manager
14806 * This is the global state manager. By default all components that are "state aware" check this class
14807 * for state information if you don't pass them a custom state provider. In order for this class
14808 * to be useful, it must be initialized with a provider when your application initializes.
14810 // in your initialization function
14812 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14814 // supposed you have a {@link Roo.BorderLayout}
14815 var layout = new Roo.BorderLayout(...);
14816 layout.restoreState();
14817 // or a {Roo.BasicDialog}
14818 var dialog = new Roo.BasicDialog(...);
14819 dialog.restoreState();
14823 Roo.state.Manager = function(){
14824 var provider = new Roo.state.Provider();
14828 * Configures the default state provider for your application
14829 * @param {Provider} stateProvider The state provider to set
14831 setProvider : function(stateProvider){
14832 provider = stateProvider;
14836 * Returns the current value for a key
14837 * @param {String} name The key name
14838 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14839 * @return {Mixed} The state data
14841 get : function(key, defaultValue){
14842 return provider.get(key, defaultValue);
14846 * Sets the value for a key
14847 * @param {String} name The key name
14848 * @param {Mixed} value The state data
14850 set : function(key, value){
14851 provider.set(key, value);
14855 * Clears a value from the state
14856 * @param {String} name The key name
14858 clear : function(key){
14859 provider.clear(key);
14863 * Gets the currently configured state provider
14864 * @return {Provider} The state provider
14866 getProvider : function(){
14873 * Ext JS Library 1.1.1
14874 * Copyright(c) 2006-2007, Ext JS, LLC.
14876 * Originally Released Under LGPL - original licence link has changed is not relivant.
14879 * <script type="text/javascript">
14882 * @class Roo.state.CookieProvider
14883 * @extends Roo.state.Provider
14884 * The default Provider implementation which saves state via cookies.
14887 var cp = new Roo.state.CookieProvider({
14889 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14890 domain: "roojs.com"
14892 Roo.state.Manager.setProvider(cp);
14894 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14895 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14896 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14897 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14898 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14899 * domain the page is running on including the 'www' like 'www.roojs.com')
14900 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14902 * Create a new CookieProvider
14903 * @param {Object} config The configuration object
14905 Roo.state.CookieProvider = function(config){
14906 Roo.state.CookieProvider.superclass.constructor.call(this);
14908 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14909 this.domain = null;
14910 this.secure = false;
14911 Roo.apply(this, config);
14912 this.state = this.readCookies();
14915 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14917 set : function(name, value){
14918 if(typeof value == "undefined" || value === null){
14922 this.setCookie(name, value);
14923 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14927 clear : function(name){
14928 this.clearCookie(name);
14929 Roo.state.CookieProvider.superclass.clear.call(this, name);
14933 readCookies : function(){
14935 var c = document.cookie + ";";
14936 var re = /\s?(.*?)=(.*?);/g;
14938 while((matches = re.exec(c)) != null){
14939 var name = matches[1];
14940 var value = matches[2];
14941 if(name && name.substring(0,3) == "ys-"){
14942 cookies[name.substr(3)] = this.decodeValue(value);
14949 setCookie : function(name, value){
14950 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14951 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14952 ((this.path == null) ? "" : ("; path=" + this.path)) +
14953 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14954 ((this.secure == true) ? "; secure" : "");
14958 clearCookie : function(name){
14959 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14960 ((this.path == null) ? "" : ("; path=" + this.path)) +
14961 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14962 ((this.secure == true) ? "; secure" : "");
14966 * Ext JS Library 1.1.1
14967 * Copyright(c) 2006-2007, Ext JS, LLC.
14969 * Originally Released Under LGPL - original licence link has changed is not relivant.
14972 * <script type="text/javascript">
14977 * @class Roo.ComponentMgr
14978 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14981 Roo.ComponentMgr = function(){
14982 var all = new Roo.util.MixedCollection();
14986 * Registers a component.
14987 * @param {Roo.Component} c The component
14989 register : function(c){
14994 * Unregisters a component.
14995 * @param {Roo.Component} c The component
14997 unregister : function(c){
15002 * Returns a component by id
15003 * @param {String} id The component id
15005 get : function(id){
15006 return all.get(id);
15010 * Registers a function that will be called when a specified component is added to ComponentMgr
15011 * @param {String} id The component id
15012 * @param {Funtction} fn The callback function
15013 * @param {Object} scope The scope of the callback
15015 onAvailable : function(id, fn, scope){
15016 all.on("add", function(index, o){
15018 fn.call(scope || o, o);
15019 all.un("add", fn, scope);
15026 * Ext JS Library 1.1.1
15027 * Copyright(c) 2006-2007, Ext JS, LLC.
15029 * Originally Released Under LGPL - original licence link has changed is not relivant.
15032 * <script type="text/javascript">
15036 * @class Roo.Component
15037 * @extends Roo.util.Observable
15038 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15039 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15040 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15041 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15042 * All visual components (widgets) that require rendering into a layout should subclass Component.
15044 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15045 * 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
15046 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15048 Roo.Component = function(config){
15049 config = config || {};
15050 if(config.tagName || config.dom || typeof config == "string"){ // element object
15051 config = {el: config, id: config.id || config};
15053 this.initialConfig = config;
15055 Roo.apply(this, config);
15059 * Fires after the component is disabled.
15060 * @param {Roo.Component} this
15065 * Fires after the component is enabled.
15066 * @param {Roo.Component} this
15070 * @event beforeshow
15071 * Fires before the component is shown. Return false to stop the show.
15072 * @param {Roo.Component} this
15077 * Fires after the component is shown.
15078 * @param {Roo.Component} this
15082 * @event beforehide
15083 * Fires before the component is hidden. Return false to stop the hide.
15084 * @param {Roo.Component} this
15089 * Fires after the component is hidden.
15090 * @param {Roo.Component} this
15094 * @event beforerender
15095 * Fires before the component is rendered. Return false to stop the render.
15096 * @param {Roo.Component} this
15098 beforerender : true,
15101 * Fires after the component is rendered.
15102 * @param {Roo.Component} this
15106 * @event beforedestroy
15107 * Fires before the component is destroyed. Return false to stop the destroy.
15108 * @param {Roo.Component} this
15110 beforedestroy : true,
15113 * Fires after the component is destroyed.
15114 * @param {Roo.Component} this
15119 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15121 Roo.ComponentMgr.register(this);
15122 Roo.Component.superclass.constructor.call(this);
15123 this.initComponent();
15124 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15125 this.render(this.renderTo);
15126 delete this.renderTo;
15131 Roo.Component.AUTO_ID = 1000;
15133 Roo.extend(Roo.Component, Roo.util.Observable, {
15135 * @scope Roo.Component.prototype
15137 * true if this component is hidden. Read-only.
15142 * true if this component is disabled. Read-only.
15147 * true if this component has been rendered. Read-only.
15151 /** @cfg {String} disableClass
15152 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15154 disabledClass : "x-item-disabled",
15155 /** @cfg {Boolean} allowDomMove
15156 * Whether the component can move the Dom node when rendering (defaults to true).
15158 allowDomMove : true,
15159 /** @cfg {String} hideMode
15160 * How this component should hidden. Supported values are
15161 * "visibility" (css visibility), "offsets" (negative offset position) and
15162 * "display" (css display) - defaults to "display".
15164 hideMode: 'display',
15167 ctype : "Roo.Component",
15170 * @cfg {String} actionMode
15171 * which property holds the element that used for hide() / show() / disable() / enable()
15177 getActionEl : function(){
15178 return this[this.actionMode];
15181 initComponent : Roo.emptyFn,
15183 * If this is a lazy rendering component, render it to its container element.
15184 * @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.
15186 render : function(container, position){
15187 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15188 if(!container && this.el){
15189 this.el = Roo.get(this.el);
15190 container = this.el.dom.parentNode;
15191 this.allowDomMove = false;
15193 this.container = Roo.get(container);
15194 this.rendered = true;
15195 if(position !== undefined){
15196 if(typeof position == 'number'){
15197 position = this.container.dom.childNodes[position];
15199 position = Roo.getDom(position);
15202 this.onRender(this.container, position || null);
15204 this.el.addClass(this.cls);
15208 this.el.applyStyles(this.style);
15211 this.fireEvent("render", this);
15212 this.afterRender(this.container);
15224 // default function is not really useful
15225 onRender : function(ct, position){
15227 this.el = Roo.get(this.el);
15228 if(this.allowDomMove !== false){
15229 ct.dom.insertBefore(this.el.dom, position);
15235 getAutoCreate : function(){
15236 var cfg = typeof this.autoCreate == "object" ?
15237 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15238 if(this.id && !cfg.id){
15245 afterRender : Roo.emptyFn,
15248 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15249 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15251 destroy : function(){
15252 if(this.fireEvent("beforedestroy", this) !== false){
15253 this.purgeListeners();
15254 this.beforeDestroy();
15256 this.el.removeAllListeners();
15258 if(this.actionMode == "container"){
15259 this.container.remove();
15263 Roo.ComponentMgr.unregister(this);
15264 this.fireEvent("destroy", this);
15269 beforeDestroy : function(){
15274 onDestroy : function(){
15279 * Returns the underlying {@link Roo.Element}.
15280 * @return {Roo.Element} The element
15282 getEl : function(){
15287 * Returns the id of this component.
15290 getId : function(){
15295 * Try to focus this component.
15296 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15297 * @return {Roo.Component} this
15299 focus : function(selectText){
15302 if(selectText === true){
15303 this.el.dom.select();
15318 * Disable this component.
15319 * @return {Roo.Component} this
15321 disable : function(){
15325 this.disabled = true;
15326 this.fireEvent("disable", this);
15331 onDisable : function(){
15332 this.getActionEl().addClass(this.disabledClass);
15333 this.el.dom.disabled = true;
15337 * Enable this component.
15338 * @return {Roo.Component} this
15340 enable : function(){
15344 this.disabled = false;
15345 this.fireEvent("enable", this);
15350 onEnable : function(){
15351 this.getActionEl().removeClass(this.disabledClass);
15352 this.el.dom.disabled = false;
15356 * Convenience function for setting disabled/enabled by boolean.
15357 * @param {Boolean} disabled
15359 setDisabled : function(disabled){
15360 this[disabled ? "disable" : "enable"]();
15364 * Show this component.
15365 * @return {Roo.Component} this
15368 if(this.fireEvent("beforeshow", this) !== false){
15369 this.hidden = false;
15373 this.fireEvent("show", this);
15379 onShow : function(){
15380 var ae = this.getActionEl();
15381 if(this.hideMode == 'visibility'){
15382 ae.dom.style.visibility = "visible";
15383 }else if(this.hideMode == 'offsets'){
15384 ae.removeClass('x-hidden');
15386 ae.dom.style.display = "";
15391 * Hide this component.
15392 * @return {Roo.Component} this
15395 if(this.fireEvent("beforehide", this) !== false){
15396 this.hidden = true;
15400 this.fireEvent("hide", this);
15406 onHide : function(){
15407 var ae = this.getActionEl();
15408 if(this.hideMode == 'visibility'){
15409 ae.dom.style.visibility = "hidden";
15410 }else if(this.hideMode == 'offsets'){
15411 ae.addClass('x-hidden');
15413 ae.dom.style.display = "none";
15418 * Convenience function to hide or show this component by boolean.
15419 * @param {Boolean} visible True to show, false to hide
15420 * @return {Roo.Component} this
15422 setVisible: function(visible){
15432 * Returns true if this component is visible.
15434 isVisible : function(){
15435 return this.getActionEl().isVisible();
15438 cloneConfig : function(overrides){
15439 overrides = overrides || {};
15440 var id = overrides.id || Roo.id();
15441 var cfg = Roo.applyIf(overrides, this.initialConfig);
15442 cfg.id = id; // prevent dup id
15443 return new this.constructor(cfg);
15447 * Ext JS Library 1.1.1
15448 * Copyright(c) 2006-2007, Ext JS, LLC.
15450 * Originally Released Under LGPL - original licence link has changed is not relivant.
15453 * <script type="text/javascript">
15457 * @class Roo.BoxComponent
15458 * @extends Roo.Component
15459 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15460 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15461 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15462 * layout containers.
15464 * @param {Roo.Element/String/Object} config The configuration options.
15466 Roo.BoxComponent = function(config){
15467 Roo.Component.call(this, config);
15471 * Fires after the component is resized.
15472 * @param {Roo.Component} this
15473 * @param {Number} adjWidth The box-adjusted width that was set
15474 * @param {Number} adjHeight The box-adjusted height that was set
15475 * @param {Number} rawWidth The width that was originally specified
15476 * @param {Number} rawHeight The height that was originally specified
15481 * Fires after the component is moved.
15482 * @param {Roo.Component} this
15483 * @param {Number} x The new x position
15484 * @param {Number} y The new y position
15490 Roo.extend(Roo.BoxComponent, Roo.Component, {
15491 // private, set in afterRender to signify that the component has been rendered
15493 // private, used to defer height settings to subclasses
15494 deferHeight: false,
15495 /** @cfg {Number} width
15496 * width (optional) size of component
15498 /** @cfg {Number} height
15499 * height (optional) size of component
15503 * Sets the width and height of the component. This method fires the resize event. This method can accept
15504 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15505 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15506 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15507 * @return {Roo.BoxComponent} this
15509 setSize : function(w, h){
15510 // support for standard size objects
15511 if(typeof w == 'object'){
15516 if(!this.boxReady){
15522 // prevent recalcs when not needed
15523 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15526 this.lastSize = {width: w, height: h};
15528 var adj = this.adjustSize(w, h);
15529 var aw = adj.width, ah = adj.height;
15530 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15531 var rz = this.getResizeEl();
15532 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15533 rz.setSize(aw, ah);
15534 }else if(!this.deferHeight && ah !== undefined){
15536 }else if(aw !== undefined){
15539 this.onResize(aw, ah, w, h);
15540 this.fireEvent('resize', this, aw, ah, w, h);
15546 * Gets the current size of the component's underlying element.
15547 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15549 getSize : function(){
15550 return this.el.getSize();
15554 * Gets the current XY position of the component's underlying element.
15555 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15556 * @return {Array} The XY position of the element (e.g., [100, 200])
15558 getPosition : function(local){
15559 if(local === true){
15560 return [this.el.getLeft(true), this.el.getTop(true)];
15562 return this.xy || this.el.getXY();
15566 * Gets the current box measurements of the component's underlying element.
15567 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15568 * @returns {Object} box An object in the format {x, y, width, height}
15570 getBox : function(local){
15571 var s = this.el.getSize();
15573 s.x = this.el.getLeft(true);
15574 s.y = this.el.getTop(true);
15576 var xy = this.xy || this.el.getXY();
15584 * Sets the current box measurements of the component's underlying element.
15585 * @param {Object} box An object in the format {x, y, width, height}
15586 * @returns {Roo.BoxComponent} this
15588 updateBox : function(box){
15589 this.setSize(box.width, box.height);
15590 this.setPagePosition(box.x, box.y);
15595 getResizeEl : function(){
15596 return this.resizeEl || this.el;
15600 getPositionEl : function(){
15601 return this.positionEl || this.el;
15605 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15606 * This method fires the move event.
15607 * @param {Number} left The new left
15608 * @param {Number} top The new top
15609 * @returns {Roo.BoxComponent} this
15611 setPosition : function(x, y){
15614 if(!this.boxReady){
15617 var adj = this.adjustPosition(x, y);
15618 var ax = adj.x, ay = adj.y;
15620 var el = this.getPositionEl();
15621 if(ax !== undefined || ay !== undefined){
15622 if(ax !== undefined && ay !== undefined){
15623 el.setLeftTop(ax, ay);
15624 }else if(ax !== undefined){
15626 }else if(ay !== undefined){
15629 this.onPosition(ax, ay);
15630 this.fireEvent('move', this, ax, ay);
15636 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15637 * This method fires the move event.
15638 * @param {Number} x The new x position
15639 * @param {Number} y The new y position
15640 * @returns {Roo.BoxComponent} this
15642 setPagePosition : function(x, y){
15645 if(!this.boxReady){
15648 if(x === undefined || y === undefined){ // cannot translate undefined points
15651 var p = this.el.translatePoints(x, y);
15652 this.setPosition(p.left, p.top);
15657 onRender : function(ct, position){
15658 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15660 this.resizeEl = Roo.get(this.resizeEl);
15662 if(this.positionEl){
15663 this.positionEl = Roo.get(this.positionEl);
15668 afterRender : function(){
15669 Roo.BoxComponent.superclass.afterRender.call(this);
15670 this.boxReady = true;
15671 this.setSize(this.width, this.height);
15672 if(this.x || this.y){
15673 this.setPosition(this.x, this.y);
15675 if(this.pageX || this.pageY){
15676 this.setPagePosition(this.pageX, this.pageY);
15681 * Force the component's size to recalculate based on the underlying element's current height and width.
15682 * @returns {Roo.BoxComponent} this
15684 syncSize : function(){
15685 delete this.lastSize;
15686 this.setSize(this.el.getWidth(), this.el.getHeight());
15691 * Called after the component is resized, this method is empty by default but can be implemented by any
15692 * subclass that needs to perform custom logic after a resize occurs.
15693 * @param {Number} adjWidth The box-adjusted width that was set
15694 * @param {Number} adjHeight The box-adjusted height that was set
15695 * @param {Number} rawWidth The width that was originally specified
15696 * @param {Number} rawHeight The height that was originally specified
15698 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15703 * Called after the component is moved, this method is empty by default but can be implemented by any
15704 * subclass that needs to perform custom logic after a move occurs.
15705 * @param {Number} x The new x position
15706 * @param {Number} y The new y position
15708 onPosition : function(x, y){
15713 adjustSize : function(w, h){
15714 if(this.autoWidth){
15717 if(this.autoHeight){
15720 return {width : w, height: h};
15724 adjustPosition : function(x, y){
15725 return {x : x, y: y};
15728 * Original code for Roojs - LGPL
15729 * <script type="text/javascript">
15733 * @class Roo.XComponent
15734 * A delayed Element creator...
15735 * Or a way to group chunks of interface together.
15737 * Mypart.xyx = new Roo.XComponent({
15739 parent : 'Mypart.xyz', // empty == document.element.!!
15743 disabled : function() {}
15745 tree : function() { // return an tree of xtype declared components
15749 xtype : 'NestedLayoutPanel',
15756 * It can be used to build a big heiracy, with parent etc.
15757 * or you can just use this to render a single compoent to a dom element
15758 * MYPART.render(Roo.Element | String(id) | dom_element )
15760 * @extends Roo.util.Observable
15762 * @param cfg {Object} configuration of component
15765 Roo.XComponent = function(cfg) {
15766 Roo.apply(this, cfg);
15770 * Fires when this the componnt is built
15771 * @param {Roo.XComponent} c the component
15776 this.region = this.region || 'center'; // default..
15777 Roo.XComponent.register(this);
15778 this.modules = false;
15779 this.el = false; // where the layout goes..
15783 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15786 * The created element (with Roo.factory())
15787 * @type {Roo.Layout}
15793 * for BC - use el in new code
15794 * @type {Roo.Layout}
15800 * for BC - use el in new code
15801 * @type {Roo.Layout}
15806 * @cfg {Function|boolean} disabled
15807 * If this module is disabled by some rule, return true from the funtion
15812 * @cfg {String} parent
15813 * Name of parent element which it get xtype added to..
15818 * @cfg {String} order
15819 * Used to set the order in which elements are created (usefull for multiple tabs)
15824 * @cfg {String} name
15825 * String to display while loading.
15829 * @cfg {String} region
15830 * Region to render component to (defaults to center)
15835 * @cfg {Array} items
15836 * A single item array - the first element is the root of the tree..
15837 * It's done this way to stay compatible with the Xtype system...
15843 * The method that retuns the tree of parts that make up this compoennt
15850 * render element to dom or tree
15851 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15854 render : function(el)
15858 var hp = this.parent ? 1 : 0;
15860 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15861 // if parent is a '#.....' string, then let's use that..
15862 var ename = this.parent.substr(1)
15863 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
15864 el = Roo.get(ename);
15865 if (!el && !this.parent) {
15866 Roo.log("Warning - element can not be found :#" + ename );
15870 var tree = this._tree ? this._tree() : this.tree();
15872 // altertive root elements ??? - we need a better way to indicate these.
15873 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15874 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15876 if (!this.parent && is_alt) {
15877 //el = Roo.get(document.body);
15878 this.parent = { el : true };
15883 if (!this.parent) {
15885 Roo.log("no parent - creating one");
15887 el = el ? Roo.get(el) : false;
15889 // it's a top level one..
15891 el : new Roo.BorderLayout(el || document.body, {
15897 tabPosition: 'top',
15898 //resizeTabs: true,
15899 alwaysShowTabs: el && hp? false : true,
15900 hideTabs: el || !hp ? true : false,
15907 if (!this.parent.el) {
15908 // probably an old style ctor, which has been disabled.
15912 // The 'tree' method is '_tree now'
15914 tree.region = tree.region || this.region;
15916 if (this.parent.el === true) {
15917 // bootstrap... - body..
15918 this.parent.el = Roo.factory(tree);
15921 this.el = this.parent.el.addxtype(tree);
15922 this.fireEvent('built', this);
15924 this.panel = this.el;
15925 this.layout = this.panel.layout;
15926 this.parentLayout = this.parent.layout || false;
15932 Roo.apply(Roo.XComponent, {
15934 * @property hideProgress
15935 * true to disable the building progress bar.. usefull on single page renders.
15938 hideProgress : false,
15940 * @property buildCompleted
15941 * True when the builder has completed building the interface.
15944 buildCompleted : false,
15947 * @property topModule
15948 * the upper most module - uses document.element as it's constructor.
15955 * @property modules
15956 * array of modules to be created by registration system.
15957 * @type {Array} of Roo.XComponent
15962 * @property elmodules
15963 * array of modules to be created by which use #ID
15964 * @type {Array} of Roo.XComponent
15970 * @property build_from_html
15971 * Build elements from html - used by bootstrap HTML stuff
15972 * - this is cleared after build is completed
15973 * @type {boolean} true (default false)
15976 build_from_html : false,
15979 * Register components to be built later.
15981 * This solves the following issues
15982 * - Building is not done on page load, but after an authentication process has occured.
15983 * - Interface elements are registered on page load
15984 * - Parent Interface elements may not be loaded before child, so this handles that..
15991 module : 'Pman.Tab.projectMgr',
15993 parent : 'Pman.layout',
15994 disabled : false, // or use a function..
15997 * * @param {Object} details about module
15999 register : function(obj) {
16001 Roo.XComponent.event.fireEvent('register', obj);
16002 switch(typeof(obj.disabled) ) {
16008 if ( obj.disabled() ) {
16014 if (obj.disabled) {
16020 this.modules.push(obj);
16024 * convert a string to an object..
16025 * eg. 'AAA.BBB' -> finds AAA.BBB
16029 toObject : function(str)
16031 if (!str || typeof(str) == 'object') {
16034 if (str.substring(0,1) == '#') {
16038 var ar = str.split('.');
16043 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16045 throw "Module not found : " + str;
16049 throw "Module not found : " + str;
16051 Roo.each(ar, function(e) {
16052 if (typeof(o[e]) == 'undefined') {
16053 throw "Module not found : " + str;
16064 * move modules into their correct place in the tree..
16067 preBuild : function ()
16070 Roo.each(this.modules , function (obj)
16072 Roo.XComponent.event.fireEvent('beforebuild', obj);
16074 var opar = obj.parent;
16076 obj.parent = this.toObject(opar);
16078 Roo.log("parent:toObject failed: " + e.toString());
16083 Roo.debug && Roo.log("GOT top level module");
16084 Roo.debug && Roo.log(obj);
16085 obj.modules = new Roo.util.MixedCollection(false,
16086 function(o) { return o.order + '' }
16088 this.topModule = obj;
16091 // parent is a string (usually a dom element name..)
16092 if (typeof(obj.parent) == 'string') {
16093 this.elmodules.push(obj);
16096 if (obj.parent.constructor != Roo.XComponent) {
16097 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16099 if (!obj.parent.modules) {
16100 obj.parent.modules = new Roo.util.MixedCollection(false,
16101 function(o) { return o.order + '' }
16104 if (obj.parent.disabled) {
16105 obj.disabled = true;
16107 obj.parent.modules.add(obj);
16112 * make a list of modules to build.
16113 * @return {Array} list of modules.
16116 buildOrder : function()
16119 var cmp = function(a,b) {
16120 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16122 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16123 throw "No top level modules to build";
16126 // make a flat list in order of modules to build.
16127 var mods = this.topModule ? [ this.topModule ] : [];
16130 // elmodules (is a list of DOM based modules )
16131 Roo.each(this.elmodules, function(e) {
16133 if (!this.topModule &&
16134 typeof(e.parent) == 'string' &&
16135 e.parent.substring(0,1) == '#' &&
16136 Roo.get(e.parent.substr(1))
16139 _this.topModule = e;
16145 // add modules to their parents..
16146 var addMod = function(m) {
16147 Roo.debug && Roo.log("build Order: add: " + m.name);
16150 if (m.modules && !m.disabled) {
16151 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16152 m.modules.keySort('ASC', cmp );
16153 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16155 m.modules.each(addMod);
16157 Roo.debug && Roo.log("build Order: no child modules");
16159 // not sure if this is used any more..
16161 m.finalize.name = m.name + " (clean up) ";
16162 mods.push(m.finalize);
16166 if (this.topModule && this.topModule.modules) {
16167 this.topModule.modules.keySort('ASC', cmp );
16168 this.topModule.modules.each(addMod);
16174 * Build the registered modules.
16175 * @param {Object} parent element.
16176 * @param {Function} optional method to call after module has been added.
16180 build : function(opts)
16183 if (typeof(opts) != 'undefined') {
16184 Roo.apply(this,opts);
16188 var mods = this.buildOrder();
16190 //this.allmods = mods;
16191 //Roo.debug && Roo.log(mods);
16193 if (!mods.length) { // should not happen
16194 throw "NO modules!!!";
16198 var msg = "Building Interface...";
16199 // flash it up as modal - so we store the mask!?
16200 if (!this.hideProgress && Roo.MessageBox) {
16201 Roo.MessageBox.show({ title: 'loading' });
16202 Roo.MessageBox.show({
16203 title: "Please wait...",
16212 var total = mods.length;
16215 var progressRun = function() {
16216 if (!mods.length) {
16217 Roo.debug && Roo.log('hide?');
16218 if (!this.hideProgress && Roo.MessageBox) {
16219 Roo.MessageBox.hide();
16221 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16223 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16229 var m = mods.shift();
16232 Roo.debug && Roo.log(m);
16233 // not sure if this is supported any more.. - modules that are are just function
16234 if (typeof(m) == 'function') {
16236 return progressRun.defer(10, _this);
16240 msg = "Building Interface " + (total - mods.length) +
16242 (m.name ? (' - ' + m.name) : '');
16243 Roo.debug && Roo.log(msg);
16244 if (!this.hideProgress && Roo.MessageBox) {
16245 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16249 // is the module disabled?
16250 var disabled = (typeof(m.disabled) == 'function') ?
16251 m.disabled.call(m.module.disabled) : m.disabled;
16255 return progressRun(); // we do not update the display!
16263 // it's 10 on top level, and 1 on others??? why...
16264 return progressRun.defer(10, _this);
16267 progressRun.defer(1, _this);
16281 * wrapper for event.on - aliased later..
16282 * Typically use to register a event handler for register:
16284 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16293 Roo.XComponent.event = new Roo.util.Observable({
16297 * Fires when an Component is registered,
16298 * set the disable property on the Component to stop registration.
16299 * @param {Roo.XComponent} c the component being registerd.
16304 * @event beforebuild
16305 * Fires before each Component is built
16306 * can be used to apply permissions.
16307 * @param {Roo.XComponent} c the component being registerd.
16310 'beforebuild' : true,
16312 * @event buildcomplete
16313 * Fires on the top level element when all elements have been built
16314 * @param {Roo.XComponent} the top level component.
16316 'buildcomplete' : true
16321 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16324 * Ext JS Library 1.1.1
16325 * Copyright(c) 2006-2007, Ext JS, LLC.
16327 * Originally Released Under LGPL - original licence link has changed is not relivant.
16330 * <script type="text/javascript">
16336 * These classes are derivatives of the similarly named classes in the YUI Library.
16337 * The original license:
16338 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16339 * Code licensed under the BSD License:
16340 * http://developer.yahoo.net/yui/license.txt
16345 var Event=Roo.EventManager;
16346 var Dom=Roo.lib.Dom;
16349 * @class Roo.dd.DragDrop
16350 * @extends Roo.util.Observable
16351 * Defines the interface and base operation of items that that can be
16352 * dragged or can be drop targets. It was designed to be extended, overriding
16353 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16354 * Up to three html elements can be associated with a DragDrop instance:
16356 * <li>linked element: the element that is passed into the constructor.
16357 * This is the element which defines the boundaries for interaction with
16358 * other DragDrop objects.</li>
16359 * <li>handle element(s): The drag operation only occurs if the element that
16360 * was clicked matches a handle element. By default this is the linked
16361 * element, but there are times that you will want only a portion of the
16362 * linked element to initiate the drag operation, and the setHandleElId()
16363 * method provides a way to define this.</li>
16364 * <li>drag element: this represents the element that would be moved along
16365 * with the cursor during a drag operation. By default, this is the linked
16366 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16367 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16370 * This class should not be instantiated until the onload event to ensure that
16371 * the associated elements are available.
16372 * The following would define a DragDrop obj that would interact with any
16373 * other DragDrop obj in the "group1" group:
16375 * dd = new Roo.dd.DragDrop("div1", "group1");
16377 * Since none of the event handlers have been implemented, nothing would
16378 * actually happen if you were to run the code above. Normally you would
16379 * override this class or one of the default implementations, but you can
16380 * also override the methods you want on an instance of the class...
16382 * dd.onDragDrop = function(e, id) {
16383 * alert("dd was dropped on " + id);
16387 * @param {String} id of the element that is linked to this instance
16388 * @param {String} sGroup the group of related DragDrop objects
16389 * @param {object} config an object containing configurable attributes
16390 * Valid properties for DragDrop:
16391 * padding, isTarget, maintainOffset, primaryButtonOnly
16393 Roo.dd.DragDrop = function(id, sGroup, config) {
16395 this.init(id, sGroup, config);
16400 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16403 * The id of the element associated with this object. This is what we
16404 * refer to as the "linked element" because the size and position of
16405 * this element is used to determine when the drag and drop objects have
16413 * Configuration attributes passed into the constructor
16420 * The id of the element that will be dragged. By default this is same
16421 * as the linked element , but could be changed to another element. Ex:
16423 * @property dragElId
16430 * the id of the element that initiates the drag operation. By default
16431 * this is the linked element, but could be changed to be a child of this
16432 * element. This lets us do things like only starting the drag when the
16433 * header element within the linked html element is clicked.
16434 * @property handleElId
16441 * An associative array of HTML tags that will be ignored if clicked.
16442 * @property invalidHandleTypes
16443 * @type {string: string}
16445 invalidHandleTypes: null,
16448 * An associative array of ids for elements that will be ignored if clicked
16449 * @property invalidHandleIds
16450 * @type {string: string}
16452 invalidHandleIds: null,
16455 * An indexted array of css class names for elements that will be ignored
16457 * @property invalidHandleClasses
16460 invalidHandleClasses: null,
16463 * The linked element's absolute X position at the time the drag was
16465 * @property startPageX
16472 * The linked element's absolute X position at the time the drag was
16474 * @property startPageY
16481 * The group defines a logical collection of DragDrop objects that are
16482 * related. Instances only get events when interacting with other
16483 * DragDrop object in the same group. This lets us define multiple
16484 * groups using a single DragDrop subclass if we want.
16486 * @type {string: string}
16491 * Individual drag/drop instances can be locked. This will prevent
16492 * onmousedown start drag.
16500 * Lock this instance
16503 lock: function() { this.locked = true; },
16506 * Unlock this instace
16509 unlock: function() { this.locked = false; },
16512 * By default, all insances can be a drop target. This can be disabled by
16513 * setting isTarget to false.
16520 * The padding configured for this drag and drop object for calculating
16521 * the drop zone intersection with this object.
16528 * Cached reference to the linked element
16529 * @property _domRef
16535 * Internal typeof flag
16536 * @property __ygDragDrop
16539 __ygDragDrop: true,
16542 * Set to true when horizontal contraints are applied
16543 * @property constrainX
16550 * Set to true when vertical contraints are applied
16551 * @property constrainY
16558 * The left constraint
16566 * The right constraint
16574 * The up constraint
16583 * The down constraint
16591 * Maintain offsets when we resetconstraints. Set to true when you want
16592 * the position of the element relative to its parent to stay the same
16593 * when the page changes
16595 * @property maintainOffset
16598 maintainOffset: false,
16601 * Array of pixel locations the element will snap to if we specified a
16602 * horizontal graduation/interval. This array is generated automatically
16603 * when you define a tick interval.
16610 * Array of pixel locations the element will snap to if we specified a
16611 * vertical graduation/interval. This array is generated automatically
16612 * when you define a tick interval.
16619 * By default the drag and drop instance will only respond to the primary
16620 * button click (left button for a right-handed mouse). Set to true to
16621 * allow drag and drop to start with any mouse click that is propogated
16623 * @property primaryButtonOnly
16626 primaryButtonOnly: true,
16629 * The availabe property is false until the linked dom element is accessible.
16630 * @property available
16636 * By default, drags can only be initiated if the mousedown occurs in the
16637 * region the linked element is. This is done in part to work around a
16638 * bug in some browsers that mis-report the mousedown if the previous
16639 * mouseup happened outside of the window. This property is set to true
16640 * if outer handles are defined.
16642 * @property hasOuterHandles
16646 hasOuterHandles: false,
16649 * Code that executes immediately before the startDrag event
16650 * @method b4StartDrag
16653 b4StartDrag: function(x, y) { },
16656 * Abstract method called after a drag/drop object is clicked
16657 * and the drag or mousedown time thresholds have beeen met.
16658 * @method startDrag
16659 * @param {int} X click location
16660 * @param {int} Y click location
16662 startDrag: function(x, y) { /* override this */ },
16665 * Code that executes immediately before the onDrag event
16669 b4Drag: function(e) { },
16672 * Abstract method called during the onMouseMove event while dragging an
16675 * @param {Event} e the mousemove event
16677 onDrag: function(e) { /* override this */ },
16680 * Abstract method called when this element fist begins hovering over
16681 * another DragDrop obj
16682 * @method onDragEnter
16683 * @param {Event} e the mousemove event
16684 * @param {String|DragDrop[]} id In POINT mode, the element
16685 * id this is hovering over. In INTERSECT mode, an array of one or more
16686 * dragdrop items being hovered over.
16688 onDragEnter: function(e, id) { /* override this */ },
16691 * Code that executes immediately before the onDragOver event
16692 * @method b4DragOver
16695 b4DragOver: function(e) { },
16698 * Abstract method called when this element is hovering over another
16700 * @method onDragOver
16701 * @param {Event} e the mousemove event
16702 * @param {String|DragDrop[]} id In POINT mode, the element
16703 * id this is hovering over. In INTERSECT mode, an array of dd items
16704 * being hovered over.
16706 onDragOver: function(e, id) { /* override this */ },
16709 * Code that executes immediately before the onDragOut event
16710 * @method b4DragOut
16713 b4DragOut: function(e) { },
16716 * Abstract method called when we are no longer hovering over an element
16717 * @method onDragOut
16718 * @param {Event} e the mousemove event
16719 * @param {String|DragDrop[]} id In POINT mode, the element
16720 * id this was hovering over. In INTERSECT mode, an array of dd items
16721 * that the mouse is no longer over.
16723 onDragOut: function(e, id) { /* override this */ },
16726 * Code that executes immediately before the onDragDrop event
16727 * @method b4DragDrop
16730 b4DragDrop: function(e) { },
16733 * Abstract method called when this item is dropped on another DragDrop
16735 * @method onDragDrop
16736 * @param {Event} e the mouseup event
16737 * @param {String|DragDrop[]} id In POINT mode, the element
16738 * id this was dropped on. In INTERSECT mode, an array of dd items this
16741 onDragDrop: function(e, id) { /* override this */ },
16744 * Abstract method called when this item is dropped on an area with no
16746 * @method onInvalidDrop
16747 * @param {Event} e the mouseup event
16749 onInvalidDrop: function(e) { /* override this */ },
16752 * Code that executes immediately before the endDrag event
16753 * @method b4EndDrag
16756 b4EndDrag: function(e) { },
16759 * Fired when we are done dragging the object
16761 * @param {Event} e the mouseup event
16763 endDrag: function(e) { /* override this */ },
16766 * Code executed immediately before the onMouseDown event
16767 * @method b4MouseDown
16768 * @param {Event} e the mousedown event
16771 b4MouseDown: function(e) { },
16774 * Event handler that fires when a drag/drop obj gets a mousedown
16775 * @method onMouseDown
16776 * @param {Event} e the mousedown event
16778 onMouseDown: function(e) { /* override this */ },
16781 * Event handler that fires when a drag/drop obj gets a mouseup
16782 * @method onMouseUp
16783 * @param {Event} e the mouseup event
16785 onMouseUp: function(e) { /* override this */ },
16788 * Override the onAvailable method to do what is needed after the initial
16789 * position was determined.
16790 * @method onAvailable
16792 onAvailable: function () {
16796 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16799 defaultPadding : {left:0, right:0, top:0, bottom:0},
16802 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16806 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16807 { dragElId: "existingProxyDiv" });
16808 dd.startDrag = function(){
16809 this.constrainTo("parent-id");
16812 * Or you can initalize it using the {@link Roo.Element} object:
16814 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16815 startDrag : function(){
16816 this.constrainTo("parent-id");
16820 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16821 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16822 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16823 * an object containing the sides to pad. For example: {right:10, bottom:10}
16824 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16826 constrainTo : function(constrainTo, pad, inContent){
16827 if(typeof pad == "number"){
16828 pad = {left: pad, right:pad, top:pad, bottom:pad};
16830 pad = pad || this.defaultPadding;
16831 var b = Roo.get(this.getEl()).getBox();
16832 var ce = Roo.get(constrainTo);
16833 var s = ce.getScroll();
16834 var c, cd = ce.dom;
16835 if(cd == document.body){
16836 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16839 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16843 var topSpace = b.y - c.y;
16844 var leftSpace = b.x - c.x;
16846 this.resetConstraints();
16847 this.setXConstraint(leftSpace - (pad.left||0), // left
16848 c.width - leftSpace - b.width - (pad.right||0) //right
16850 this.setYConstraint(topSpace - (pad.top||0), //top
16851 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16856 * Returns a reference to the linked element
16858 * @return {HTMLElement} the html element
16860 getEl: function() {
16861 if (!this._domRef) {
16862 this._domRef = Roo.getDom(this.id);
16865 return this._domRef;
16869 * Returns a reference to the actual element to drag. By default this is
16870 * the same as the html element, but it can be assigned to another
16871 * element. An example of this can be found in Roo.dd.DDProxy
16872 * @method getDragEl
16873 * @return {HTMLElement} the html element
16875 getDragEl: function() {
16876 return Roo.getDom(this.dragElId);
16880 * Sets up the DragDrop object. Must be called in the constructor of any
16881 * Roo.dd.DragDrop subclass
16883 * @param id the id of the linked element
16884 * @param {String} sGroup the group of related items
16885 * @param {object} config configuration attributes
16887 init: function(id, sGroup, config) {
16888 this.initTarget(id, sGroup, config);
16889 if (!Roo.isTouch) {
16890 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16892 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16893 // Event.on(this.id, "selectstart", Event.preventDefault);
16897 * Initializes Targeting functionality only... the object does not
16898 * get a mousedown handler.
16899 * @method initTarget
16900 * @param id the id of the linked element
16901 * @param {String} sGroup the group of related items
16902 * @param {object} config configuration attributes
16904 initTarget: function(id, sGroup, config) {
16906 // configuration attributes
16907 this.config = config || {};
16909 // create a local reference to the drag and drop manager
16910 this.DDM = Roo.dd.DDM;
16911 // initialize the groups array
16914 // assume that we have an element reference instead of an id if the
16915 // parameter is not a string
16916 if (typeof id !== "string") {
16923 // add to an interaction group
16924 this.addToGroup((sGroup) ? sGroup : "default");
16926 // We don't want to register this as the handle with the manager
16927 // so we just set the id rather than calling the setter.
16928 this.handleElId = id;
16930 // the linked element is the element that gets dragged by default
16931 this.setDragElId(id);
16933 // by default, clicked anchors will not start drag operations.
16934 this.invalidHandleTypes = { A: "A" };
16935 this.invalidHandleIds = {};
16936 this.invalidHandleClasses = [];
16938 this.applyConfig();
16940 this.handleOnAvailable();
16944 * Applies the configuration parameters that were passed into the constructor.
16945 * This is supposed to happen at each level through the inheritance chain. So
16946 * a DDProxy implentation will execute apply config on DDProxy, DD, and
16947 * DragDrop in order to get all of the parameters that are available in
16949 * @method applyConfig
16951 applyConfig: function() {
16953 // configurable properties:
16954 // padding, isTarget, maintainOffset, primaryButtonOnly
16955 this.padding = this.config.padding || [0, 0, 0, 0];
16956 this.isTarget = (this.config.isTarget !== false);
16957 this.maintainOffset = (this.config.maintainOffset);
16958 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
16963 * Executed when the linked element is available
16964 * @method handleOnAvailable
16967 handleOnAvailable: function() {
16968 this.available = true;
16969 this.resetConstraints();
16970 this.onAvailable();
16974 * Configures the padding for the target zone in px. Effectively expands
16975 * (or reduces) the virtual object size for targeting calculations.
16976 * Supports css-style shorthand; if only one parameter is passed, all sides
16977 * will have that padding, and if only two are passed, the top and bottom
16978 * will have the first param, the left and right the second.
16979 * @method setPadding
16980 * @param {int} iTop Top pad
16981 * @param {int} iRight Right pad
16982 * @param {int} iBot Bot pad
16983 * @param {int} iLeft Left pad
16985 setPadding: function(iTop, iRight, iBot, iLeft) {
16986 // this.padding = [iLeft, iRight, iTop, iBot];
16987 if (!iRight && 0 !== iRight) {
16988 this.padding = [iTop, iTop, iTop, iTop];
16989 } else if (!iBot && 0 !== iBot) {
16990 this.padding = [iTop, iRight, iTop, iRight];
16992 this.padding = [iTop, iRight, iBot, iLeft];
16997 * Stores the initial placement of the linked element.
16998 * @method setInitialPosition
16999 * @param {int} diffX the X offset, default 0
17000 * @param {int} diffY the Y offset, default 0
17002 setInitPosition: function(diffX, diffY) {
17003 var el = this.getEl();
17005 if (!this.DDM.verifyEl(el)) {
17009 var dx = diffX || 0;
17010 var dy = diffY || 0;
17012 var p = Dom.getXY( el );
17014 this.initPageX = p[0] - dx;
17015 this.initPageY = p[1] - dy;
17017 this.lastPageX = p[0];
17018 this.lastPageY = p[1];
17021 this.setStartPosition(p);
17025 * Sets the start position of the element. This is set when the obj
17026 * is initialized, the reset when a drag is started.
17027 * @method setStartPosition
17028 * @param pos current position (from previous lookup)
17031 setStartPosition: function(pos) {
17032 var p = pos || Dom.getXY( this.getEl() );
17033 this.deltaSetXY = null;
17035 this.startPageX = p[0];
17036 this.startPageY = p[1];
17040 * Add this instance to a group of related drag/drop objects. All
17041 * instances belong to at least one group, and can belong to as many
17042 * groups as needed.
17043 * @method addToGroup
17044 * @param sGroup {string} the name of the group
17046 addToGroup: function(sGroup) {
17047 this.groups[sGroup] = true;
17048 this.DDM.regDragDrop(this, sGroup);
17052 * Remove's this instance from the supplied interaction group
17053 * @method removeFromGroup
17054 * @param {string} sGroup The group to drop
17056 removeFromGroup: function(sGroup) {
17057 if (this.groups[sGroup]) {
17058 delete this.groups[sGroup];
17061 this.DDM.removeDDFromGroup(this, sGroup);
17065 * Allows you to specify that an element other than the linked element
17066 * will be moved with the cursor during a drag
17067 * @method setDragElId
17068 * @param id {string} the id of the element that will be used to initiate the drag
17070 setDragElId: function(id) {
17071 this.dragElId = id;
17075 * Allows you to specify a child of the linked element that should be
17076 * used to initiate the drag operation. An example of this would be if
17077 * you have a content div with text and links. Clicking anywhere in the
17078 * content area would normally start the drag operation. Use this method
17079 * to specify that an element inside of the content div is the element
17080 * that starts the drag operation.
17081 * @method setHandleElId
17082 * @param id {string} the id of the element that will be used to
17083 * initiate the drag.
17085 setHandleElId: function(id) {
17086 if (typeof id !== "string") {
17089 this.handleElId = id;
17090 this.DDM.regHandle(this.id, id);
17094 * Allows you to set an element outside of the linked element as a drag
17096 * @method setOuterHandleElId
17097 * @param id the id of the element that will be used to initiate the drag
17099 setOuterHandleElId: function(id) {
17100 if (typeof id !== "string") {
17103 Event.on(id, "mousedown",
17104 this.handleMouseDown, this);
17105 this.setHandleElId(id);
17107 this.hasOuterHandles = true;
17111 * Remove all drag and drop hooks for this element
17114 unreg: function() {
17115 Event.un(this.id, "mousedown",
17116 this.handleMouseDown);
17117 Event.un(this.id, "touchstart",
17118 this.handleMouseDown);
17119 this._domRef = null;
17120 this.DDM._remove(this);
17123 destroy : function(){
17128 * Returns true if this instance is locked, or the drag drop mgr is locked
17129 * (meaning that all drag/drop is disabled on the page.)
17131 * @return {boolean} true if this obj or all drag/drop is locked, else
17134 isLocked: function() {
17135 return (this.DDM.isLocked() || this.locked);
17139 * Fired when this object is clicked
17140 * @method handleMouseDown
17142 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17145 handleMouseDown: function(e, oDD){
17147 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17148 //Roo.log('not touch/ button !=0');
17151 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17152 return; // double touch..
17156 if (this.isLocked()) {
17157 //Roo.log('locked');
17161 this.DDM.refreshCache(this.groups);
17162 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17163 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17164 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17165 //Roo.log('no outer handes or not over target');
17168 // Roo.log('check validator');
17169 if (this.clickValidator(e)) {
17170 // Roo.log('validate success');
17171 // set the initial element position
17172 this.setStartPosition();
17175 this.b4MouseDown(e);
17176 this.onMouseDown(e);
17178 this.DDM.handleMouseDown(e, this);
17180 this.DDM.stopEvent(e);
17188 clickValidator: function(e) {
17189 var target = e.getTarget();
17190 return ( this.isValidHandleChild(target) &&
17191 (this.id == this.handleElId ||
17192 this.DDM.handleWasClicked(target, this.id)) );
17196 * Allows you to specify a tag name that should not start a drag operation
17197 * when clicked. This is designed to facilitate embedding links within a
17198 * drag handle that do something other than start the drag.
17199 * @method addInvalidHandleType
17200 * @param {string} tagName the type of element to exclude
17202 addInvalidHandleType: function(tagName) {
17203 var type = tagName.toUpperCase();
17204 this.invalidHandleTypes[type] = type;
17208 * Lets you to specify an element id for a child of a drag handle
17209 * that should not initiate a drag
17210 * @method addInvalidHandleId
17211 * @param {string} id the element id of the element you wish to ignore
17213 addInvalidHandleId: function(id) {
17214 if (typeof id !== "string") {
17217 this.invalidHandleIds[id] = id;
17221 * Lets you specify a css class of elements that will not initiate a drag
17222 * @method addInvalidHandleClass
17223 * @param {string} cssClass the class of the elements you wish to ignore
17225 addInvalidHandleClass: function(cssClass) {
17226 this.invalidHandleClasses.push(cssClass);
17230 * Unsets an excluded tag name set by addInvalidHandleType
17231 * @method removeInvalidHandleType
17232 * @param {string} tagName the type of element to unexclude
17234 removeInvalidHandleType: function(tagName) {
17235 var type = tagName.toUpperCase();
17236 // this.invalidHandleTypes[type] = null;
17237 delete this.invalidHandleTypes[type];
17241 * Unsets an invalid handle id
17242 * @method removeInvalidHandleId
17243 * @param {string} id the id of the element to re-enable
17245 removeInvalidHandleId: function(id) {
17246 if (typeof id !== "string") {
17249 delete this.invalidHandleIds[id];
17253 * Unsets an invalid css class
17254 * @method removeInvalidHandleClass
17255 * @param {string} cssClass the class of the element(s) you wish to
17258 removeInvalidHandleClass: function(cssClass) {
17259 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17260 if (this.invalidHandleClasses[i] == cssClass) {
17261 delete this.invalidHandleClasses[i];
17267 * Checks the tag exclusion list to see if this click should be ignored
17268 * @method isValidHandleChild
17269 * @param {HTMLElement} node the HTMLElement to evaluate
17270 * @return {boolean} true if this is a valid tag type, false if not
17272 isValidHandleChild: function(node) {
17275 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17278 nodeName = node.nodeName.toUpperCase();
17280 nodeName = node.nodeName;
17282 valid = valid && !this.invalidHandleTypes[nodeName];
17283 valid = valid && !this.invalidHandleIds[node.id];
17285 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17286 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17295 * Create the array of horizontal tick marks if an interval was specified
17296 * in setXConstraint().
17297 * @method setXTicks
17300 setXTicks: function(iStartX, iTickSize) {
17302 this.xTickSize = iTickSize;
17306 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17308 this.xTicks[this.xTicks.length] = i;
17313 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17315 this.xTicks[this.xTicks.length] = i;
17320 this.xTicks.sort(this.DDM.numericSort) ;
17324 * Create the array of vertical tick marks if an interval was specified in
17325 * setYConstraint().
17326 * @method setYTicks
17329 setYTicks: function(iStartY, iTickSize) {
17331 this.yTickSize = iTickSize;
17335 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17337 this.yTicks[this.yTicks.length] = i;
17342 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17344 this.yTicks[this.yTicks.length] = i;
17349 this.yTicks.sort(this.DDM.numericSort) ;
17353 * By default, the element can be dragged any place on the screen. Use
17354 * this method to limit the horizontal travel of the element. Pass in
17355 * 0,0 for the parameters if you want to lock the drag to the y axis.
17356 * @method setXConstraint
17357 * @param {int} iLeft the number of pixels the element can move to the left
17358 * @param {int} iRight the number of pixels the element can move to the
17360 * @param {int} iTickSize optional parameter for specifying that the
17362 * should move iTickSize pixels at a time.
17364 setXConstraint: function(iLeft, iRight, iTickSize) {
17365 this.leftConstraint = iLeft;
17366 this.rightConstraint = iRight;
17368 this.minX = this.initPageX - iLeft;
17369 this.maxX = this.initPageX + iRight;
17370 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17372 this.constrainX = true;
17376 * Clears any constraints applied to this instance. Also clears ticks
17377 * since they can't exist independent of a constraint at this time.
17378 * @method clearConstraints
17380 clearConstraints: function() {
17381 this.constrainX = false;
17382 this.constrainY = false;
17387 * Clears any tick interval defined for this instance
17388 * @method clearTicks
17390 clearTicks: function() {
17391 this.xTicks = null;
17392 this.yTicks = null;
17393 this.xTickSize = 0;
17394 this.yTickSize = 0;
17398 * By default, the element can be dragged any place on the screen. Set
17399 * this to limit the vertical travel of the element. Pass in 0,0 for the
17400 * parameters if you want to lock the drag to the x axis.
17401 * @method setYConstraint
17402 * @param {int} iUp the number of pixels the element can move up
17403 * @param {int} iDown the number of pixels the element can move down
17404 * @param {int} iTickSize optional parameter for specifying that the
17405 * element should move iTickSize pixels at a time.
17407 setYConstraint: function(iUp, iDown, iTickSize) {
17408 this.topConstraint = iUp;
17409 this.bottomConstraint = iDown;
17411 this.minY = this.initPageY - iUp;
17412 this.maxY = this.initPageY + iDown;
17413 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17415 this.constrainY = true;
17420 * resetConstraints must be called if you manually reposition a dd element.
17421 * @method resetConstraints
17422 * @param {boolean} maintainOffset
17424 resetConstraints: function() {
17427 // Maintain offsets if necessary
17428 if (this.initPageX || this.initPageX === 0) {
17429 // figure out how much this thing has moved
17430 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17431 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17433 this.setInitPosition(dx, dy);
17435 // This is the first time we have detected the element's position
17437 this.setInitPosition();
17440 if (this.constrainX) {
17441 this.setXConstraint( this.leftConstraint,
17442 this.rightConstraint,
17446 if (this.constrainY) {
17447 this.setYConstraint( this.topConstraint,
17448 this.bottomConstraint,
17454 * Normally the drag element is moved pixel by pixel, but we can specify
17455 * that it move a number of pixels at a time. This method resolves the
17456 * location when we have it set up like this.
17458 * @param {int} val where we want to place the object
17459 * @param {int[]} tickArray sorted array of valid points
17460 * @return {int} the closest tick
17463 getTick: function(val, tickArray) {
17466 // If tick interval is not defined, it is effectively 1 pixel,
17467 // so we return the value passed to us.
17469 } else if (tickArray[0] >= val) {
17470 // The value is lower than the first tick, so we return the first
17472 return tickArray[0];
17474 for (var i=0, len=tickArray.length; i<len; ++i) {
17476 if (tickArray[next] && tickArray[next] >= val) {
17477 var diff1 = val - tickArray[i];
17478 var diff2 = tickArray[next] - val;
17479 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17483 // The value is larger than the last tick, so we return the last
17485 return tickArray[tickArray.length - 1];
17492 * @return {string} string representation of the dd obj
17494 toString: function() {
17495 return ("DragDrop " + this.id);
17503 * Ext JS Library 1.1.1
17504 * Copyright(c) 2006-2007, Ext JS, LLC.
17506 * Originally Released Under LGPL - original licence link has changed is not relivant.
17509 * <script type="text/javascript">
17514 * The drag and drop utility provides a framework for building drag and drop
17515 * applications. In addition to enabling drag and drop for specific elements,
17516 * the drag and drop elements are tracked by the manager class, and the
17517 * interactions between the various elements are tracked during the drag and
17518 * the implementing code is notified about these important moments.
17521 // Only load the library once. Rewriting the manager class would orphan
17522 // existing drag and drop instances.
17523 if (!Roo.dd.DragDropMgr) {
17526 * @class Roo.dd.DragDropMgr
17527 * DragDropMgr is a singleton that tracks the element interaction for
17528 * all DragDrop items in the window. Generally, you will not call
17529 * this class directly, but it does have helper methods that could
17530 * be useful in your DragDrop implementations.
17533 Roo.dd.DragDropMgr = function() {
17535 var Event = Roo.EventManager;
17540 * Two dimensional Array of registered DragDrop objects. The first
17541 * dimension is the DragDrop item group, the second the DragDrop
17544 * @type {string: string}
17551 * Array of element ids defined as drag handles. Used to determine
17552 * if the element that generated the mousedown event is actually the
17553 * handle and not the html element itself.
17554 * @property handleIds
17555 * @type {string: string}
17562 * the DragDrop object that is currently being dragged
17563 * @property dragCurrent
17571 * the DragDrop object(s) that are being hovered over
17572 * @property dragOvers
17580 * the X distance between the cursor and the object being dragged
17589 * the Y distance between the cursor and the object being dragged
17598 * Flag to determine if we should prevent the default behavior of the
17599 * events we define. By default this is true, but this can be set to
17600 * false if you need the default behavior (not recommended)
17601 * @property preventDefault
17605 preventDefault: true,
17608 * Flag to determine if we should stop the propagation of the events
17609 * we generate. This is true by default but you may want to set it to
17610 * false if the html element contains other features that require the
17612 * @property stopPropagation
17616 stopPropagation: true,
17619 * Internal flag that is set to true when drag and drop has been
17621 * @property initialized
17628 * All drag and drop can be disabled.
17636 * Called the first time an element is registered.
17642 this.initialized = true;
17646 * In point mode, drag and drop interaction is defined by the
17647 * location of the cursor during the drag/drop
17655 * In intersect mode, drag and drop interactio nis defined by the
17656 * overlap of two or more drag and drop objects.
17657 * @property INTERSECT
17664 * The current drag and drop mode. Default: POINT
17672 * Runs method on all drag and drop objects
17673 * @method _execOnAll
17677 _execOnAll: function(sMethod, args) {
17678 for (var i in this.ids) {
17679 for (var j in this.ids[i]) {
17680 var oDD = this.ids[i][j];
17681 if (! this.isTypeOfDD(oDD)) {
17684 oDD[sMethod].apply(oDD, args);
17690 * Drag and drop initialization. Sets up the global event handlers
17695 _onLoad: function() {
17699 if (!Roo.isTouch) {
17700 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17701 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17703 Event.on(document, "touchend", this.handleMouseUp, this, true);
17704 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17706 Event.on(window, "unload", this._onUnload, this, true);
17707 Event.on(window, "resize", this._onResize, this, true);
17708 // Event.on(window, "mouseout", this._test);
17713 * Reset constraints on all drag and drop objs
17714 * @method _onResize
17718 _onResize: function(e) {
17719 this._execOnAll("resetConstraints", []);
17723 * Lock all drag and drop functionality
17727 lock: function() { this.locked = true; },
17730 * Unlock all drag and drop functionality
17734 unlock: function() { this.locked = false; },
17737 * Is drag and drop locked?
17739 * @return {boolean} True if drag and drop is locked, false otherwise.
17742 isLocked: function() { return this.locked; },
17745 * Location cache that is set for all drag drop objects when a drag is
17746 * initiated, cleared when the drag is finished.
17747 * @property locationCache
17754 * Set useCache to false if you want to force object the lookup of each
17755 * drag and drop linked element constantly during a drag.
17756 * @property useCache
17763 * The number of pixels that the mouse needs to move after the
17764 * mousedown before the drag is initiated. Default=3;
17765 * @property clickPixelThresh
17769 clickPixelThresh: 3,
17772 * The number of milliseconds after the mousedown event to initiate the
17773 * drag if we don't get a mouseup event. Default=1000
17774 * @property clickTimeThresh
17778 clickTimeThresh: 350,
17781 * Flag that indicates that either the drag pixel threshold or the
17782 * mousdown time threshold has been met
17783 * @property dragThreshMet
17788 dragThreshMet: false,
17791 * Timeout used for the click time threshold
17792 * @property clickTimeout
17797 clickTimeout: null,
17800 * The X position of the mousedown event stored for later use when a
17801 * drag threshold is met.
17810 * The Y position of the mousedown event stored for later use when a
17811 * drag threshold is met.
17820 * Each DragDrop instance must be registered with the DragDropMgr.
17821 * This is executed in DragDrop.init()
17822 * @method regDragDrop
17823 * @param {DragDrop} oDD the DragDrop object to register
17824 * @param {String} sGroup the name of the group this element belongs to
17827 regDragDrop: function(oDD, sGroup) {
17828 if (!this.initialized) { this.init(); }
17830 if (!this.ids[sGroup]) {
17831 this.ids[sGroup] = {};
17833 this.ids[sGroup][oDD.id] = oDD;
17837 * Removes the supplied dd instance from the supplied group. Executed
17838 * by DragDrop.removeFromGroup, so don't call this function directly.
17839 * @method removeDDFromGroup
17843 removeDDFromGroup: function(oDD, sGroup) {
17844 if (!this.ids[sGroup]) {
17845 this.ids[sGroup] = {};
17848 var obj = this.ids[sGroup];
17849 if (obj && obj[oDD.id]) {
17850 delete obj[oDD.id];
17855 * Unregisters a drag and drop item. This is executed in
17856 * DragDrop.unreg, use that method instead of calling this directly.
17861 _remove: function(oDD) {
17862 for (var g in oDD.groups) {
17863 if (g && this.ids[g][oDD.id]) {
17864 delete this.ids[g][oDD.id];
17867 delete this.handleIds[oDD.id];
17871 * Each DragDrop handle element must be registered. This is done
17872 * automatically when executing DragDrop.setHandleElId()
17873 * @method regHandle
17874 * @param {String} sDDId the DragDrop id this element is a handle for
17875 * @param {String} sHandleId the id of the element that is the drag
17879 regHandle: function(sDDId, sHandleId) {
17880 if (!this.handleIds[sDDId]) {
17881 this.handleIds[sDDId] = {};
17883 this.handleIds[sDDId][sHandleId] = sHandleId;
17887 * Utility function to determine if a given element has been
17888 * registered as a drag drop item.
17889 * @method isDragDrop
17890 * @param {String} id the element id to check
17891 * @return {boolean} true if this element is a DragDrop item,
17895 isDragDrop: function(id) {
17896 return ( this.getDDById(id) ) ? true : false;
17900 * Returns the drag and drop instances that are in all groups the
17901 * passed in instance belongs to.
17902 * @method getRelated
17903 * @param {DragDrop} p_oDD the obj to get related data for
17904 * @param {boolean} bTargetsOnly if true, only return targetable objs
17905 * @return {DragDrop[]} the related instances
17908 getRelated: function(p_oDD, bTargetsOnly) {
17910 for (var i in p_oDD.groups) {
17911 for (j in this.ids[i]) {
17912 var dd = this.ids[i][j];
17913 if (! this.isTypeOfDD(dd)) {
17916 if (!bTargetsOnly || dd.isTarget) {
17917 oDDs[oDDs.length] = dd;
17926 * Returns true if the specified dd target is a legal target for
17927 * the specifice drag obj
17928 * @method isLegalTarget
17929 * @param {DragDrop} the drag obj
17930 * @param {DragDrop} the target
17931 * @return {boolean} true if the target is a legal target for the
17935 isLegalTarget: function (oDD, oTargetDD) {
17936 var targets = this.getRelated(oDD, true);
17937 for (var i=0, len=targets.length;i<len;++i) {
17938 if (targets[i].id == oTargetDD.id) {
17947 * My goal is to be able to transparently determine if an object is
17948 * typeof DragDrop, and the exact subclass of DragDrop. typeof
17949 * returns "object", oDD.constructor.toString() always returns
17950 * "DragDrop" and not the name of the subclass. So for now it just
17951 * evaluates a well-known variable in DragDrop.
17952 * @method isTypeOfDD
17953 * @param {Object} the object to evaluate
17954 * @return {boolean} true if typeof oDD = DragDrop
17957 isTypeOfDD: function (oDD) {
17958 return (oDD && oDD.__ygDragDrop);
17962 * Utility function to determine if a given element has been
17963 * registered as a drag drop handle for the given Drag Drop object.
17965 * @param {String} id the element id to check
17966 * @return {boolean} true if this element is a DragDrop handle, false
17970 isHandle: function(sDDId, sHandleId) {
17971 return ( this.handleIds[sDDId] &&
17972 this.handleIds[sDDId][sHandleId] );
17976 * Returns the DragDrop instance for a given id
17977 * @method getDDById
17978 * @param {String} id the id of the DragDrop object
17979 * @return {DragDrop} the drag drop object, null if it is not found
17982 getDDById: function(id) {
17983 for (var i in this.ids) {
17984 if (this.ids[i][id]) {
17985 return this.ids[i][id];
17992 * Fired after a registered DragDrop object gets the mousedown event.
17993 * Sets up the events required to track the object being dragged
17994 * @method handleMouseDown
17995 * @param {Event} e the event
17996 * @param oDD the DragDrop object being dragged
18000 handleMouseDown: function(e, oDD) {
18002 Roo.QuickTips.disable();
18004 this.currentTarget = e.getTarget();
18006 this.dragCurrent = oDD;
18008 var el = oDD.getEl();
18010 // track start position
18011 this.startX = e.getPageX();
18012 this.startY = e.getPageY();
18014 this.deltaX = this.startX - el.offsetLeft;
18015 this.deltaY = this.startY - el.offsetTop;
18017 this.dragThreshMet = false;
18019 this.clickTimeout = setTimeout(
18021 var DDM = Roo.dd.DDM;
18022 DDM.startDrag(DDM.startX, DDM.startY);
18024 this.clickTimeThresh );
18028 * Fired when either the drag pixel threshol or the mousedown hold
18029 * time threshold has been met.
18030 * @method startDrag
18031 * @param x {int} the X position of the original mousedown
18032 * @param y {int} the Y position of the original mousedown
18035 startDrag: function(x, y) {
18036 clearTimeout(this.clickTimeout);
18037 if (this.dragCurrent) {
18038 this.dragCurrent.b4StartDrag(x, y);
18039 this.dragCurrent.startDrag(x, y);
18041 this.dragThreshMet = true;
18045 * Internal function to handle the mouseup event. Will be invoked
18046 * from the context of the document.
18047 * @method handleMouseUp
18048 * @param {Event} e the event
18052 handleMouseUp: function(e) {
18055 Roo.QuickTips.enable();
18057 if (! this.dragCurrent) {
18061 clearTimeout(this.clickTimeout);
18063 if (this.dragThreshMet) {
18064 this.fireEvents(e, true);
18074 * Utility to stop event propagation and event default, if these
18075 * features are turned on.
18076 * @method stopEvent
18077 * @param {Event} e the event as returned by this.getEvent()
18080 stopEvent: function(e){
18081 if(this.stopPropagation) {
18082 e.stopPropagation();
18085 if (this.preventDefault) {
18086 e.preventDefault();
18091 * Internal function to clean up event handlers after the drag
18092 * operation is complete
18094 * @param {Event} e the event
18098 stopDrag: function(e) {
18099 // Fire the drag end event for the item that was dragged
18100 if (this.dragCurrent) {
18101 if (this.dragThreshMet) {
18102 this.dragCurrent.b4EndDrag(e);
18103 this.dragCurrent.endDrag(e);
18106 this.dragCurrent.onMouseUp(e);
18109 this.dragCurrent = null;
18110 this.dragOvers = {};
18114 * Internal function to handle the mousemove event. Will be invoked
18115 * from the context of the html element.
18117 * @TODO figure out what we can do about mouse events lost when the
18118 * user drags objects beyond the window boundary. Currently we can
18119 * detect this in internet explorer by verifying that the mouse is
18120 * down during the mousemove event. Firefox doesn't give us the
18121 * button state on the mousemove event.
18122 * @method handleMouseMove
18123 * @param {Event} e the event
18127 handleMouseMove: function(e) {
18128 if (! this.dragCurrent) {
18132 // var button = e.which || e.button;
18134 // check for IE mouseup outside of page boundary
18135 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18137 return this.handleMouseUp(e);
18140 if (!this.dragThreshMet) {
18141 var diffX = Math.abs(this.startX - e.getPageX());
18142 var diffY = Math.abs(this.startY - e.getPageY());
18143 if (diffX > this.clickPixelThresh ||
18144 diffY > this.clickPixelThresh) {
18145 this.startDrag(this.startX, this.startY);
18149 if (this.dragThreshMet) {
18150 this.dragCurrent.b4Drag(e);
18151 this.dragCurrent.onDrag(e);
18152 if(!this.dragCurrent.moveOnly){
18153 this.fireEvents(e, false);
18163 * Iterates over all of the DragDrop elements to find ones we are
18164 * hovering over or dropping on
18165 * @method fireEvents
18166 * @param {Event} e the event
18167 * @param {boolean} isDrop is this a drop op or a mouseover op?
18171 fireEvents: function(e, isDrop) {
18172 var dc = this.dragCurrent;
18174 // If the user did the mouse up outside of the window, we could
18175 // get here even though we have ended the drag.
18176 if (!dc || dc.isLocked()) {
18180 var pt = e.getPoint();
18182 // cache the previous dragOver array
18188 var enterEvts = [];
18190 // Check to see if the object(s) we were hovering over is no longer
18191 // being hovered over so we can fire the onDragOut event
18192 for (var i in this.dragOvers) {
18194 var ddo = this.dragOvers[i];
18196 if (! this.isTypeOfDD(ddo)) {
18200 if (! this.isOverTarget(pt, ddo, this.mode)) {
18201 outEvts.push( ddo );
18204 oldOvers[i] = true;
18205 delete this.dragOvers[i];
18208 for (var sGroup in dc.groups) {
18210 if ("string" != typeof sGroup) {
18214 for (i in this.ids[sGroup]) {
18215 var oDD = this.ids[sGroup][i];
18216 if (! this.isTypeOfDD(oDD)) {
18220 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18221 if (this.isOverTarget(pt, oDD, this.mode)) {
18222 // look for drop interactions
18224 dropEvts.push( oDD );
18225 // look for drag enter and drag over interactions
18228 // initial drag over: dragEnter fires
18229 if (!oldOvers[oDD.id]) {
18230 enterEvts.push( oDD );
18231 // subsequent drag overs: dragOver fires
18233 overEvts.push( oDD );
18236 this.dragOvers[oDD.id] = oDD;
18244 if (outEvts.length) {
18245 dc.b4DragOut(e, outEvts);
18246 dc.onDragOut(e, outEvts);
18249 if (enterEvts.length) {
18250 dc.onDragEnter(e, enterEvts);
18253 if (overEvts.length) {
18254 dc.b4DragOver(e, overEvts);
18255 dc.onDragOver(e, overEvts);
18258 if (dropEvts.length) {
18259 dc.b4DragDrop(e, dropEvts);
18260 dc.onDragDrop(e, dropEvts);
18264 // fire dragout events
18266 for (i=0, len=outEvts.length; i<len; ++i) {
18267 dc.b4DragOut(e, outEvts[i].id);
18268 dc.onDragOut(e, outEvts[i].id);
18271 // fire enter events
18272 for (i=0,len=enterEvts.length; i<len; ++i) {
18273 // dc.b4DragEnter(e, oDD.id);
18274 dc.onDragEnter(e, enterEvts[i].id);
18277 // fire over events
18278 for (i=0,len=overEvts.length; i<len; ++i) {
18279 dc.b4DragOver(e, overEvts[i].id);
18280 dc.onDragOver(e, overEvts[i].id);
18283 // fire drop events
18284 for (i=0, len=dropEvts.length; i<len; ++i) {
18285 dc.b4DragDrop(e, dropEvts[i].id);
18286 dc.onDragDrop(e, dropEvts[i].id);
18291 // notify about a drop that did not find a target
18292 if (isDrop && !dropEvts.length) {
18293 dc.onInvalidDrop(e);
18299 * Helper function for getting the best match from the list of drag
18300 * and drop objects returned by the drag and drop events when we are
18301 * in INTERSECT mode. It returns either the first object that the
18302 * cursor is over, or the object that has the greatest overlap with
18303 * the dragged element.
18304 * @method getBestMatch
18305 * @param {DragDrop[]} dds The array of drag and drop objects
18307 * @return {DragDrop} The best single match
18310 getBestMatch: function(dds) {
18312 // Return null if the input is not what we expect
18313 //if (!dds || !dds.length || dds.length == 0) {
18315 // If there is only one item, it wins
18316 //} else if (dds.length == 1) {
18318 var len = dds.length;
18323 // Loop through the targeted items
18324 for (var i=0; i<len; ++i) {
18326 // If the cursor is over the object, it wins. If the
18327 // cursor is over multiple matches, the first one we come
18329 if (dd.cursorIsOver) {
18332 // Otherwise the object with the most overlap wins
18335 winner.overlap.getArea() < dd.overlap.getArea()) {
18346 * Refreshes the cache of the top-left and bottom-right points of the
18347 * drag and drop objects in the specified group(s). This is in the
18348 * format that is stored in the drag and drop instance, so typical
18351 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18355 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18357 * @TODO this really should be an indexed array. Alternatively this
18358 * method could accept both.
18359 * @method refreshCache
18360 * @param {Object} groups an associative array of groups to refresh
18363 refreshCache: function(groups) {
18364 for (var sGroup in groups) {
18365 if ("string" != typeof sGroup) {
18368 for (var i in this.ids[sGroup]) {
18369 var oDD = this.ids[sGroup][i];
18371 if (this.isTypeOfDD(oDD)) {
18372 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18373 var loc = this.getLocation(oDD);
18375 this.locationCache[oDD.id] = loc;
18377 delete this.locationCache[oDD.id];
18378 // this will unregister the drag and drop object if
18379 // the element is not in a usable state
18388 * This checks to make sure an element exists and is in the DOM. The
18389 * main purpose is to handle cases where innerHTML is used to remove
18390 * drag and drop objects from the DOM. IE provides an 'unspecified
18391 * error' when trying to access the offsetParent of such an element
18393 * @param {HTMLElement} el the element to check
18394 * @return {boolean} true if the element looks usable
18397 verifyEl: function(el) {
18402 parent = el.offsetParent;
18405 parent = el.offsetParent;
18416 * Returns a Region object containing the drag and drop element's position
18417 * and size, including the padding configured for it
18418 * @method getLocation
18419 * @param {DragDrop} oDD the drag and drop object to get the
18421 * @return {Roo.lib.Region} a Region object representing the total area
18422 * the element occupies, including any padding
18423 * the instance is configured for.
18426 getLocation: function(oDD) {
18427 if (! this.isTypeOfDD(oDD)) {
18431 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18434 pos= Roo.lib.Dom.getXY(el);
18442 x2 = x1 + el.offsetWidth;
18444 y2 = y1 + el.offsetHeight;
18446 t = y1 - oDD.padding[0];
18447 r = x2 + oDD.padding[1];
18448 b = y2 + oDD.padding[2];
18449 l = x1 - oDD.padding[3];
18451 return new Roo.lib.Region( t, r, b, l );
18455 * Checks the cursor location to see if it over the target
18456 * @method isOverTarget
18457 * @param {Roo.lib.Point} pt The point to evaluate
18458 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18459 * @return {boolean} true if the mouse is over the target
18463 isOverTarget: function(pt, oTarget, intersect) {
18464 // use cache if available
18465 var loc = this.locationCache[oTarget.id];
18466 if (!loc || !this.useCache) {
18467 loc = this.getLocation(oTarget);
18468 this.locationCache[oTarget.id] = loc;
18476 oTarget.cursorIsOver = loc.contains( pt );
18478 // DragDrop is using this as a sanity check for the initial mousedown
18479 // in this case we are done. In POINT mode, if the drag obj has no
18480 // contraints, we are also done. Otherwise we need to evaluate the
18481 // location of the target as related to the actual location of the
18482 // dragged element.
18483 var dc = this.dragCurrent;
18484 if (!dc || !dc.getTargetCoord ||
18485 (!intersect && !dc.constrainX && !dc.constrainY)) {
18486 return oTarget.cursorIsOver;
18489 oTarget.overlap = null;
18491 // Get the current location of the drag element, this is the
18492 // location of the mouse event less the delta that represents
18493 // where the original mousedown happened on the element. We
18494 // need to consider constraints and ticks as well.
18495 var pos = dc.getTargetCoord(pt.x, pt.y);
18497 var el = dc.getDragEl();
18498 var curRegion = new Roo.lib.Region( pos.y,
18499 pos.x + el.offsetWidth,
18500 pos.y + el.offsetHeight,
18503 var overlap = curRegion.intersect(loc);
18506 oTarget.overlap = overlap;
18507 return (intersect) ? true : oTarget.cursorIsOver;
18514 * unload event handler
18515 * @method _onUnload
18519 _onUnload: function(e, me) {
18520 Roo.dd.DragDropMgr.unregAll();
18524 * Cleans up the drag and drop events and objects.
18529 unregAll: function() {
18531 if (this.dragCurrent) {
18533 this.dragCurrent = null;
18536 this._execOnAll("unreg", []);
18538 for (i in this.elementCache) {
18539 delete this.elementCache[i];
18542 this.elementCache = {};
18547 * A cache of DOM elements
18548 * @property elementCache
18555 * Get the wrapper for the DOM element specified
18556 * @method getElWrapper
18557 * @param {String} id the id of the element to get
18558 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18560 * @deprecated This wrapper isn't that useful
18563 getElWrapper: function(id) {
18564 var oWrapper = this.elementCache[id];
18565 if (!oWrapper || !oWrapper.el) {
18566 oWrapper = this.elementCache[id] =
18567 new this.ElementWrapper(Roo.getDom(id));
18573 * Returns the actual DOM element
18574 * @method getElement
18575 * @param {String} id the id of the elment to get
18576 * @return {Object} The element
18577 * @deprecated use Roo.getDom instead
18580 getElement: function(id) {
18581 return Roo.getDom(id);
18585 * Returns the style property for the DOM element (i.e.,
18586 * document.getElById(id).style)
18588 * @param {String} id the id of the elment to get
18589 * @return {Object} The style property of the element
18590 * @deprecated use Roo.getDom instead
18593 getCss: function(id) {
18594 var el = Roo.getDom(id);
18595 return (el) ? el.style : null;
18599 * Inner class for cached elements
18600 * @class DragDropMgr.ElementWrapper
18605 ElementWrapper: function(el) {
18610 this.el = el || null;
18615 this.id = this.el && el.id;
18617 * A reference to the style property
18620 this.css = this.el && el.style;
18624 * Returns the X position of an html element
18626 * @param el the element for which to get the position
18627 * @return {int} the X coordinate
18629 * @deprecated use Roo.lib.Dom.getX instead
18632 getPosX: function(el) {
18633 return Roo.lib.Dom.getX(el);
18637 * Returns the Y position of an html element
18639 * @param el the element for which to get the position
18640 * @return {int} the Y coordinate
18641 * @deprecated use Roo.lib.Dom.getY instead
18644 getPosY: function(el) {
18645 return Roo.lib.Dom.getY(el);
18649 * Swap two nodes. In IE, we use the native method, for others we
18650 * emulate the IE behavior
18652 * @param n1 the first node to swap
18653 * @param n2 the other node to swap
18656 swapNode: function(n1, n2) {
18660 var p = n2.parentNode;
18661 var s = n2.nextSibling;
18664 p.insertBefore(n1, n2);
18665 } else if (n2 == n1.nextSibling) {
18666 p.insertBefore(n2, n1);
18668 n1.parentNode.replaceChild(n2, n1);
18669 p.insertBefore(n1, s);
18675 * Returns the current scroll position
18676 * @method getScroll
18680 getScroll: function () {
18681 var t, l, dde=document.documentElement, db=document.body;
18682 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18684 l = dde.scrollLeft;
18691 return { top: t, left: l };
18695 * Returns the specified element style property
18697 * @param {HTMLElement} el the element
18698 * @param {string} styleProp the style property
18699 * @return {string} The value of the style property
18700 * @deprecated use Roo.lib.Dom.getStyle
18703 getStyle: function(el, styleProp) {
18704 return Roo.fly(el).getStyle(styleProp);
18708 * Gets the scrollTop
18709 * @method getScrollTop
18710 * @return {int} the document's scrollTop
18713 getScrollTop: function () { return this.getScroll().top; },
18716 * Gets the scrollLeft
18717 * @method getScrollLeft
18718 * @return {int} the document's scrollTop
18721 getScrollLeft: function () { return this.getScroll().left; },
18724 * Sets the x/y position of an element to the location of the
18727 * @param {HTMLElement} moveEl The element to move
18728 * @param {HTMLElement} targetEl The position reference element
18731 moveToEl: function (moveEl, targetEl) {
18732 var aCoord = Roo.lib.Dom.getXY(targetEl);
18733 Roo.lib.Dom.setXY(moveEl, aCoord);
18737 * Numeric array sort function
18738 * @method numericSort
18741 numericSort: function(a, b) { return (a - b); },
18745 * @property _timeoutCount
18752 * Trying to make the load order less important. Without this we get
18753 * an error if this file is loaded before the Event Utility.
18754 * @method _addListeners
18758 _addListeners: function() {
18759 var DDM = Roo.dd.DDM;
18760 if ( Roo.lib.Event && document ) {
18763 if (DDM._timeoutCount > 2000) {
18765 setTimeout(DDM._addListeners, 10);
18766 if (document && document.body) {
18767 DDM._timeoutCount += 1;
18774 * Recursively searches the immediate parent and all child nodes for
18775 * the handle element in order to determine wheter or not it was
18777 * @method handleWasClicked
18778 * @param node the html element to inspect
18781 handleWasClicked: function(node, id) {
18782 if (this.isHandle(id, node.id)) {
18785 // check to see if this is a text node child of the one we want
18786 var p = node.parentNode;
18789 if (this.isHandle(id, p.id)) {
18804 // shorter alias, save a few bytes
18805 Roo.dd.DDM = Roo.dd.DragDropMgr;
18806 Roo.dd.DDM._addListeners();
18810 * Ext JS Library 1.1.1
18811 * Copyright(c) 2006-2007, Ext JS, LLC.
18813 * Originally Released Under LGPL - original licence link has changed is not relivant.
18816 * <script type="text/javascript">
18821 * A DragDrop implementation where the linked element follows the
18822 * mouse cursor during a drag.
18823 * @extends Roo.dd.DragDrop
18825 * @param {String} id the id of the linked element
18826 * @param {String} sGroup the group of related DragDrop items
18827 * @param {object} config an object containing configurable attributes
18828 * Valid properties for DD:
18831 Roo.dd.DD = function(id, sGroup, config) {
18833 this.init(id, sGroup, config);
18837 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18840 * When set to true, the utility automatically tries to scroll the browser
18841 * window wehn a drag and drop element is dragged near the viewport boundary.
18842 * Defaults to true.
18849 * Sets the pointer offset to the distance between the linked element's top
18850 * left corner and the location the element was clicked
18851 * @method autoOffset
18852 * @param {int} iPageX the X coordinate of the click
18853 * @param {int} iPageY the Y coordinate of the click
18855 autoOffset: function(iPageX, iPageY) {
18856 var x = iPageX - this.startPageX;
18857 var y = iPageY - this.startPageY;
18858 this.setDelta(x, y);
18862 * Sets the pointer offset. You can call this directly to force the
18863 * offset to be in a particular location (e.g., pass in 0,0 to set it
18864 * to the center of the object)
18866 * @param {int} iDeltaX the distance from the left
18867 * @param {int} iDeltaY the distance from the top
18869 setDelta: function(iDeltaX, iDeltaY) {
18870 this.deltaX = iDeltaX;
18871 this.deltaY = iDeltaY;
18875 * Sets the drag element to the location of the mousedown or click event,
18876 * maintaining the cursor location relative to the location on the element
18877 * that was clicked. Override this if you want to place the element in a
18878 * location other than where the cursor is.
18879 * @method setDragElPos
18880 * @param {int} iPageX the X coordinate of the mousedown or drag event
18881 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18883 setDragElPos: function(iPageX, iPageY) {
18884 // the first time we do this, we are going to check to make sure
18885 // the element has css positioning
18887 var el = this.getDragEl();
18888 this.alignElWithMouse(el, iPageX, iPageY);
18892 * Sets the element to the location of the mousedown or click event,
18893 * maintaining the cursor location relative to the location on the element
18894 * that was clicked. Override this if you want to place the element in a
18895 * location other than where the cursor is.
18896 * @method alignElWithMouse
18897 * @param {HTMLElement} el the element to move
18898 * @param {int} iPageX the X coordinate of the mousedown or drag event
18899 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18901 alignElWithMouse: function(el, iPageX, iPageY) {
18902 var oCoord = this.getTargetCoord(iPageX, iPageY);
18903 var fly = el.dom ? el : Roo.fly(el);
18904 if (!this.deltaSetXY) {
18905 var aCoord = [oCoord.x, oCoord.y];
18907 var newLeft = fly.getLeft(true);
18908 var newTop = fly.getTop(true);
18909 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18911 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18914 this.cachePosition(oCoord.x, oCoord.y);
18915 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18920 * Saves the most recent position so that we can reset the constraints and
18921 * tick marks on-demand. We need to know this so that we can calculate the
18922 * number of pixels the element is offset from its original position.
18923 * @method cachePosition
18924 * @param iPageX the current x position (optional, this just makes it so we
18925 * don't have to look it up again)
18926 * @param iPageY the current y position (optional, this just makes it so we
18927 * don't have to look it up again)
18929 cachePosition: function(iPageX, iPageY) {
18931 this.lastPageX = iPageX;
18932 this.lastPageY = iPageY;
18934 var aCoord = Roo.lib.Dom.getXY(this.getEl());
18935 this.lastPageX = aCoord[0];
18936 this.lastPageY = aCoord[1];
18941 * Auto-scroll the window if the dragged object has been moved beyond the
18942 * visible window boundary.
18943 * @method autoScroll
18944 * @param {int} x the drag element's x position
18945 * @param {int} y the drag element's y position
18946 * @param {int} h the height of the drag element
18947 * @param {int} w the width of the drag element
18950 autoScroll: function(x, y, h, w) {
18953 // The client height
18954 var clientH = Roo.lib.Dom.getViewWidth();
18956 // The client width
18957 var clientW = Roo.lib.Dom.getViewHeight();
18959 // The amt scrolled down
18960 var st = this.DDM.getScrollTop();
18962 // The amt scrolled right
18963 var sl = this.DDM.getScrollLeft();
18965 // Location of the bottom of the element
18968 // Location of the right of the element
18971 // The distance from the cursor to the bottom of the visible area,
18972 // adjusted so that we don't scroll if the cursor is beyond the
18973 // element drag constraints
18974 var toBot = (clientH + st - y - this.deltaY);
18976 // The distance from the cursor to the right of the visible area
18977 var toRight = (clientW + sl - x - this.deltaX);
18980 // How close to the edge the cursor must be before we scroll
18981 // var thresh = (document.all) ? 100 : 40;
18984 // How many pixels to scroll per autoscroll op. This helps to reduce
18985 // clunky scrolling. IE is more sensitive about this ... it needs this
18986 // value to be higher.
18987 var scrAmt = (document.all) ? 80 : 30;
18989 // Scroll down if we are near the bottom of the visible page and the
18990 // obj extends below the crease
18991 if ( bot > clientH && toBot < thresh ) {
18992 window.scrollTo(sl, st + scrAmt);
18995 // Scroll up if the window is scrolled down and the top of the object
18996 // goes above the top border
18997 if ( y < st && st > 0 && y - st < thresh ) {
18998 window.scrollTo(sl, st - scrAmt);
19001 // Scroll right if the obj is beyond the right border and the cursor is
19002 // near the border.
19003 if ( right > clientW && toRight < thresh ) {
19004 window.scrollTo(sl + scrAmt, st);
19007 // Scroll left if the window has been scrolled to the right and the obj
19008 // extends past the left border
19009 if ( x < sl && sl > 0 && x - sl < thresh ) {
19010 window.scrollTo(sl - scrAmt, st);
19016 * Finds the location the element should be placed if we want to move
19017 * it to where the mouse location less the click offset would place us.
19018 * @method getTargetCoord
19019 * @param {int} iPageX the X coordinate of the click
19020 * @param {int} iPageY the Y coordinate of the click
19021 * @return an object that contains the coordinates (Object.x and Object.y)
19024 getTargetCoord: function(iPageX, iPageY) {
19027 var x = iPageX - this.deltaX;
19028 var y = iPageY - this.deltaY;
19030 if (this.constrainX) {
19031 if (x < this.minX) { x = this.minX; }
19032 if (x > this.maxX) { x = this.maxX; }
19035 if (this.constrainY) {
19036 if (y < this.minY) { y = this.minY; }
19037 if (y > this.maxY) { y = this.maxY; }
19040 x = this.getTick(x, this.xTicks);
19041 y = this.getTick(y, this.yTicks);
19048 * Sets up config options specific to this class. Overrides
19049 * Roo.dd.DragDrop, but all versions of this method through the
19050 * inheritance chain are called
19052 applyConfig: function() {
19053 Roo.dd.DD.superclass.applyConfig.call(this);
19054 this.scroll = (this.config.scroll !== false);
19058 * Event that fires prior to the onMouseDown event. Overrides
19061 b4MouseDown: function(e) {
19062 // this.resetConstraints();
19063 this.autoOffset(e.getPageX(),
19068 * Event that fires prior to the onDrag event. Overrides
19071 b4Drag: function(e) {
19072 this.setDragElPos(e.getPageX(),
19076 toString: function() {
19077 return ("DD " + this.id);
19080 //////////////////////////////////////////////////////////////////////////
19081 // Debugging ygDragDrop events that can be overridden
19082 //////////////////////////////////////////////////////////////////////////
19084 startDrag: function(x, y) {
19087 onDrag: function(e) {
19090 onDragEnter: function(e, id) {
19093 onDragOver: function(e, id) {
19096 onDragOut: function(e, id) {
19099 onDragDrop: function(e, id) {
19102 endDrag: function(e) {
19109 * Ext JS Library 1.1.1
19110 * Copyright(c) 2006-2007, Ext JS, LLC.
19112 * Originally Released Under LGPL - original licence link has changed is not relivant.
19115 * <script type="text/javascript">
19119 * @class Roo.dd.DDProxy
19120 * A DragDrop implementation that inserts an empty, bordered div into
19121 * the document that follows the cursor during drag operations. At the time of
19122 * the click, the frame div is resized to the dimensions of the linked html
19123 * element, and moved to the exact location of the linked element.
19125 * References to the "frame" element refer to the single proxy element that
19126 * was created to be dragged in place of all DDProxy elements on the
19129 * @extends Roo.dd.DD
19131 * @param {String} id the id of the linked html element
19132 * @param {String} sGroup the group of related DragDrop objects
19133 * @param {object} config an object containing configurable attributes
19134 * Valid properties for DDProxy in addition to those in DragDrop:
19135 * resizeFrame, centerFrame, dragElId
19137 Roo.dd.DDProxy = function(id, sGroup, config) {
19139 this.init(id, sGroup, config);
19145 * The default drag frame div id
19146 * @property Roo.dd.DDProxy.dragElId
19150 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19152 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19155 * By default we resize the drag frame to be the same size as the element
19156 * we want to drag (this is to get the frame effect). We can turn it off
19157 * if we want a different behavior.
19158 * @property resizeFrame
19164 * By default the frame is positioned exactly where the drag element is, so
19165 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19166 * you do not have constraints on the obj is to have the drag frame centered
19167 * around the cursor. Set centerFrame to true for this effect.
19168 * @property centerFrame
19171 centerFrame: false,
19174 * Creates the proxy element if it does not yet exist
19175 * @method createFrame
19177 createFrame: function() {
19179 var body = document.body;
19181 if (!body || !body.firstChild) {
19182 setTimeout( function() { self.createFrame(); }, 50 );
19186 var div = this.getDragEl();
19189 div = document.createElement("div");
19190 div.id = this.dragElId;
19193 s.position = "absolute";
19194 s.visibility = "hidden";
19196 s.border = "2px solid #aaa";
19199 // appendChild can blow up IE if invoked prior to the window load event
19200 // while rendering a table. It is possible there are other scenarios
19201 // that would cause this to happen as well.
19202 body.insertBefore(div, body.firstChild);
19207 * Initialization for the drag frame element. Must be called in the
19208 * constructor of all subclasses
19209 * @method initFrame
19211 initFrame: function() {
19212 this.createFrame();
19215 applyConfig: function() {
19216 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19218 this.resizeFrame = (this.config.resizeFrame !== false);
19219 this.centerFrame = (this.config.centerFrame);
19220 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19224 * Resizes the drag frame to the dimensions of the clicked object, positions
19225 * it over the object, and finally displays it
19226 * @method showFrame
19227 * @param {int} iPageX X click position
19228 * @param {int} iPageY Y click position
19231 showFrame: function(iPageX, iPageY) {
19232 var el = this.getEl();
19233 var dragEl = this.getDragEl();
19234 var s = dragEl.style;
19236 this._resizeProxy();
19238 if (this.centerFrame) {
19239 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19240 Math.round(parseInt(s.height, 10)/2) );
19243 this.setDragElPos(iPageX, iPageY);
19245 Roo.fly(dragEl).show();
19249 * The proxy is automatically resized to the dimensions of the linked
19250 * element when a drag is initiated, unless resizeFrame is set to false
19251 * @method _resizeProxy
19254 _resizeProxy: function() {
19255 if (this.resizeFrame) {
19256 var el = this.getEl();
19257 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19261 // overrides Roo.dd.DragDrop
19262 b4MouseDown: function(e) {
19263 var x = e.getPageX();
19264 var y = e.getPageY();
19265 this.autoOffset(x, y);
19266 this.setDragElPos(x, y);
19269 // overrides Roo.dd.DragDrop
19270 b4StartDrag: function(x, y) {
19271 // show the drag frame
19272 this.showFrame(x, y);
19275 // overrides Roo.dd.DragDrop
19276 b4EndDrag: function(e) {
19277 Roo.fly(this.getDragEl()).hide();
19280 // overrides Roo.dd.DragDrop
19281 // By default we try to move the element to the last location of the frame.
19282 // This is so that the default behavior mirrors that of Roo.dd.DD.
19283 endDrag: function(e) {
19285 var lel = this.getEl();
19286 var del = this.getDragEl();
19288 // Show the drag frame briefly so we can get its position
19289 del.style.visibility = "";
19292 // Hide the linked element before the move to get around a Safari
19294 lel.style.visibility = "hidden";
19295 Roo.dd.DDM.moveToEl(lel, del);
19296 del.style.visibility = "hidden";
19297 lel.style.visibility = "";
19302 beforeMove : function(){
19306 afterDrag : function(){
19310 toString: function() {
19311 return ("DDProxy " + this.id);
19317 * Ext JS Library 1.1.1
19318 * Copyright(c) 2006-2007, Ext JS, LLC.
19320 * Originally Released Under LGPL - original licence link has changed is not relivant.
19323 * <script type="text/javascript">
19327 * @class Roo.dd.DDTarget
19328 * A DragDrop implementation that does not move, but can be a drop
19329 * target. You would get the same result by simply omitting implementation
19330 * for the event callbacks, but this way we reduce the processing cost of the
19331 * event listener and the callbacks.
19332 * @extends Roo.dd.DragDrop
19334 * @param {String} id the id of the element that is a drop target
19335 * @param {String} sGroup the group of related DragDrop objects
19336 * @param {object} config an object containing configurable attributes
19337 * Valid properties for DDTarget in addition to those in
19341 Roo.dd.DDTarget = function(id, sGroup, config) {
19343 this.initTarget(id, sGroup, config);
19345 if (config.listeners || config.events) {
19346 Roo.dd.DragDrop.superclass.constructor.call(this, {
19347 listeners : config.listeners || {},
19348 events : config.events || {}
19353 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19354 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19355 toString: function() {
19356 return ("DDTarget " + this.id);
19361 * Ext JS Library 1.1.1
19362 * Copyright(c) 2006-2007, Ext JS, LLC.
19364 * Originally Released Under LGPL - original licence link has changed is not relivant.
19367 * <script type="text/javascript">
19372 * @class Roo.dd.ScrollManager
19373 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19374 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19377 Roo.dd.ScrollManager = function(){
19378 var ddm = Roo.dd.DragDropMgr;
19385 var onStop = function(e){
19390 var triggerRefresh = function(){
19391 if(ddm.dragCurrent){
19392 ddm.refreshCache(ddm.dragCurrent.groups);
19396 var doScroll = function(){
19397 if(ddm.dragCurrent){
19398 var dds = Roo.dd.ScrollManager;
19400 if(proc.el.scroll(proc.dir, dds.increment)){
19404 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19409 var clearProc = function(){
19411 clearInterval(proc.id);
19418 var startProc = function(el, dir){
19419 Roo.log('scroll startproc');
19423 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19426 var onFire = function(e, isDrop){
19428 if(isDrop || !ddm.dragCurrent){ return; }
19429 var dds = Roo.dd.ScrollManager;
19430 if(!dragEl || dragEl != ddm.dragCurrent){
19431 dragEl = ddm.dragCurrent;
19432 // refresh regions on drag start
19433 dds.refreshCache();
19436 var xy = Roo.lib.Event.getXY(e);
19437 var pt = new Roo.lib.Point(xy[0], xy[1]);
19438 for(var id in els){
19439 var el = els[id], r = el._region;
19440 if(r && r.contains(pt) && el.isScrollable()){
19441 if(r.bottom - pt.y <= dds.thresh){
19443 startProc(el, "down");
19446 }else if(r.right - pt.x <= dds.thresh){
19448 startProc(el, "left");
19451 }else if(pt.y - r.top <= dds.thresh){
19453 startProc(el, "up");
19456 }else if(pt.x - r.left <= dds.thresh){
19458 startProc(el, "right");
19467 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19468 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19472 * Registers new overflow element(s) to auto scroll
19473 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19475 register : function(el){
19476 if(el instanceof Array){
19477 for(var i = 0, len = el.length; i < len; i++) {
19478 this.register(el[i]);
19484 Roo.dd.ScrollManager.els = els;
19488 * Unregisters overflow element(s) so they are no longer scrolled
19489 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19491 unregister : function(el){
19492 if(el instanceof Array){
19493 for(var i = 0, len = el.length; i < len; i++) {
19494 this.unregister(el[i]);
19503 * The number of pixels from the edge of a container the pointer needs to be to
19504 * trigger scrolling (defaults to 25)
19510 * The number of pixels to scroll in each scroll increment (defaults to 50)
19516 * The frequency of scrolls in milliseconds (defaults to 500)
19522 * True to animate the scroll (defaults to true)
19528 * The animation duration in seconds -
19529 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19535 * Manually trigger a cache refresh.
19537 refreshCache : function(){
19538 for(var id in els){
19539 if(typeof els[id] == 'object'){ // for people extending the object prototype
19540 els[id]._region = els[id].getRegion();
19547 * Ext JS Library 1.1.1
19548 * Copyright(c) 2006-2007, Ext JS, LLC.
19550 * Originally Released Under LGPL - original licence link has changed is not relivant.
19553 * <script type="text/javascript">
19558 * @class Roo.dd.Registry
19559 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19560 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19563 Roo.dd.Registry = function(){
19566 var autoIdSeed = 0;
19568 var getId = function(el, autogen){
19569 if(typeof el == "string"){
19573 if(!id && autogen !== false){
19574 id = "roodd-" + (++autoIdSeed);
19582 * Register a drag drop element
19583 * @param {String|HTMLElement} element The id or DOM node to register
19584 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19585 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19586 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19587 * populated in the data object (if applicable):
19589 Value Description<br />
19590 --------- ------------------------------------------<br />
19591 handles Array of DOM nodes that trigger dragging<br />
19592 for the element being registered<br />
19593 isHandle True if the element passed in triggers<br />
19594 dragging itself, else false
19597 register : function(el, data){
19599 if(typeof el == "string"){
19600 el = document.getElementById(el);
19603 elements[getId(el)] = data;
19604 if(data.isHandle !== false){
19605 handles[data.ddel.id] = data;
19608 var hs = data.handles;
19609 for(var i = 0, len = hs.length; i < len; i++){
19610 handles[getId(hs[i])] = data;
19616 * Unregister a drag drop element
19617 * @param {String|HTMLElement} element The id or DOM node to unregister
19619 unregister : function(el){
19620 var id = getId(el, false);
19621 var data = elements[id];
19623 delete elements[id];
19625 var hs = data.handles;
19626 for(var i = 0, len = hs.length; i < len; i++){
19627 delete handles[getId(hs[i], false)];
19634 * Returns the handle registered for a DOM Node by id
19635 * @param {String|HTMLElement} id The DOM node or id to look up
19636 * @return {Object} handle The custom handle data
19638 getHandle : function(id){
19639 if(typeof id != "string"){ // must be element?
19642 return handles[id];
19646 * Returns the handle that is registered for the DOM node that is the target of the event
19647 * @param {Event} e The event
19648 * @return {Object} handle The custom handle data
19650 getHandleFromEvent : function(e){
19651 var t = Roo.lib.Event.getTarget(e);
19652 return t ? handles[t.id] : null;
19656 * Returns a custom data object that is registered for a DOM node by id
19657 * @param {String|HTMLElement} id The DOM node or id to look up
19658 * @return {Object} data The custom data
19660 getTarget : function(id){
19661 if(typeof id != "string"){ // must be element?
19664 return elements[id];
19668 * Returns a custom data object that is registered for the DOM node that is the target of the event
19669 * @param {Event} e The event
19670 * @return {Object} data The custom data
19672 getTargetFromEvent : function(e){
19673 var t = Roo.lib.Event.getTarget(e);
19674 return t ? elements[t.id] || handles[t.id] : null;
19679 * Ext JS Library 1.1.1
19680 * Copyright(c) 2006-2007, Ext JS, LLC.
19682 * Originally Released Under LGPL - original licence link has changed is not relivant.
19685 * <script type="text/javascript">
19690 * @class Roo.dd.StatusProxy
19691 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19692 * default drag proxy used by all Roo.dd components.
19694 * @param {Object} config
19696 Roo.dd.StatusProxy = function(config){
19697 Roo.apply(this, config);
19698 this.id = this.id || Roo.id();
19699 this.el = new Roo.Layer({
19701 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19702 {tag: "div", cls: "x-dd-drop-icon"},
19703 {tag: "div", cls: "x-dd-drag-ghost"}
19706 shadow: !config || config.shadow !== false
19708 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19709 this.dropStatus = this.dropNotAllowed;
19712 Roo.dd.StatusProxy.prototype = {
19714 * @cfg {String} dropAllowed
19715 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19717 dropAllowed : "x-dd-drop-ok",
19719 * @cfg {String} dropNotAllowed
19720 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19722 dropNotAllowed : "x-dd-drop-nodrop",
19725 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19726 * over the current target element.
19727 * @param {String} cssClass The css class for the new drop status indicator image
19729 setStatus : function(cssClass){
19730 cssClass = cssClass || this.dropNotAllowed;
19731 if(this.dropStatus != cssClass){
19732 this.el.replaceClass(this.dropStatus, cssClass);
19733 this.dropStatus = cssClass;
19738 * Resets the status indicator to the default dropNotAllowed value
19739 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19741 reset : function(clearGhost){
19742 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19743 this.dropStatus = this.dropNotAllowed;
19745 this.ghost.update("");
19750 * Updates the contents of the ghost element
19751 * @param {String} html The html that will replace the current innerHTML of the ghost element
19753 update : function(html){
19754 if(typeof html == "string"){
19755 this.ghost.update(html);
19757 this.ghost.update("");
19758 html.style.margin = "0";
19759 this.ghost.dom.appendChild(html);
19761 // ensure float = none set?? cant remember why though.
19762 var el = this.ghost.dom.firstChild;
19764 Roo.fly(el).setStyle('float', 'none');
19769 * Returns the underlying proxy {@link Roo.Layer}
19770 * @return {Roo.Layer} el
19772 getEl : function(){
19777 * Returns the ghost element
19778 * @return {Roo.Element} el
19780 getGhost : function(){
19786 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19788 hide : function(clear){
19796 * Stops the repair animation if it's currently running
19799 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19805 * Displays this proxy
19812 * Force the Layer to sync its shadow and shim positions to the element
19819 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19820 * invalid drop operation by the item being dragged.
19821 * @param {Array} xy The XY position of the element ([x, y])
19822 * @param {Function} callback The function to call after the repair is complete
19823 * @param {Object} scope The scope in which to execute the callback
19825 repair : function(xy, callback, scope){
19826 this.callback = callback;
19827 this.scope = scope;
19828 if(xy && this.animRepair !== false){
19829 this.el.addClass("x-dd-drag-repair");
19830 this.el.hideUnders(true);
19831 this.anim = this.el.shift({
19832 duration: this.repairDuration || .5,
19836 callback: this.afterRepair,
19840 this.afterRepair();
19845 afterRepair : function(){
19847 if(typeof this.callback == "function"){
19848 this.callback.call(this.scope || this);
19850 this.callback = null;
19855 * Ext JS Library 1.1.1
19856 * Copyright(c) 2006-2007, Ext JS, LLC.
19858 * Originally Released Under LGPL - original licence link has changed is not relivant.
19861 * <script type="text/javascript">
19865 * @class Roo.dd.DragSource
19866 * @extends Roo.dd.DDProxy
19867 * A simple class that provides the basic implementation needed to make any element draggable.
19869 * @param {String/HTMLElement/Element} el The container element
19870 * @param {Object} config
19872 Roo.dd.DragSource = function(el, config){
19873 this.el = Roo.get(el);
19874 this.dragData = {};
19876 Roo.apply(this, config);
19879 this.proxy = new Roo.dd.StatusProxy();
19882 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19883 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19885 this.dragging = false;
19888 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19890 * @cfg {String} dropAllowed
19891 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19893 dropAllowed : "x-dd-drop-ok",
19895 * @cfg {String} dropNotAllowed
19896 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19898 dropNotAllowed : "x-dd-drop-nodrop",
19901 * Returns the data object associated with this drag source
19902 * @return {Object} data An object containing arbitrary data
19904 getDragData : function(e){
19905 return this.dragData;
19909 onDragEnter : function(e, id){
19910 var target = Roo.dd.DragDropMgr.getDDById(id);
19911 this.cachedTarget = target;
19912 if(this.beforeDragEnter(target, e, id) !== false){
19913 if(target.isNotifyTarget){
19914 var status = target.notifyEnter(this, e, this.dragData);
19915 this.proxy.setStatus(status);
19917 this.proxy.setStatus(this.dropAllowed);
19920 if(this.afterDragEnter){
19922 * An empty function by default, but provided so that you can perform a custom action
19923 * when the dragged item enters the drop target by providing an implementation.
19924 * @param {Roo.dd.DragDrop} target The drop target
19925 * @param {Event} e The event object
19926 * @param {String} id The id of the dragged element
19927 * @method afterDragEnter
19929 this.afterDragEnter(target, e, id);
19935 * An empty function by default, but provided so that you can perform a custom action
19936 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
19937 * @param {Roo.dd.DragDrop} target The drop target
19938 * @param {Event} e The event object
19939 * @param {String} id The id of the dragged element
19940 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19942 beforeDragEnter : function(target, e, id){
19947 alignElWithMouse: function() {
19948 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
19953 onDragOver : function(e, id){
19954 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19955 if(this.beforeDragOver(target, e, id) !== false){
19956 if(target.isNotifyTarget){
19957 var status = target.notifyOver(this, e, this.dragData);
19958 this.proxy.setStatus(status);
19961 if(this.afterDragOver){
19963 * An empty function by default, but provided so that you can perform a custom action
19964 * while the dragged item is over the drop target by providing an implementation.
19965 * @param {Roo.dd.DragDrop} target The drop target
19966 * @param {Event} e The event object
19967 * @param {String} id The id of the dragged element
19968 * @method afterDragOver
19970 this.afterDragOver(target, e, id);
19976 * An empty function by default, but provided so that you can perform a custom action
19977 * while the dragged item is over the drop target and optionally cancel the onDragOver.
19978 * @param {Roo.dd.DragDrop} target The drop target
19979 * @param {Event} e The event object
19980 * @param {String} id The id of the dragged element
19981 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19983 beforeDragOver : function(target, e, id){
19988 onDragOut : function(e, id){
19989 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19990 if(this.beforeDragOut(target, e, id) !== false){
19991 if(target.isNotifyTarget){
19992 target.notifyOut(this, e, this.dragData);
19994 this.proxy.reset();
19995 if(this.afterDragOut){
19997 * An empty function by default, but provided so that you can perform a custom action
19998 * after the dragged item is dragged out of the target without dropping.
19999 * @param {Roo.dd.DragDrop} target The drop target
20000 * @param {Event} e The event object
20001 * @param {String} id The id of the dragged element
20002 * @method afterDragOut
20004 this.afterDragOut(target, e, id);
20007 this.cachedTarget = null;
20011 * An empty function by default, but provided so that you can perform a custom action before the dragged
20012 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20013 * @param {Roo.dd.DragDrop} target The drop target
20014 * @param {Event} e The event object
20015 * @param {String} id The id of the dragged element
20016 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20018 beforeDragOut : function(target, e, id){
20023 onDragDrop : function(e, id){
20024 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20025 if(this.beforeDragDrop(target, e, id) !== false){
20026 if(target.isNotifyTarget){
20027 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20028 this.onValidDrop(target, e, id);
20030 this.onInvalidDrop(target, e, id);
20033 this.onValidDrop(target, e, id);
20036 if(this.afterDragDrop){
20038 * An empty function by default, but provided so that you can perform a custom action
20039 * after a valid drag drop has occurred by providing an implementation.
20040 * @param {Roo.dd.DragDrop} target The drop target
20041 * @param {Event} e The event object
20042 * @param {String} id The id of the dropped element
20043 * @method afterDragDrop
20045 this.afterDragDrop(target, e, id);
20048 delete this.cachedTarget;
20052 * An empty function by default, but provided so that you can perform a custom action before the dragged
20053 * item is dropped onto the target and optionally cancel the onDragDrop.
20054 * @param {Roo.dd.DragDrop} target The drop target
20055 * @param {Event} e The event object
20056 * @param {String} id The id of the dragged element
20057 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20059 beforeDragDrop : function(target, e, id){
20064 onValidDrop : function(target, e, id){
20066 if(this.afterValidDrop){
20068 * An empty function by default, but provided so that you can perform a custom action
20069 * after a valid drop has occurred by providing an implementation.
20070 * @param {Object} target The target DD
20071 * @param {Event} e The event object
20072 * @param {String} id The id of the dropped element
20073 * @method afterInvalidDrop
20075 this.afterValidDrop(target, e, id);
20080 getRepairXY : function(e, data){
20081 return this.el.getXY();
20085 onInvalidDrop : function(target, e, id){
20086 this.beforeInvalidDrop(target, e, id);
20087 if(this.cachedTarget){
20088 if(this.cachedTarget.isNotifyTarget){
20089 this.cachedTarget.notifyOut(this, e, this.dragData);
20091 this.cacheTarget = null;
20093 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20095 if(this.afterInvalidDrop){
20097 * An empty function by default, but provided so that you can perform a custom action
20098 * after an invalid drop has occurred by providing an implementation.
20099 * @param {Event} e The event object
20100 * @param {String} id The id of the dropped element
20101 * @method afterInvalidDrop
20103 this.afterInvalidDrop(e, id);
20108 afterRepair : function(){
20110 this.el.highlight(this.hlColor || "c3daf9");
20112 this.dragging = false;
20116 * An empty function by default, but provided so that you can perform a custom action after an invalid
20117 * drop has occurred.
20118 * @param {Roo.dd.DragDrop} target The drop target
20119 * @param {Event} e The event object
20120 * @param {String} id The id of the dragged element
20121 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20123 beforeInvalidDrop : function(target, e, id){
20128 handleMouseDown : function(e){
20129 if(this.dragging) {
20132 var data = this.getDragData(e);
20133 if(data && this.onBeforeDrag(data, e) !== false){
20134 this.dragData = data;
20136 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20141 * An empty function by default, but provided so that you can perform a custom action before the initial
20142 * drag event begins and optionally cancel it.
20143 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20144 * @param {Event} e The event object
20145 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20147 onBeforeDrag : function(data, e){
20152 * An empty function by default, but provided so that you can perform a custom action once the initial
20153 * drag event has begun. The drag cannot be canceled from this function.
20154 * @param {Number} x The x position of the click on the dragged object
20155 * @param {Number} y The y position of the click on the dragged object
20157 onStartDrag : Roo.emptyFn,
20159 // private - YUI override
20160 startDrag : function(x, y){
20161 this.proxy.reset();
20162 this.dragging = true;
20163 this.proxy.update("");
20164 this.onInitDrag(x, y);
20169 onInitDrag : function(x, y){
20170 var clone = this.el.dom.cloneNode(true);
20171 clone.id = Roo.id(); // prevent duplicate ids
20172 this.proxy.update(clone);
20173 this.onStartDrag(x, y);
20178 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20179 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20181 getProxy : function(){
20186 * Hides the drag source's {@link Roo.dd.StatusProxy}
20188 hideProxy : function(){
20190 this.proxy.reset(true);
20191 this.dragging = false;
20195 triggerCacheRefresh : function(){
20196 Roo.dd.DDM.refreshCache(this.groups);
20199 // private - override to prevent hiding
20200 b4EndDrag: function(e) {
20203 // private - override to prevent moving
20204 endDrag : function(e){
20205 this.onEndDrag(this.dragData, e);
20209 onEndDrag : function(data, e){
20212 // private - pin to cursor
20213 autoOffset : function(x, y) {
20214 this.setDelta(-12, -20);
20218 * Ext JS Library 1.1.1
20219 * Copyright(c) 2006-2007, Ext JS, LLC.
20221 * Originally Released Under LGPL - original licence link has changed is not relivant.
20224 * <script type="text/javascript">
20229 * @class Roo.dd.DropTarget
20230 * @extends Roo.dd.DDTarget
20231 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20232 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20234 * @param {String/HTMLElement/Element} el The container element
20235 * @param {Object} config
20237 Roo.dd.DropTarget = function(el, config){
20238 this.el = Roo.get(el);
20240 var listeners = false; ;
20241 if (config && config.listeners) {
20242 listeners= config.listeners;
20243 delete config.listeners;
20245 Roo.apply(this, config);
20247 if(this.containerScroll){
20248 Roo.dd.ScrollManager.register(this.el);
20252 * @scope Roo.dd.DropTarget
20257 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20258 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20259 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20261 * IMPORTANT : it should set this.overClass and this.dropAllowed
20263 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20264 * @param {Event} e The event
20265 * @param {Object} data An object containing arbitrary data supplied by the drag source
20271 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20272 * This method will be called on every mouse movement while the drag source is over the drop target.
20273 * This default implementation simply returns the dropAllowed config value.
20275 * IMPORTANT : it should set this.dropAllowed
20277 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20278 * @param {Event} e The event
20279 * @param {Object} data An object containing arbitrary data supplied by the drag source
20285 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20286 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20287 * overClass (if any) from the drop element.
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 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20298 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20299 * implementation that does something to process the drop event and returns true so that the drag source's
20300 * repair action does not run.
20302 * IMPORTANT : it should set this.success
20304 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20305 * @param {Event} e The event
20306 * @param {Object} data An object containing arbitrary data supplied by the drag source
20312 Roo.dd.DropTarget.superclass.constructor.call( this,
20314 this.ddGroup || this.group,
20317 listeners : listeners || {}
20325 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20327 * @cfg {String} overClass
20328 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20331 * @cfg {String} ddGroup
20332 * The drag drop group to handle drop events for
20336 * @cfg {String} dropAllowed
20337 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20339 dropAllowed : "x-dd-drop-ok",
20341 * @cfg {String} dropNotAllowed
20342 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20344 dropNotAllowed : "x-dd-drop-nodrop",
20346 * @cfg {boolean} success
20347 * set this after drop listener..
20351 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20352 * if the drop point is valid for over/enter..
20359 isNotifyTarget : true,
20364 notifyEnter : function(dd, e, data)
20367 this.fireEvent('enter', dd, e, data);
20368 if(this.overClass){
20369 this.el.addClass(this.overClass);
20371 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20372 this.valid ? this.dropAllowed : this.dropNotAllowed
20379 notifyOver : function(dd, e, data)
20382 this.fireEvent('over', dd, e, data);
20383 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20384 this.valid ? this.dropAllowed : this.dropNotAllowed
20391 notifyOut : function(dd, e, data)
20393 this.fireEvent('out', dd, e, data);
20394 if(this.overClass){
20395 this.el.removeClass(this.overClass);
20402 notifyDrop : function(dd, e, data)
20404 this.success = false;
20405 this.fireEvent('drop', dd, e, data);
20406 return this.success;
20410 * Ext JS Library 1.1.1
20411 * Copyright(c) 2006-2007, Ext JS, LLC.
20413 * Originally Released Under LGPL - original licence link has changed is not relivant.
20416 * <script type="text/javascript">
20421 * @class Roo.dd.DragZone
20422 * @extends Roo.dd.DragSource
20423 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20424 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20426 * @param {String/HTMLElement/Element} el The container element
20427 * @param {Object} config
20429 Roo.dd.DragZone = function(el, config){
20430 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20431 if(this.containerScroll){
20432 Roo.dd.ScrollManager.register(this.el);
20436 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20438 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20439 * for auto scrolling during drag operations.
20442 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20443 * method after a failed drop (defaults to "c3daf9" - light blue)
20447 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20448 * for a valid target to drag based on the mouse down. Override this method
20449 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20450 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20451 * @param {EventObject} e The mouse down event
20452 * @return {Object} The dragData
20454 getDragData : function(e){
20455 return Roo.dd.Registry.getHandleFromEvent(e);
20459 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20460 * this.dragData.ddel
20461 * @param {Number} x The x position of the click on the dragged object
20462 * @param {Number} y The y position of the click on the dragged object
20463 * @return {Boolean} true to continue the drag, false to cancel
20465 onInitDrag : function(x, y){
20466 this.proxy.update(this.dragData.ddel.cloneNode(true));
20467 this.onStartDrag(x, y);
20472 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20474 afterRepair : function(){
20476 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20478 this.dragging = false;
20482 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20483 * the XY of this.dragData.ddel
20484 * @param {EventObject} e The mouse up event
20485 * @return {Array} The xy location (e.g. [100, 200])
20487 getRepairXY : function(e){
20488 return Roo.Element.fly(this.dragData.ddel).getXY();
20492 * Ext JS Library 1.1.1
20493 * Copyright(c) 2006-2007, Ext JS, LLC.
20495 * Originally Released Under LGPL - original licence link has changed is not relivant.
20498 * <script type="text/javascript">
20501 * @class Roo.dd.DropZone
20502 * @extends Roo.dd.DropTarget
20503 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20504 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20506 * @param {String/HTMLElement/Element} el The container element
20507 * @param {Object} config
20509 Roo.dd.DropZone = function(el, config){
20510 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20513 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20515 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20516 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20517 * provide your own custom lookup.
20518 * @param {Event} e The event
20519 * @return {Object} data The custom data
20521 getTargetFromEvent : function(e){
20522 return Roo.dd.Registry.getTargetFromEvent(e);
20526 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20527 * that it has registered. This method has no default implementation and should be overridden to provide
20528 * node-specific processing if necessary.
20529 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20530 * {@link #getTargetFromEvent} for this node)
20531 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20532 * @param {Event} e The event
20533 * @param {Object} data An object containing arbitrary data supplied by the drag source
20535 onNodeEnter : function(n, dd, e, data){
20540 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20541 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20542 * overridden to provide the proper feedback.
20543 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20544 * {@link #getTargetFromEvent} for this node)
20545 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20546 * @param {Event} e The event
20547 * @param {Object} data An object containing arbitrary data supplied by the drag source
20548 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20549 * underlying {@link Roo.dd.StatusProxy} can be updated
20551 onNodeOver : function(n, dd, e, data){
20552 return this.dropAllowed;
20556 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20557 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20558 * node-specific processing if necessary.
20559 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20560 * {@link #getTargetFromEvent} for this node)
20561 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20562 * @param {Event} e The event
20563 * @param {Object} data An object containing arbitrary data supplied by the drag source
20565 onNodeOut : function(n, dd, e, data){
20570 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20571 * the drop node. The default implementation returns false, so it should be overridden to provide the
20572 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20573 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20574 * {@link #getTargetFromEvent} for this node)
20575 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20576 * @param {Event} e The event
20577 * @param {Object} data An object containing arbitrary data supplied by the drag source
20578 * @return {Boolean} True if the drop was valid, else false
20580 onNodeDrop : function(n, dd, e, data){
20585 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20586 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20587 * it should be overridden to provide the proper feedback if necessary.
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 {String} status The CSS class that communicates the drop status back to the source so that the
20592 * underlying {@link Roo.dd.StatusProxy} can be updated
20594 onContainerOver : function(dd, e, data){
20595 return this.dropNotAllowed;
20599 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20600 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20601 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20602 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20603 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20604 * @param {Event} e The event
20605 * @param {Object} data An object containing arbitrary data supplied by the drag source
20606 * @return {Boolean} True if the drop was valid, else false
20608 onContainerDrop : function(dd, e, data){
20613 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20614 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20615 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20616 * you should override this method and provide a custom implementation.
20617 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20618 * @param {Event} e The event
20619 * @param {Object} data An object containing arbitrary data supplied by the drag source
20620 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20621 * underlying {@link Roo.dd.StatusProxy} can be updated
20623 notifyEnter : function(dd, e, data){
20624 return this.dropNotAllowed;
20628 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20629 * This method will be called on every mouse movement while the drag source is over the drop zone.
20630 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20631 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20632 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20633 * registered node, it will call {@link #onContainerOver}.
20634 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20635 * @param {Event} e The event
20636 * @param {Object} data An object containing arbitrary data supplied by the drag source
20637 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20638 * underlying {@link Roo.dd.StatusProxy} can be updated
20640 notifyOver : function(dd, e, data){
20641 var n = this.getTargetFromEvent(e);
20642 if(!n){ // not over valid drop target
20643 if(this.lastOverNode){
20644 this.onNodeOut(this.lastOverNode, dd, e, data);
20645 this.lastOverNode = null;
20647 return this.onContainerOver(dd, e, data);
20649 if(this.lastOverNode != n){
20650 if(this.lastOverNode){
20651 this.onNodeOut(this.lastOverNode, dd, e, data);
20653 this.onNodeEnter(n, dd, e, data);
20654 this.lastOverNode = n;
20656 return this.onNodeOver(n, dd, e, data);
20660 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20661 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20662 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20663 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20664 * @param {Event} e The event
20665 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20667 notifyOut : function(dd, e, data){
20668 if(this.lastOverNode){
20669 this.onNodeOut(this.lastOverNode, dd, e, data);
20670 this.lastOverNode = null;
20675 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20676 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20677 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20678 * otherwise it will call {@link #onContainerDrop}.
20679 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20680 * @param {Event} e The event
20681 * @param {Object} data An object containing arbitrary data supplied by the drag source
20682 * @return {Boolean} True if the drop was valid, else false
20684 notifyDrop : function(dd, e, data){
20685 if(this.lastOverNode){
20686 this.onNodeOut(this.lastOverNode, dd, e, data);
20687 this.lastOverNode = null;
20689 var n = this.getTargetFromEvent(e);
20691 this.onNodeDrop(n, dd, e, data) :
20692 this.onContainerDrop(dd, e, data);
20696 triggerCacheRefresh : function(){
20697 Roo.dd.DDM.refreshCache(this.groups);
20701 * Ext JS Library 1.1.1
20702 * Copyright(c) 2006-2007, Ext JS, LLC.
20704 * Originally Released Under LGPL - original licence link has changed is not relivant.
20707 * <script type="text/javascript">
20712 * @class Roo.data.SortTypes
20714 * Defines the default sorting (casting?) comparison functions used when sorting data.
20716 Roo.data.SortTypes = {
20718 * Default sort that does nothing
20719 * @param {Mixed} s The value being converted
20720 * @return {Mixed} The comparison value
20722 none : function(s){
20727 * The regular expression used to strip tags
20731 stripTagsRE : /<\/?[^>]+>/gi,
20734 * Strips all HTML tags to sort on text only
20735 * @param {Mixed} s The value being converted
20736 * @return {String} The comparison value
20738 asText : function(s){
20739 return String(s).replace(this.stripTagsRE, "");
20743 * Strips all HTML tags to sort on text only - Case insensitive
20744 * @param {Mixed} s The value being converted
20745 * @return {String} The comparison value
20747 asUCText : function(s){
20748 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20752 * Case insensitive string
20753 * @param {Mixed} s The value being converted
20754 * @return {String} The comparison value
20756 asUCString : function(s) {
20757 return String(s).toUpperCase();
20762 * @param {Mixed} s The value being converted
20763 * @return {Number} The comparison value
20765 asDate : function(s) {
20769 if(s instanceof Date){
20770 return s.getTime();
20772 return Date.parse(String(s));
20777 * @param {Mixed} s The value being converted
20778 * @return {Float} The comparison value
20780 asFloat : function(s) {
20781 var val = parseFloat(String(s).replace(/,/g, ""));
20782 if(isNaN(val)) val = 0;
20788 * @param {Mixed} s The value being converted
20789 * @return {Number} The comparison value
20791 asInt : function(s) {
20792 var val = parseInt(String(s).replace(/,/g, ""));
20793 if(isNaN(val)) val = 0;
20798 * Ext JS Library 1.1.1
20799 * Copyright(c) 2006-2007, Ext JS, LLC.
20801 * Originally Released Under LGPL - original licence link has changed is not relivant.
20804 * <script type="text/javascript">
20808 * @class Roo.data.Record
20809 * Instances of this class encapsulate both record <em>definition</em> information, and record
20810 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20811 * to access Records cached in an {@link Roo.data.Store} object.<br>
20813 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20814 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20817 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20819 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20820 * {@link #create}. The parameters are the same.
20821 * @param {Array} data An associative Array of data values keyed by the field name.
20822 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20823 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20824 * not specified an integer id is generated.
20826 Roo.data.Record = function(data, id){
20827 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20832 * Generate a constructor for a specific record layout.
20833 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20834 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20835 * Each field definition object may contain the following properties: <ul>
20836 * <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,
20837 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20838 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20839 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20840 * is being used, then this is a string containing the javascript expression to reference the data relative to
20841 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20842 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20843 * this may be omitted.</p></li>
20844 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20845 * <ul><li>auto (Default, implies no conversion)</li>
20850 * <li>date</li></ul></p></li>
20851 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20852 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20853 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20854 * by the Reader into an object that will be stored in the Record. It is passed the
20855 * following parameters:<ul>
20856 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20858 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20860 * <br>usage:<br><pre><code>
20861 var TopicRecord = Roo.data.Record.create(
20862 {name: 'title', mapping: 'topic_title'},
20863 {name: 'author', mapping: 'username'},
20864 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20865 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20866 {name: 'lastPoster', mapping: 'user2'},
20867 {name: 'excerpt', mapping: 'post_text'}
20870 var myNewRecord = new TopicRecord({
20871 title: 'Do my job please',
20874 lastPost: new Date(),
20875 lastPoster: 'Animal',
20876 excerpt: 'No way dude!'
20878 myStore.add(myNewRecord);
20883 Roo.data.Record.create = function(o){
20884 var f = function(){
20885 f.superclass.constructor.apply(this, arguments);
20887 Roo.extend(f, Roo.data.Record);
20888 var p = f.prototype;
20889 p.fields = new Roo.util.MixedCollection(false, function(field){
20892 for(var i = 0, len = o.length; i < len; i++){
20893 p.fields.add(new Roo.data.Field(o[i]));
20895 f.getField = function(name){
20896 return p.fields.get(name);
20901 Roo.data.Record.AUTO_ID = 1000;
20902 Roo.data.Record.EDIT = 'edit';
20903 Roo.data.Record.REJECT = 'reject';
20904 Roo.data.Record.COMMIT = 'commit';
20906 Roo.data.Record.prototype = {
20908 * Readonly flag - true if this record has been modified.
20917 join : function(store){
20918 this.store = store;
20922 * Set the named field to the specified value.
20923 * @param {String} name The name of the field to set.
20924 * @param {Object} value The value to set the field to.
20926 set : function(name, value){
20927 if(this.data[name] == value){
20931 if(!this.modified){
20932 this.modified = {};
20934 if(typeof this.modified[name] == 'undefined'){
20935 this.modified[name] = this.data[name];
20937 this.data[name] = value;
20938 if(!this.editing && this.store){
20939 this.store.afterEdit(this);
20944 * Get the value of the named field.
20945 * @param {String} name The name of the field to get the value of.
20946 * @return {Object} The value of the field.
20948 get : function(name){
20949 return this.data[name];
20953 beginEdit : function(){
20954 this.editing = true;
20955 this.modified = {};
20959 cancelEdit : function(){
20960 this.editing = false;
20961 delete this.modified;
20965 endEdit : function(){
20966 this.editing = false;
20967 if(this.dirty && this.store){
20968 this.store.afterEdit(this);
20973 * Usually called by the {@link Roo.data.Store} which owns the Record.
20974 * Rejects all changes made to the Record since either creation, or the last commit operation.
20975 * Modified fields are reverted to their original values.
20977 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20978 * of reject operations.
20980 reject : function(){
20981 var m = this.modified;
20983 if(typeof m[n] != "function"){
20984 this.data[n] = m[n];
20987 this.dirty = false;
20988 delete this.modified;
20989 this.editing = false;
20991 this.store.afterReject(this);
20996 * Usually called by the {@link Roo.data.Store} which owns the Record.
20997 * Commits all changes made to the Record since either creation, or the last commit operation.
20999 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21000 * of commit operations.
21002 commit : function(){
21003 this.dirty = false;
21004 delete this.modified;
21005 this.editing = false;
21007 this.store.afterCommit(this);
21012 hasError : function(){
21013 return this.error != null;
21017 clearError : function(){
21022 * Creates a copy of this record.
21023 * @param {String} id (optional) A new record id if you don't want to use this record's id
21026 copy : function(newId) {
21027 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21031 * Ext JS Library 1.1.1
21032 * Copyright(c) 2006-2007, Ext JS, LLC.
21034 * Originally Released Under LGPL - original licence link has changed is not relivant.
21037 * <script type="text/javascript">
21043 * @class Roo.data.Store
21044 * @extends Roo.util.Observable
21045 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21046 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21048 * 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
21049 * has no knowledge of the format of the data returned by the Proxy.<br>
21051 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21052 * instances from the data object. These records are cached and made available through accessor functions.
21054 * Creates a new Store.
21055 * @param {Object} config A config object containing the objects needed for the Store to access data,
21056 * and read the data into Records.
21058 Roo.data.Store = function(config){
21059 this.data = new Roo.util.MixedCollection(false);
21060 this.data.getKey = function(o){
21063 this.baseParams = {};
21065 this.paramNames = {
21070 "multisort" : "_multisort"
21073 if(config && config.data){
21074 this.inlineData = config.data;
21075 delete config.data;
21078 Roo.apply(this, config);
21080 if(this.reader){ // reader passed
21081 this.reader = Roo.factory(this.reader, Roo.data);
21082 this.reader.xmodule = this.xmodule || false;
21083 if(!this.recordType){
21084 this.recordType = this.reader.recordType;
21086 if(this.reader.onMetaChange){
21087 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21091 if(this.recordType){
21092 this.fields = this.recordType.prototype.fields;
21094 this.modified = [];
21098 * @event datachanged
21099 * Fires when the data cache has changed, and a widget which is using this Store
21100 * as a Record cache should refresh its view.
21101 * @param {Store} this
21103 datachanged : true,
21105 * @event metachange
21106 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21107 * @param {Store} this
21108 * @param {Object} meta The JSON metadata
21113 * Fires when Records have been added to the Store
21114 * @param {Store} this
21115 * @param {Roo.data.Record[]} records The array of Records added
21116 * @param {Number} index The index at which the record(s) were added
21121 * Fires when a Record has been removed from the Store
21122 * @param {Store} this
21123 * @param {Roo.data.Record} record The Record that was removed
21124 * @param {Number} index The index at which the record was removed
21129 * Fires when a Record has been updated
21130 * @param {Store} this
21131 * @param {Roo.data.Record} record The Record that was updated
21132 * @param {String} operation The update operation being performed. Value may be one of:
21134 Roo.data.Record.EDIT
21135 Roo.data.Record.REJECT
21136 Roo.data.Record.COMMIT
21142 * Fires when the data cache has been cleared.
21143 * @param {Store} this
21147 * @event beforeload
21148 * Fires before a request is made for a new data object. If the beforeload handler returns false
21149 * the load action will be canceled.
21150 * @param {Store} this
21151 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21155 * @event beforeloadadd
21156 * Fires after a new set of Records has been loaded.
21157 * @param {Store} this
21158 * @param {Roo.data.Record[]} records The Records that were loaded
21159 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21161 beforeloadadd : true,
21164 * Fires after a new set of Records has been loaded, before they are added to the store.
21165 * @param {Store} this
21166 * @param {Roo.data.Record[]} records The Records that were loaded
21167 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21168 * @params {Object} return from reader
21172 * @event loadexception
21173 * Fires if an exception occurs in the Proxy during loading.
21174 * Called with the signature of the Proxy's "loadexception" event.
21175 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21178 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21179 * @param {Object} load options
21180 * @param {Object} jsonData from your request (normally this contains the Exception)
21182 loadexception : true
21186 this.proxy = Roo.factory(this.proxy, Roo.data);
21187 this.proxy.xmodule = this.xmodule || false;
21188 this.relayEvents(this.proxy, ["loadexception"]);
21190 this.sortToggle = {};
21191 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21193 Roo.data.Store.superclass.constructor.call(this);
21195 if(this.inlineData){
21196 this.loadData(this.inlineData);
21197 delete this.inlineData;
21201 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21203 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21204 * without a remote query - used by combo/forms at present.
21208 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21211 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21214 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21215 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21218 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21219 * on any HTTP request
21222 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21225 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21229 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21230 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21232 remoteSort : false,
21235 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21236 * loaded or when a record is removed. (defaults to false).
21238 pruneModifiedRecords : false,
21241 lastOptions : null,
21244 * Add Records to the Store and fires the add event.
21245 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21247 add : function(records){
21248 records = [].concat(records);
21249 for(var i = 0, len = records.length; i < len; i++){
21250 records[i].join(this);
21252 var index = this.data.length;
21253 this.data.addAll(records);
21254 this.fireEvent("add", this, records, index);
21258 * Remove a Record from the Store and fires the remove event.
21259 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21261 remove : function(record){
21262 var index = this.data.indexOf(record);
21263 this.data.removeAt(index);
21264 if(this.pruneModifiedRecords){
21265 this.modified.remove(record);
21267 this.fireEvent("remove", this, record, index);
21271 * Remove all Records from the Store and fires the clear event.
21273 removeAll : function(){
21275 if(this.pruneModifiedRecords){
21276 this.modified = [];
21278 this.fireEvent("clear", this);
21282 * Inserts Records to the Store at the given index and fires the add event.
21283 * @param {Number} index The start index at which to insert the passed Records.
21284 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21286 insert : function(index, records){
21287 records = [].concat(records);
21288 for(var i = 0, len = records.length; i < len; i++){
21289 this.data.insert(index, records[i]);
21290 records[i].join(this);
21292 this.fireEvent("add", this, records, index);
21296 * Get the index within the cache of the passed Record.
21297 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21298 * @return {Number} The index of the passed Record. Returns -1 if not found.
21300 indexOf : function(record){
21301 return this.data.indexOf(record);
21305 * Get the index within the cache of the Record with the passed id.
21306 * @param {String} id The id of the Record to find.
21307 * @return {Number} The index of the Record. Returns -1 if not found.
21309 indexOfId : function(id){
21310 return this.data.indexOfKey(id);
21314 * Get the Record with the specified id.
21315 * @param {String} id The id of the Record to find.
21316 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21318 getById : function(id){
21319 return this.data.key(id);
21323 * Get the Record at the specified index.
21324 * @param {Number} index The index of the Record to find.
21325 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21327 getAt : function(index){
21328 return this.data.itemAt(index);
21332 * Returns a range of Records between specified indices.
21333 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21334 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21335 * @return {Roo.data.Record[]} An array of Records
21337 getRange : function(start, end){
21338 return this.data.getRange(start, end);
21342 storeOptions : function(o){
21343 o = Roo.apply({}, o);
21346 this.lastOptions = o;
21350 * Loads the Record cache from the configured Proxy using the configured Reader.
21352 * If using remote paging, then the first load call must specify the <em>start</em>
21353 * and <em>limit</em> properties in the options.params property to establish the initial
21354 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21356 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21357 * and this call will return before the new data has been loaded. Perform any post-processing
21358 * in a callback function, or in a "load" event handler.</strong>
21360 * @param {Object} options An object containing properties which control loading options:<ul>
21361 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21362 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21363 * passed the following arguments:<ul>
21364 * <li>r : Roo.data.Record[]</li>
21365 * <li>options: Options object from the load call</li>
21366 * <li>success: Boolean success indicator</li></ul></li>
21367 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21368 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21371 load : function(options){
21372 options = options || {};
21373 if(this.fireEvent("beforeload", this, options) !== false){
21374 this.storeOptions(options);
21375 var p = Roo.apply(options.params || {}, this.baseParams);
21376 // if meta was not loaded from remote source.. try requesting it.
21377 if (!this.reader.metaFromRemote) {
21378 p._requestMeta = 1;
21380 if(this.sortInfo && this.remoteSort){
21381 var pn = this.paramNames;
21382 p[pn["sort"]] = this.sortInfo.field;
21383 p[pn["dir"]] = this.sortInfo.direction;
21385 if (this.multiSort) {
21386 var pn = this.paramNames;
21387 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21390 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21395 * Reloads the Record cache from the configured Proxy using the configured Reader and
21396 * the options from the last load operation performed.
21397 * @param {Object} options (optional) An object containing properties which may override the options
21398 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21399 * the most recently used options are reused).
21401 reload : function(options){
21402 this.load(Roo.applyIf(options||{}, this.lastOptions));
21406 // Called as a callback by the Reader during a load operation.
21407 loadRecords : function(o, options, success){
21408 if(!o || success === false){
21409 if(success !== false){
21410 this.fireEvent("load", this, [], options, o);
21412 if(options.callback){
21413 options.callback.call(options.scope || this, [], options, false);
21417 // if data returned failure - throw an exception.
21418 if (o.success === false) {
21419 // show a message if no listener is registered.
21420 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21421 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21423 // loadmask wil be hooked into this..
21424 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21427 var r = o.records, t = o.totalRecords || r.length;
21429 this.fireEvent("beforeloadadd", this, r, options, o);
21431 if(!options || options.add !== true){
21432 if(this.pruneModifiedRecords){
21433 this.modified = [];
21435 for(var i = 0, len = r.length; i < len; i++){
21439 this.data = this.snapshot;
21440 delete this.snapshot;
21443 this.data.addAll(r);
21444 this.totalLength = t;
21446 this.fireEvent("datachanged", this);
21448 this.totalLength = Math.max(t, this.data.length+r.length);
21451 this.fireEvent("load", this, r, options, o);
21452 if(options.callback){
21453 options.callback.call(options.scope || this, r, options, true);
21459 * Loads data from a passed data block. A Reader which understands the format of the data
21460 * must have been configured in the constructor.
21461 * @param {Object} data The data block from which to read the Records. The format of the data expected
21462 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21463 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21465 loadData : function(o, append){
21466 var r = this.reader.readRecords(o);
21467 this.loadRecords(r, {add: append}, true);
21471 * Gets the number of cached records.
21473 * <em>If using paging, this may not be the total size of the dataset. If the data object
21474 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21475 * the data set size</em>
21477 getCount : function(){
21478 return this.data.length || 0;
21482 * Gets the total number of records in the dataset as returned by the server.
21484 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21485 * the dataset size</em>
21487 getTotalCount : function(){
21488 return this.totalLength || 0;
21492 * Returns the sort state of the Store as an object with two properties:
21494 field {String} The name of the field by which the Records are sorted
21495 direction {String} The sort order, "ASC" or "DESC"
21498 getSortState : function(){
21499 return this.sortInfo;
21503 applySort : function(){
21504 if(this.sortInfo && !this.remoteSort){
21505 var s = this.sortInfo, f = s.field;
21506 var st = this.fields.get(f).sortType;
21507 var fn = function(r1, r2){
21508 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21509 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21511 this.data.sort(s.direction, fn);
21512 if(this.snapshot && this.snapshot != this.data){
21513 this.snapshot.sort(s.direction, fn);
21519 * Sets the default sort column and order to be used by the next load operation.
21520 * @param {String} fieldName The name of the field to sort by.
21521 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21523 setDefaultSort : function(field, dir){
21524 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21528 * Sort the Records.
21529 * If remote sorting is used, the sort is performed on the server, and the cache is
21530 * reloaded. If local sorting is used, the cache is sorted internally.
21531 * @param {String} fieldName The name of the field to sort by.
21532 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21534 sort : function(fieldName, dir){
21535 var f = this.fields.get(fieldName);
21537 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21539 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21540 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21545 this.sortToggle[f.name] = dir;
21546 this.sortInfo = {field: f.name, direction: dir};
21547 if(!this.remoteSort){
21549 this.fireEvent("datachanged", this);
21551 this.load(this.lastOptions);
21556 * Calls the specified function for each of the Records in the cache.
21557 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21558 * Returning <em>false</em> aborts and exits the iteration.
21559 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21561 each : function(fn, scope){
21562 this.data.each(fn, scope);
21566 * Gets all records modified since the last commit. Modified records are persisted across load operations
21567 * (e.g., during paging).
21568 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21570 getModifiedRecords : function(){
21571 return this.modified;
21575 createFilterFn : function(property, value, anyMatch){
21576 if(!value.exec){ // not a regex
21577 value = String(value);
21578 if(value.length == 0){
21581 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21583 return function(r){
21584 return value.test(r.data[property]);
21589 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21590 * @param {String} property A field on your records
21591 * @param {Number} start The record index to start at (defaults to 0)
21592 * @param {Number} end The last record index to include (defaults to length - 1)
21593 * @return {Number} The sum
21595 sum : function(property, start, end){
21596 var rs = this.data.items, v = 0;
21597 start = start || 0;
21598 end = (end || end === 0) ? end : rs.length-1;
21600 for(var i = start; i <= end; i++){
21601 v += (rs[i].data[property] || 0);
21607 * Filter the records by a specified property.
21608 * @param {String} field A field on your records
21609 * @param {String/RegExp} value Either a string that the field
21610 * should start with or a RegExp to test against the field
21611 * @param {Boolean} anyMatch True to match any part not just the beginning
21613 filter : function(property, value, anyMatch){
21614 var fn = this.createFilterFn(property, value, anyMatch);
21615 return fn ? this.filterBy(fn) : this.clearFilter();
21619 * Filter by a function. The specified function will be called with each
21620 * record in this data source. If the function returns true the record is included,
21621 * otherwise it is filtered.
21622 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21623 * @param {Object} scope (optional) The scope of the function (defaults to this)
21625 filterBy : function(fn, scope){
21626 this.snapshot = this.snapshot || this.data;
21627 this.data = this.queryBy(fn, scope||this);
21628 this.fireEvent("datachanged", this);
21632 * Query the records by a specified property.
21633 * @param {String} field A field on your records
21634 * @param {String/RegExp} value Either a string that the field
21635 * should start with or a RegExp to test against the field
21636 * @param {Boolean} anyMatch True to match any part not just the beginning
21637 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21639 query : function(property, value, anyMatch){
21640 var fn = this.createFilterFn(property, value, anyMatch);
21641 return fn ? this.queryBy(fn) : this.data.clone();
21645 * Query by a function. The specified function will be called with each
21646 * record in this data source. If the function returns true the record is included
21648 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21649 * @param {Object} scope (optional) The scope of the function (defaults to this)
21650 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21652 queryBy : function(fn, scope){
21653 var data = this.snapshot || this.data;
21654 return data.filterBy(fn, scope||this);
21658 * Collects unique values for a particular dataIndex from this store.
21659 * @param {String} dataIndex The property to collect
21660 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21661 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21662 * @return {Array} An array of the unique values
21664 collect : function(dataIndex, allowNull, bypassFilter){
21665 var d = (bypassFilter === true && this.snapshot) ?
21666 this.snapshot.items : this.data.items;
21667 var v, sv, r = [], l = {};
21668 for(var i = 0, len = d.length; i < len; i++){
21669 v = d[i].data[dataIndex];
21671 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21680 * Revert to a view of the Record cache with no filtering applied.
21681 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21683 clearFilter : function(suppressEvent){
21684 if(this.snapshot && this.snapshot != this.data){
21685 this.data = this.snapshot;
21686 delete this.snapshot;
21687 if(suppressEvent !== true){
21688 this.fireEvent("datachanged", this);
21694 afterEdit : function(record){
21695 if(this.modified.indexOf(record) == -1){
21696 this.modified.push(record);
21698 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21702 afterReject : function(record){
21703 this.modified.remove(record);
21704 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21708 afterCommit : function(record){
21709 this.modified.remove(record);
21710 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21714 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21715 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21717 commitChanges : function(){
21718 var m = this.modified.slice(0);
21719 this.modified = [];
21720 for(var i = 0, len = m.length; i < len; i++){
21726 * Cancel outstanding changes on all changed records.
21728 rejectChanges : function(){
21729 var m = this.modified.slice(0);
21730 this.modified = [];
21731 for(var i = 0, len = m.length; i < len; i++){
21736 onMetaChange : function(meta, rtype, o){
21737 this.recordType = rtype;
21738 this.fields = rtype.prototype.fields;
21739 delete this.snapshot;
21740 this.sortInfo = meta.sortInfo || this.sortInfo;
21741 this.modified = [];
21742 this.fireEvent('metachange', this, this.reader.meta);
21745 moveIndex : function(data, type)
21747 var index = this.indexOf(data);
21749 var newIndex = index + type;
21753 this.insert(newIndex, data);
21758 * Ext JS Library 1.1.1
21759 * Copyright(c) 2006-2007, Ext JS, LLC.
21761 * Originally Released Under LGPL - original licence link has changed is not relivant.
21764 * <script type="text/javascript">
21768 * @class Roo.data.SimpleStore
21769 * @extends Roo.data.Store
21770 * Small helper class to make creating Stores from Array data easier.
21771 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21772 * @cfg {Array} fields An array of field definition objects, or field name strings.
21773 * @cfg {Array} data The multi-dimensional array of data
21775 * @param {Object} config
21777 Roo.data.SimpleStore = function(config){
21778 Roo.data.SimpleStore.superclass.constructor.call(this, {
21780 reader: new Roo.data.ArrayReader({
21783 Roo.data.Record.create(config.fields)
21785 proxy : new Roo.data.MemoryProxy(config.data)
21789 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21791 * Ext JS Library 1.1.1
21792 * Copyright(c) 2006-2007, Ext JS, LLC.
21794 * Originally Released Under LGPL - original licence link has changed is not relivant.
21797 * <script type="text/javascript">
21802 * @extends Roo.data.Store
21803 * @class Roo.data.JsonStore
21804 * Small helper class to make creating Stores for JSON data easier. <br/>
21806 var store = new Roo.data.JsonStore({
21807 url: 'get-images.php',
21809 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21812 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21813 * JsonReader and HttpProxy (unless inline data is provided).</b>
21814 * @cfg {Array} fields An array of field definition objects, or field name strings.
21816 * @param {Object} config
21818 Roo.data.JsonStore = function(c){
21819 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21820 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21821 reader: new Roo.data.JsonReader(c, c.fields)
21824 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21826 * Ext JS Library 1.1.1
21827 * Copyright(c) 2006-2007, Ext JS, LLC.
21829 * Originally Released Under LGPL - original licence link has changed is not relivant.
21832 * <script type="text/javascript">
21836 Roo.data.Field = function(config){
21837 if(typeof config == "string"){
21838 config = {name: config};
21840 Roo.apply(this, config);
21843 this.type = "auto";
21846 var st = Roo.data.SortTypes;
21847 // named sortTypes are supported, here we look them up
21848 if(typeof this.sortType == "string"){
21849 this.sortType = st[this.sortType];
21852 // set default sortType for strings and dates
21853 if(!this.sortType){
21856 this.sortType = st.asUCString;
21859 this.sortType = st.asDate;
21862 this.sortType = st.none;
21867 var stripRe = /[\$,%]/g;
21869 // prebuilt conversion function for this field, instead of
21870 // switching every time we're reading a value
21872 var cv, dateFormat = this.dateFormat;
21877 cv = function(v){ return v; };
21880 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21884 return v !== undefined && v !== null && v !== '' ?
21885 parseInt(String(v).replace(stripRe, ""), 10) : '';
21890 return v !== undefined && v !== null && v !== '' ?
21891 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21896 cv = function(v){ return v === true || v === "true" || v == 1; };
21903 if(v instanceof Date){
21907 if(dateFormat == "timestamp"){
21908 return new Date(v*1000);
21910 return Date.parseDate(v, dateFormat);
21912 var parsed = Date.parse(v);
21913 return parsed ? new Date(parsed) : null;
21922 Roo.data.Field.prototype = {
21930 * Ext JS Library 1.1.1
21931 * Copyright(c) 2006-2007, Ext JS, LLC.
21933 * Originally Released Under LGPL - original licence link has changed is not relivant.
21936 * <script type="text/javascript">
21939 // Base class for reading structured data from a data source. This class is intended to be
21940 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
21943 * @class Roo.data.DataReader
21944 * Base class for reading structured data from a data source. This class is intended to be
21945 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
21948 Roo.data.DataReader = function(meta, recordType){
21952 this.recordType = recordType instanceof Array ?
21953 Roo.data.Record.create(recordType) : recordType;
21956 Roo.data.DataReader.prototype = {
21958 * Create an empty record
21959 * @param {Object} data (optional) - overlay some values
21960 * @return {Roo.data.Record} record created.
21962 newRow : function(d) {
21964 this.recordType.prototype.fields.each(function(c) {
21966 case 'int' : da[c.name] = 0; break;
21967 case 'date' : da[c.name] = new Date(); break;
21968 case 'float' : da[c.name] = 0.0; break;
21969 case 'boolean' : da[c.name] = false; break;
21970 default : da[c.name] = ""; break;
21974 return new this.recordType(Roo.apply(da, d));
21979 * Ext JS Library 1.1.1
21980 * Copyright(c) 2006-2007, Ext JS, LLC.
21982 * Originally Released Under LGPL - original licence link has changed is not relivant.
21985 * <script type="text/javascript">
21989 * @class Roo.data.DataProxy
21990 * @extends Roo.data.Observable
21991 * This class is an abstract base class for implementations which provide retrieval of
21992 * unformatted data objects.<br>
21994 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
21995 * (of the appropriate type which knows how to parse the data object) to provide a block of
21996 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
21998 * Custom implementations must implement the load method as described in
21999 * {@link Roo.data.HttpProxy#load}.
22001 Roo.data.DataProxy = function(){
22004 * @event beforeload
22005 * Fires before a network request is made to retrieve a data object.
22006 * @param {Object} This DataProxy object.
22007 * @param {Object} params The params parameter to the load function.
22012 * Fires before the load method's callback is called.
22013 * @param {Object} This DataProxy object.
22014 * @param {Object} o The data object.
22015 * @param {Object} arg The callback argument object passed to the load function.
22019 * @event loadexception
22020 * Fires if an Exception occurs during data retrieval.
22021 * @param {Object} This DataProxy object.
22022 * @param {Object} o The data object.
22023 * @param {Object} arg The callback argument object passed to the load function.
22024 * @param {Object} e The Exception.
22026 loadexception : true
22028 Roo.data.DataProxy.superclass.constructor.call(this);
22031 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22034 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22038 * Ext JS Library 1.1.1
22039 * Copyright(c) 2006-2007, Ext JS, LLC.
22041 * Originally Released Under LGPL - original licence link has changed is not relivant.
22044 * <script type="text/javascript">
22047 * @class Roo.data.MemoryProxy
22048 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22049 * to the Reader when its load method is called.
22051 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22053 Roo.data.MemoryProxy = function(data){
22057 Roo.data.MemoryProxy.superclass.constructor.call(this);
22061 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22063 * Load data from the requested source (in this case an in-memory
22064 * data object passed to the constructor), read the data object into
22065 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22066 * process that block using the passed callback.
22067 * @param {Object} params This parameter is not used by the MemoryProxy class.
22068 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22069 * object into a block of Roo.data.Records.
22070 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22071 * The function must be passed <ul>
22072 * <li>The Record block object</li>
22073 * <li>The "arg" argument from the load function</li>
22074 * <li>A boolean success indicator</li>
22076 * @param {Object} scope The scope in which to call the callback
22077 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22079 load : function(params, reader, callback, scope, arg){
22080 params = params || {};
22083 result = reader.readRecords(this.data);
22085 this.fireEvent("loadexception", this, arg, null, e);
22086 callback.call(scope, null, arg, false);
22089 callback.call(scope, result, arg, true);
22093 update : function(params, records){
22098 * Ext JS Library 1.1.1
22099 * Copyright(c) 2006-2007, Ext JS, LLC.
22101 * Originally Released Under LGPL - original licence link has changed is not relivant.
22104 * <script type="text/javascript">
22107 * @class Roo.data.HttpProxy
22108 * @extends Roo.data.DataProxy
22109 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22110 * configured to reference a certain URL.<br><br>
22112 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22113 * from which the running page was served.<br><br>
22115 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22117 * Be aware that to enable the browser to parse an XML document, the server must set
22118 * the Content-Type header in the HTTP response to "text/xml".
22120 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22121 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22122 * will be used to make the request.
22124 Roo.data.HttpProxy = function(conn){
22125 Roo.data.HttpProxy.superclass.constructor.call(this);
22126 // is conn a conn config or a real conn?
22128 this.useAjax = !conn || !conn.events;
22132 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22133 // thse are take from connection...
22136 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22139 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22140 * extra parameters to each request made by this object. (defaults to undefined)
22143 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22144 * to each request made by this object. (defaults to undefined)
22147 * @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)
22150 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22153 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22159 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22163 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22164 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22165 * a finer-grained basis than the DataProxy events.
22167 getConnection : function(){
22168 return this.useAjax ? Roo.Ajax : this.conn;
22172 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22173 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22174 * process that block using the passed callback.
22175 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22176 * for the request to the remote server.
22177 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22178 * object into a block of Roo.data.Records.
22179 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22180 * The function must be passed <ul>
22181 * <li>The Record block object</li>
22182 * <li>The "arg" argument from the load function</li>
22183 * <li>A boolean success indicator</li>
22185 * @param {Object} scope The scope in which to call the callback
22186 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22188 load : function(params, reader, callback, scope, arg){
22189 if(this.fireEvent("beforeload", this, params) !== false){
22191 params : params || {},
22193 callback : callback,
22198 callback : this.loadResponse,
22202 Roo.applyIf(o, this.conn);
22203 if(this.activeRequest){
22204 Roo.Ajax.abort(this.activeRequest);
22206 this.activeRequest = Roo.Ajax.request(o);
22208 this.conn.request(o);
22211 callback.call(scope||this, null, arg, false);
22216 loadResponse : function(o, success, response){
22217 delete this.activeRequest;
22219 this.fireEvent("loadexception", this, o, response);
22220 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22225 result = o.reader.read(response);
22227 this.fireEvent("loadexception", this, o, response, e);
22228 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22232 this.fireEvent("load", this, o, o.request.arg);
22233 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22237 update : function(dataSet){
22242 updateResponse : function(dataSet){
22247 * Ext JS Library 1.1.1
22248 * Copyright(c) 2006-2007, Ext JS, LLC.
22250 * Originally Released Under LGPL - original licence link has changed is not relivant.
22253 * <script type="text/javascript">
22257 * @class Roo.data.ScriptTagProxy
22258 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22259 * other than the originating domain of the running page.<br><br>
22261 * <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
22262 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22264 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22265 * source code that is used as the source inside a <script> tag.<br><br>
22267 * In order for the browser to process the returned data, the server must wrap the data object
22268 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22269 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22270 * depending on whether the callback name was passed:
22273 boolean scriptTag = false;
22274 String cb = request.getParameter("callback");
22277 response.setContentType("text/javascript");
22279 response.setContentType("application/x-json");
22281 Writer out = response.getWriter();
22283 out.write(cb + "(");
22285 out.print(dataBlock.toJsonString());
22292 * @param {Object} config A configuration object.
22294 Roo.data.ScriptTagProxy = function(config){
22295 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22296 Roo.apply(this, config);
22297 this.head = document.getElementsByTagName("head")[0];
22300 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22302 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22304 * @cfg {String} url The URL from which to request the data object.
22307 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22311 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22312 * the server the name of the callback function set up by the load call to process the returned data object.
22313 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22314 * javascript output which calls this named function passing the data object as its only parameter.
22316 callbackParam : "callback",
22318 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22319 * name to the request.
22324 * Load data from the configured URL, read the data object into
22325 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22326 * process that block using the passed callback.
22327 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22328 * for the request to the remote server.
22329 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22330 * object into a block of Roo.data.Records.
22331 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22332 * The function must be passed <ul>
22333 * <li>The Record block object</li>
22334 * <li>The "arg" argument from the load function</li>
22335 * <li>A boolean success indicator</li>
22337 * @param {Object} scope The scope in which to call the callback
22338 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22340 load : function(params, reader, callback, scope, arg){
22341 if(this.fireEvent("beforeload", this, params) !== false){
22343 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22345 var url = this.url;
22346 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22348 url += "&_dc=" + (new Date().getTime());
22350 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22353 cb : "stcCallback"+transId,
22354 scriptId : "stcScript"+transId,
22358 callback : callback,
22364 window[trans.cb] = function(o){
22365 conn.handleResponse(o, trans);
22368 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22370 if(this.autoAbort !== false){
22374 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22376 var script = document.createElement("script");
22377 script.setAttribute("src", url);
22378 script.setAttribute("type", "text/javascript");
22379 script.setAttribute("id", trans.scriptId);
22380 this.head.appendChild(script);
22382 this.trans = trans;
22384 callback.call(scope||this, null, arg, false);
22389 isLoading : function(){
22390 return this.trans ? true : false;
22394 * Abort the current server request.
22396 abort : function(){
22397 if(this.isLoading()){
22398 this.destroyTrans(this.trans);
22403 destroyTrans : function(trans, isLoaded){
22404 this.head.removeChild(document.getElementById(trans.scriptId));
22405 clearTimeout(trans.timeoutId);
22407 window[trans.cb] = undefined;
22409 delete window[trans.cb];
22412 // if hasn't been loaded, wait for load to remove it to prevent script error
22413 window[trans.cb] = function(){
22414 window[trans.cb] = undefined;
22416 delete window[trans.cb];
22423 handleResponse : function(o, trans){
22424 this.trans = false;
22425 this.destroyTrans(trans, true);
22428 result = trans.reader.readRecords(o);
22430 this.fireEvent("loadexception", this, o, trans.arg, e);
22431 trans.callback.call(trans.scope||window, null, trans.arg, false);
22434 this.fireEvent("load", this, o, trans.arg);
22435 trans.callback.call(trans.scope||window, result, trans.arg, true);
22439 handleFailure : function(trans){
22440 this.trans = false;
22441 this.destroyTrans(trans, false);
22442 this.fireEvent("loadexception", this, null, trans.arg);
22443 trans.callback.call(trans.scope||window, null, trans.arg, false);
22447 * Ext JS Library 1.1.1
22448 * Copyright(c) 2006-2007, Ext JS, LLC.
22450 * Originally Released Under LGPL - original licence link has changed is not relivant.
22453 * <script type="text/javascript">
22457 * @class Roo.data.JsonReader
22458 * @extends Roo.data.DataReader
22459 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22460 * based on mappings in a provided Roo.data.Record constructor.
22462 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22463 * in the reply previously.
22468 var RecordDef = Roo.data.Record.create([
22469 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22470 {name: 'occupation'} // This field will use "occupation" as the mapping.
22472 var myReader = new Roo.data.JsonReader({
22473 totalProperty: "results", // The property which contains the total dataset size (optional)
22474 root: "rows", // The property which contains an Array of row objects
22475 id: "id" // The property within each row object that provides an ID for the record (optional)
22479 * This would consume a JSON file like this:
22481 { 'results': 2, 'rows': [
22482 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22483 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22486 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22487 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22488 * paged from the remote server.
22489 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22490 * @cfg {String} root name of the property which contains the Array of row objects.
22491 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22493 * Create a new JsonReader
22494 * @param {Object} meta Metadata configuration options
22495 * @param {Object} recordType Either an Array of field definition objects,
22496 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22498 Roo.data.JsonReader = function(meta, recordType){
22501 // set some defaults:
22502 Roo.applyIf(meta, {
22503 totalProperty: 'total',
22504 successProperty : 'success',
22509 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22511 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22514 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22515 * Used by Store query builder to append _requestMeta to params.
22518 metaFromRemote : false,
22520 * This method is only used by a DataProxy which has retrieved data from a remote server.
22521 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22522 * @return {Object} data A data block which is used by an Roo.data.Store object as
22523 * a cache of Roo.data.Records.
22525 read : function(response){
22526 var json = response.responseText;
22528 var o = /* eval:var:o */ eval("("+json+")");
22530 throw {message: "JsonReader.read: Json object not found"};
22536 this.metaFromRemote = true;
22537 this.meta = o.metaData;
22538 this.recordType = Roo.data.Record.create(o.metaData.fields);
22539 this.onMetaChange(this.meta, this.recordType, o);
22541 return this.readRecords(o);
22544 // private function a store will implement
22545 onMetaChange : function(meta, recordType, o){
22552 simpleAccess: function(obj, subsc) {
22559 getJsonAccessor: function(){
22561 return function(expr) {
22563 return(re.test(expr))
22564 ? new Function("obj", "return obj." + expr)
22569 return Roo.emptyFn;
22574 * Create a data block containing Roo.data.Records from an XML document.
22575 * @param {Object} o An object which contains an Array of row objects in the property specified
22576 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22577 * which contains the total size of the dataset.
22578 * @return {Object} data A data block which is used by an Roo.data.Store object as
22579 * a cache of Roo.data.Records.
22581 readRecords : function(o){
22583 * After any data loads, the raw JSON data is available for further custom processing.
22587 var s = this.meta, Record = this.recordType,
22588 f = Record.prototype.fields, fi = f.items, fl = f.length;
22590 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22592 if(s.totalProperty) {
22593 this.getTotal = this.getJsonAccessor(s.totalProperty);
22595 if(s.successProperty) {
22596 this.getSuccess = this.getJsonAccessor(s.successProperty);
22598 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22600 var g = this.getJsonAccessor(s.id);
22601 this.getId = function(rec) {
22603 return (r === undefined || r === "") ? null : r;
22606 this.getId = function(){return null;};
22609 for(var jj = 0; jj < fl; jj++){
22611 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22612 this.ef[jj] = this.getJsonAccessor(map);
22616 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22617 if(s.totalProperty){
22618 var vt = parseInt(this.getTotal(o), 10);
22623 if(s.successProperty){
22624 var vs = this.getSuccess(o);
22625 if(vs === false || vs === 'false'){
22630 for(var i = 0; i < c; i++){
22633 var id = this.getId(n);
22634 for(var j = 0; j < fl; j++){
22636 var v = this.ef[j](n);
22638 Roo.log('missing convert for ' + f.name);
22642 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22644 var record = new Record(values, id);
22646 records[i] = record;
22652 totalRecords : totalRecords
22657 * Ext JS Library 1.1.1
22658 * Copyright(c) 2006-2007, Ext JS, LLC.
22660 * Originally Released Under LGPL - original licence link has changed is not relivant.
22663 * <script type="text/javascript">
22667 * @class Roo.data.XmlReader
22668 * @extends Roo.data.DataReader
22669 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22670 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22672 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22673 * header in the HTTP response must be set to "text/xml".</em>
22677 var RecordDef = Roo.data.Record.create([
22678 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22679 {name: 'occupation'} // This field will use "occupation" as the mapping.
22681 var myReader = new Roo.data.XmlReader({
22682 totalRecords: "results", // The element which contains the total dataset size (optional)
22683 record: "row", // The repeated element which contains row information
22684 id: "id" // The element within the row that provides an ID for the record (optional)
22688 * This would consume an XML file like this:
22692 <results>2</results>
22695 <name>Bill</name>
22696 <occupation>Gardener</occupation>
22700 <name>Ben</name>
22701 <occupation>Horticulturalist</occupation>
22705 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22706 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22707 * paged from the remote server.
22708 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22709 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22710 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22711 * a record identifier value.
22713 * Create a new XmlReader
22714 * @param {Object} meta Metadata configuration options
22715 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22716 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22717 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22719 Roo.data.XmlReader = function(meta, recordType){
22721 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22723 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22725 * This method is only used by a DataProxy which has retrieved data from a remote server.
22726 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22727 * to contain a method called 'responseXML' that returns an XML document object.
22728 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22729 * a cache of Roo.data.Records.
22731 read : function(response){
22732 var doc = response.responseXML;
22734 throw {message: "XmlReader.read: XML Document not available"};
22736 return this.readRecords(doc);
22740 * Create a data block containing Roo.data.Records from an XML document.
22741 * @param {Object} doc A parsed XML document.
22742 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22743 * a cache of Roo.data.Records.
22745 readRecords : function(doc){
22747 * After any data loads/reads, the raw XML Document is available for further custom processing.
22748 * @type XMLDocument
22750 this.xmlData = doc;
22751 var root = doc.documentElement || doc;
22752 var q = Roo.DomQuery;
22753 var recordType = this.recordType, fields = recordType.prototype.fields;
22754 var sid = this.meta.id;
22755 var totalRecords = 0, success = true;
22756 if(this.meta.totalRecords){
22757 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22760 if(this.meta.success){
22761 var sv = q.selectValue(this.meta.success, root, true);
22762 success = sv !== false && sv !== 'false';
22765 var ns = q.select(this.meta.record, root);
22766 for(var i = 0, len = ns.length; i < len; i++) {
22769 var id = sid ? q.selectValue(sid, n) : undefined;
22770 for(var j = 0, jlen = fields.length; j < jlen; j++){
22771 var f = fields.items[j];
22772 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22774 values[f.name] = v;
22776 var record = new recordType(values, id);
22778 records[records.length] = record;
22784 totalRecords : totalRecords || records.length
22789 * Ext JS Library 1.1.1
22790 * Copyright(c) 2006-2007, Ext JS, LLC.
22792 * Originally Released Under LGPL - original licence link has changed is not relivant.
22795 * <script type="text/javascript">
22799 * @class Roo.data.ArrayReader
22800 * @extends Roo.data.DataReader
22801 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22802 * Each element of that Array represents a row of data fields. The
22803 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22804 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22808 var RecordDef = Roo.data.Record.create([
22809 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22810 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22812 var myReader = new Roo.data.ArrayReader({
22813 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22817 * This would consume an Array like this:
22819 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22821 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22823 * Create a new JsonReader
22824 * @param {Object} meta Metadata configuration options.
22825 * @param {Object} recordType Either an Array of field definition objects
22826 * as specified to {@link Roo.data.Record#create},
22827 * or an {@link Roo.data.Record} object
22828 * created using {@link Roo.data.Record#create}.
22830 Roo.data.ArrayReader = function(meta, recordType){
22831 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22834 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22836 * Create a data block containing Roo.data.Records from an XML document.
22837 * @param {Object} o An Array of row objects which represents the dataset.
22838 * @return {Object} data A data block which is used by an Roo.data.Store object as
22839 * a cache of Roo.data.Records.
22841 readRecords : function(o){
22842 var sid = this.meta ? this.meta.id : null;
22843 var recordType = this.recordType, fields = recordType.prototype.fields;
22846 for(var i = 0; i < root.length; i++){
22849 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22850 for(var j = 0, jlen = fields.length; j < jlen; j++){
22851 var f = fields.items[j];
22852 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22853 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22855 values[f.name] = v;
22857 var record = new recordType(values, id);
22859 records[records.length] = record;
22863 totalRecords : records.length
22868 * Ext JS Library 1.1.1
22869 * Copyright(c) 2006-2007, Ext JS, LLC.
22871 * Originally Released Under LGPL - original licence link has changed is not relivant.
22874 * <script type="text/javascript">
22879 * @class Roo.data.Tree
22880 * @extends Roo.util.Observable
22881 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22882 * in the tree have most standard DOM functionality.
22884 * @param {Node} root (optional) The root node
22886 Roo.data.Tree = function(root){
22887 this.nodeHash = {};
22889 * The root node for this tree
22894 this.setRootNode(root);
22899 * Fires when a new child node is appended to a node in this tree.
22900 * @param {Tree} tree The owner tree
22901 * @param {Node} parent The parent node
22902 * @param {Node} node The newly appended node
22903 * @param {Number} index The index of the newly appended node
22908 * Fires when a child node is removed from a node in this tree.
22909 * @param {Tree} tree The owner tree
22910 * @param {Node} parent The parent node
22911 * @param {Node} node The child node removed
22916 * Fires when a node is moved to a new location in the tree
22917 * @param {Tree} tree The owner tree
22918 * @param {Node} node The node moved
22919 * @param {Node} oldParent The old parent of this node
22920 * @param {Node} newParent The new parent of this node
22921 * @param {Number} index The index it was moved to
22926 * Fires when a new child node is inserted in a node in this tree.
22927 * @param {Tree} tree The owner tree
22928 * @param {Node} parent The parent node
22929 * @param {Node} node The child node inserted
22930 * @param {Node} refNode The child node the node was inserted before
22934 * @event beforeappend
22935 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
22936 * @param {Tree} tree The owner tree
22937 * @param {Node} parent The parent node
22938 * @param {Node} node The child node to be appended
22940 "beforeappend" : true,
22942 * @event beforeremove
22943 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
22944 * @param {Tree} tree The owner tree
22945 * @param {Node} parent The parent node
22946 * @param {Node} node The child node to be removed
22948 "beforeremove" : true,
22950 * @event beforemove
22951 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
22952 * @param {Tree} tree The owner tree
22953 * @param {Node} node The node being moved
22954 * @param {Node} oldParent The parent of the node
22955 * @param {Node} newParent The new parent the node is moving to
22956 * @param {Number} index The index it is being moved to
22958 "beforemove" : true,
22960 * @event beforeinsert
22961 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
22962 * @param {Tree} tree The owner tree
22963 * @param {Node} parent The parent node
22964 * @param {Node} node The child node to be inserted
22965 * @param {Node} refNode The child node the node is being inserted before
22967 "beforeinsert" : true
22970 Roo.data.Tree.superclass.constructor.call(this);
22973 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
22974 pathSeparator: "/",
22976 proxyNodeEvent : function(){
22977 return this.fireEvent.apply(this, arguments);
22981 * Returns the root node for this tree.
22984 getRootNode : function(){
22989 * Sets the root node for this tree.
22990 * @param {Node} node
22993 setRootNode : function(node){
22995 node.ownerTree = this;
22996 node.isRoot = true;
22997 this.registerNode(node);
23002 * Gets a node in this tree by its id.
23003 * @param {String} id
23006 getNodeById : function(id){
23007 return this.nodeHash[id];
23010 registerNode : function(node){
23011 this.nodeHash[node.id] = node;
23014 unregisterNode : function(node){
23015 delete this.nodeHash[node.id];
23018 toString : function(){
23019 return "[Tree"+(this.id?" "+this.id:"")+"]";
23024 * @class Roo.data.Node
23025 * @extends Roo.util.Observable
23026 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23027 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23029 * @param {Object} attributes The attributes/config for the node
23031 Roo.data.Node = function(attributes){
23033 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23036 this.attributes = attributes || {};
23037 this.leaf = this.attributes.leaf;
23039 * The node id. @type String
23041 this.id = this.attributes.id;
23043 this.id = Roo.id(null, "ynode-");
23044 this.attributes.id = this.id;
23049 * All child nodes of this node. @type Array
23051 this.childNodes = [];
23052 if(!this.childNodes.indexOf){ // indexOf is a must
23053 this.childNodes.indexOf = function(o){
23054 for(var i = 0, len = this.length; i < len; i++){
23063 * The parent node for this node. @type Node
23065 this.parentNode = null;
23067 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23069 this.firstChild = null;
23071 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23073 this.lastChild = null;
23075 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23077 this.previousSibling = null;
23079 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23081 this.nextSibling = null;
23086 * Fires when a new child node is appended
23087 * @param {Tree} tree The owner tree
23088 * @param {Node} this This node
23089 * @param {Node} node The newly appended node
23090 * @param {Number} index The index of the newly appended node
23095 * Fires when a child node is removed
23096 * @param {Tree} tree The owner tree
23097 * @param {Node} this This node
23098 * @param {Node} node The removed node
23103 * Fires when this node is moved to a new location in the tree
23104 * @param {Tree} tree The owner tree
23105 * @param {Node} this This node
23106 * @param {Node} oldParent The old parent of this node
23107 * @param {Node} newParent The new parent of this node
23108 * @param {Number} index The index it was moved to
23113 * Fires when a new child node is inserted.
23114 * @param {Tree} tree The owner tree
23115 * @param {Node} this This node
23116 * @param {Node} node The child node inserted
23117 * @param {Node} refNode The child node the node was inserted before
23121 * @event beforeappend
23122 * Fires before a new child is appended, return false to cancel the append.
23123 * @param {Tree} tree The owner tree
23124 * @param {Node} this This node
23125 * @param {Node} node The child node to be appended
23127 "beforeappend" : true,
23129 * @event beforeremove
23130 * Fires before a child is removed, return false to cancel the remove.
23131 * @param {Tree} tree The owner tree
23132 * @param {Node} this This node
23133 * @param {Node} node The child node to be removed
23135 "beforeremove" : true,
23137 * @event beforemove
23138 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23139 * @param {Tree} tree The owner tree
23140 * @param {Node} this This node
23141 * @param {Node} oldParent The parent of this node
23142 * @param {Node} newParent The new parent this node is moving to
23143 * @param {Number} index The index it is being moved to
23145 "beforemove" : true,
23147 * @event beforeinsert
23148 * Fires before a new child is inserted, return false to cancel the insert.
23149 * @param {Tree} tree The owner tree
23150 * @param {Node} this This node
23151 * @param {Node} node The child node to be inserted
23152 * @param {Node} refNode The child node the node is being inserted before
23154 "beforeinsert" : true
23156 this.listeners = this.attributes.listeners;
23157 Roo.data.Node.superclass.constructor.call(this);
23160 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23161 fireEvent : function(evtName){
23162 // first do standard event for this node
23163 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23166 // then bubble it up to the tree if the event wasn't cancelled
23167 var ot = this.getOwnerTree();
23169 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23177 * Returns true if this node is a leaf
23178 * @return {Boolean}
23180 isLeaf : function(){
23181 return this.leaf === true;
23185 setFirstChild : function(node){
23186 this.firstChild = node;
23190 setLastChild : function(node){
23191 this.lastChild = node;
23196 * Returns true if this node is the last child of its parent
23197 * @return {Boolean}
23199 isLast : function(){
23200 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23204 * Returns true if this node is the first child of its parent
23205 * @return {Boolean}
23207 isFirst : function(){
23208 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23211 hasChildNodes : function(){
23212 return !this.isLeaf() && this.childNodes.length > 0;
23216 * Insert node(s) as the last child node of this node.
23217 * @param {Node/Array} node The node or Array of nodes to append
23218 * @return {Node} The appended node if single append, or null if an array was passed
23220 appendChild : function(node){
23222 if(node instanceof Array){
23224 }else if(arguments.length > 1){
23227 // if passed an array or multiple args do them one by one
23229 for(var i = 0, len = multi.length; i < len; i++) {
23230 this.appendChild(multi[i]);
23233 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23236 var index = this.childNodes.length;
23237 var oldParent = node.parentNode;
23238 // it's a move, make sure we move it cleanly
23240 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23243 oldParent.removeChild(node);
23245 index = this.childNodes.length;
23247 this.setFirstChild(node);
23249 this.childNodes.push(node);
23250 node.parentNode = this;
23251 var ps = this.childNodes[index-1];
23253 node.previousSibling = ps;
23254 ps.nextSibling = node;
23256 node.previousSibling = null;
23258 node.nextSibling = null;
23259 this.setLastChild(node);
23260 node.setOwnerTree(this.getOwnerTree());
23261 this.fireEvent("append", this.ownerTree, this, node, index);
23263 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23270 * Removes a child node from this node.
23271 * @param {Node} node The node to remove
23272 * @return {Node} The removed node
23274 removeChild : function(node){
23275 var index = this.childNodes.indexOf(node);
23279 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23283 // remove it from childNodes collection
23284 this.childNodes.splice(index, 1);
23287 if(node.previousSibling){
23288 node.previousSibling.nextSibling = node.nextSibling;
23290 if(node.nextSibling){
23291 node.nextSibling.previousSibling = node.previousSibling;
23294 // update child refs
23295 if(this.firstChild == node){
23296 this.setFirstChild(node.nextSibling);
23298 if(this.lastChild == node){
23299 this.setLastChild(node.previousSibling);
23302 node.setOwnerTree(null);
23303 // clear any references from the node
23304 node.parentNode = null;
23305 node.previousSibling = null;
23306 node.nextSibling = null;
23307 this.fireEvent("remove", this.ownerTree, this, node);
23312 * Inserts the first node before the second node in this nodes childNodes collection.
23313 * @param {Node} node The node to insert
23314 * @param {Node} refNode The node to insert before (if null the node is appended)
23315 * @return {Node} The inserted node
23317 insertBefore : function(node, refNode){
23318 if(!refNode){ // like standard Dom, refNode can be null for append
23319 return this.appendChild(node);
23322 if(node == refNode){
23326 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23329 var index = this.childNodes.indexOf(refNode);
23330 var oldParent = node.parentNode;
23331 var refIndex = index;
23333 // when moving internally, indexes will change after remove
23334 if(oldParent == this && this.childNodes.indexOf(node) < index){
23338 // it's a move, make sure we move it cleanly
23340 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23343 oldParent.removeChild(node);
23346 this.setFirstChild(node);
23348 this.childNodes.splice(refIndex, 0, node);
23349 node.parentNode = this;
23350 var ps = this.childNodes[refIndex-1];
23352 node.previousSibling = ps;
23353 ps.nextSibling = node;
23355 node.previousSibling = null;
23357 node.nextSibling = refNode;
23358 refNode.previousSibling = node;
23359 node.setOwnerTree(this.getOwnerTree());
23360 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23362 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23368 * Returns the child node at the specified index.
23369 * @param {Number} index
23372 item : function(index){
23373 return this.childNodes[index];
23377 * Replaces one child node in this node with another.
23378 * @param {Node} newChild The replacement node
23379 * @param {Node} oldChild The node to replace
23380 * @return {Node} The replaced node
23382 replaceChild : function(newChild, oldChild){
23383 this.insertBefore(newChild, oldChild);
23384 this.removeChild(oldChild);
23389 * Returns the index of a child node
23390 * @param {Node} node
23391 * @return {Number} The index of the node or -1 if it was not found
23393 indexOf : function(child){
23394 return this.childNodes.indexOf(child);
23398 * Returns the tree this node is in.
23401 getOwnerTree : function(){
23402 // if it doesn't have one, look for one
23403 if(!this.ownerTree){
23407 this.ownerTree = p.ownerTree;
23413 return this.ownerTree;
23417 * Returns depth of this node (the root node has a depth of 0)
23420 getDepth : function(){
23423 while(p.parentNode){
23431 setOwnerTree : function(tree){
23432 // if it's move, we need to update everyone
23433 if(tree != this.ownerTree){
23434 if(this.ownerTree){
23435 this.ownerTree.unregisterNode(this);
23437 this.ownerTree = tree;
23438 var cs = this.childNodes;
23439 for(var i = 0, len = cs.length; i < len; i++) {
23440 cs[i].setOwnerTree(tree);
23443 tree.registerNode(this);
23449 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23450 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23451 * @return {String} The path
23453 getPath : function(attr){
23454 attr = attr || "id";
23455 var p = this.parentNode;
23456 var b = [this.attributes[attr]];
23458 b.unshift(p.attributes[attr]);
23461 var sep = this.getOwnerTree().pathSeparator;
23462 return sep + b.join(sep);
23466 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23467 * function call will be the scope provided or the current node. The arguments to the function
23468 * will be the args provided or the current node. If the function returns false at any point,
23469 * the bubble is stopped.
23470 * @param {Function} fn The function to call
23471 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23472 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23474 bubble : function(fn, scope, args){
23477 if(fn.call(scope || p, args || p) === false){
23485 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23486 * function call will be the scope provided or the current node. The arguments to the function
23487 * will be the args provided or the current node. If the function returns false at any point,
23488 * the cascade is stopped on that branch.
23489 * @param {Function} fn The function to call
23490 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23491 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23493 cascade : function(fn, scope, args){
23494 if(fn.call(scope || this, args || this) !== false){
23495 var cs = this.childNodes;
23496 for(var i = 0, len = cs.length; i < len; i++) {
23497 cs[i].cascade(fn, scope, args);
23503 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23504 * function call will be the scope provided or the current node. The arguments to the function
23505 * will be the args provided or the current node. If the function returns false at any point,
23506 * the iteration stops.
23507 * @param {Function} fn The function to call
23508 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23509 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23511 eachChild : function(fn, scope, args){
23512 var cs = this.childNodes;
23513 for(var i = 0, len = cs.length; i < len; i++) {
23514 if(fn.call(scope || this, args || cs[i]) === false){
23521 * Finds the first child that has the attribute with the specified value.
23522 * @param {String} attribute The attribute name
23523 * @param {Mixed} value The value to search for
23524 * @return {Node} The found child or null if none was found
23526 findChild : function(attribute, value){
23527 var cs = this.childNodes;
23528 for(var i = 0, len = cs.length; i < len; i++) {
23529 if(cs[i].attributes[attribute] == value){
23537 * Finds the first child by a custom function. The child matches if the function passed
23539 * @param {Function} fn
23540 * @param {Object} scope (optional)
23541 * @return {Node} The found child or null if none was found
23543 findChildBy : function(fn, scope){
23544 var cs = this.childNodes;
23545 for(var i = 0, len = cs.length; i < len; i++) {
23546 if(fn.call(scope||cs[i], cs[i]) === true){
23554 * Sorts this nodes children using the supplied sort function
23555 * @param {Function} fn
23556 * @param {Object} scope (optional)
23558 sort : function(fn, scope){
23559 var cs = this.childNodes;
23560 var len = cs.length;
23562 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23564 for(var i = 0; i < len; i++){
23566 n.previousSibling = cs[i-1];
23567 n.nextSibling = cs[i+1];
23569 this.setFirstChild(n);
23572 this.setLastChild(n);
23579 * Returns true if this node is an ancestor (at any point) of the passed node.
23580 * @param {Node} node
23581 * @return {Boolean}
23583 contains : function(node){
23584 return node.isAncestor(this);
23588 * Returns true if the passed node is an ancestor (at any point) of this node.
23589 * @param {Node} node
23590 * @return {Boolean}
23592 isAncestor : function(node){
23593 var p = this.parentNode;
23603 toString : function(){
23604 return "[Node"+(this.id?" "+this.id:"")+"]";
23608 * Ext JS Library 1.1.1
23609 * Copyright(c) 2006-2007, Ext JS, LLC.
23611 * Originally Released Under LGPL - original licence link has changed is not relivant.
23614 * <script type="text/javascript">
23619 * @extends Roo.Element
23620 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23621 * automatic maintaining of shadow/shim positions.
23622 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23623 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23624 * you can pass a string with a CSS class name. False turns off the shadow.
23625 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23626 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23627 * @cfg {String} cls CSS class to add to the element
23628 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23629 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23631 * @param {Object} config An object with config options.
23632 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23635 Roo.Layer = function(config, existingEl){
23636 config = config || {};
23637 var dh = Roo.DomHelper;
23638 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23640 this.dom = Roo.getDom(existingEl);
23643 var o = config.dh || {tag: "div", cls: "x-layer"};
23644 this.dom = dh.append(pel, o);
23647 this.addClass(config.cls);
23649 this.constrain = config.constrain !== false;
23650 this.visibilityMode = Roo.Element.VISIBILITY;
23652 this.id = this.dom.id = config.id;
23654 this.id = Roo.id(this.dom);
23656 this.zindex = config.zindex || this.getZIndex();
23657 this.position("absolute", this.zindex);
23659 this.shadowOffset = config.shadowOffset || 4;
23660 this.shadow = new Roo.Shadow({
23661 offset : this.shadowOffset,
23662 mode : config.shadow
23665 this.shadowOffset = 0;
23667 this.useShim = config.shim !== false && Roo.useShims;
23668 this.useDisplay = config.useDisplay;
23672 var supr = Roo.Element.prototype;
23674 // shims are shared among layer to keep from having 100 iframes
23677 Roo.extend(Roo.Layer, Roo.Element, {
23679 getZIndex : function(){
23680 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23683 getShim : function(){
23690 var shim = shims.shift();
23692 shim = this.createShim();
23693 shim.enableDisplayMode('block');
23694 shim.dom.style.display = 'none';
23695 shim.dom.style.visibility = 'visible';
23697 var pn = this.dom.parentNode;
23698 if(shim.dom.parentNode != pn){
23699 pn.insertBefore(shim.dom, this.dom);
23701 shim.setStyle('z-index', this.getZIndex()-2);
23706 hideShim : function(){
23708 this.shim.setDisplayed(false);
23709 shims.push(this.shim);
23714 disableShadow : function(){
23716 this.shadowDisabled = true;
23717 this.shadow.hide();
23718 this.lastShadowOffset = this.shadowOffset;
23719 this.shadowOffset = 0;
23723 enableShadow : function(show){
23725 this.shadowDisabled = false;
23726 this.shadowOffset = this.lastShadowOffset;
23727 delete this.lastShadowOffset;
23735 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23736 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23737 sync : function(doShow){
23738 var sw = this.shadow;
23739 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23740 var sh = this.getShim();
23742 var w = this.getWidth(),
23743 h = this.getHeight();
23745 var l = this.getLeft(true),
23746 t = this.getTop(true);
23748 if(sw && !this.shadowDisabled){
23749 if(doShow && !sw.isVisible()){
23752 sw.realign(l, t, w, h);
23758 // fit the shim behind the shadow, so it is shimmed too
23759 var a = sw.adjusts, s = sh.dom.style;
23760 s.left = (Math.min(l, l+a.l))+"px";
23761 s.top = (Math.min(t, t+a.t))+"px";
23762 s.width = (w+a.w)+"px";
23763 s.height = (h+a.h)+"px";
23770 sh.setLeftTop(l, t);
23777 destroy : function(){
23780 this.shadow.hide();
23782 this.removeAllListeners();
23783 var pn = this.dom.parentNode;
23785 pn.removeChild(this.dom);
23787 Roo.Element.uncache(this.id);
23790 remove : function(){
23795 beginUpdate : function(){
23796 this.updating = true;
23800 endUpdate : function(){
23801 this.updating = false;
23806 hideUnders : function(negOffset){
23808 this.shadow.hide();
23814 constrainXY : function(){
23815 if(this.constrain){
23816 var vw = Roo.lib.Dom.getViewWidth(),
23817 vh = Roo.lib.Dom.getViewHeight();
23818 var s = Roo.get(document).getScroll();
23820 var xy = this.getXY();
23821 var x = xy[0], y = xy[1];
23822 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23823 // only move it if it needs it
23825 // first validate right/bottom
23826 if((x + w) > vw+s.left){
23827 x = vw - w - this.shadowOffset;
23830 if((y + h) > vh+s.top){
23831 y = vh - h - this.shadowOffset;
23834 // then make sure top/left isn't negative
23845 var ay = this.avoidY;
23846 if(y <= ay && (y+h) >= ay){
23852 supr.setXY.call(this, xy);
23858 isVisible : function(){
23859 return this.visible;
23863 showAction : function(){
23864 this.visible = true; // track visibility to prevent getStyle calls
23865 if(this.useDisplay === true){
23866 this.setDisplayed("");
23867 }else if(this.lastXY){
23868 supr.setXY.call(this, this.lastXY);
23869 }else if(this.lastLT){
23870 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23875 hideAction : function(){
23876 this.visible = false;
23877 if(this.useDisplay === true){
23878 this.setDisplayed(false);
23880 this.setLeftTop(-10000,-10000);
23884 // overridden Element method
23885 setVisible : function(v, a, d, c, e){
23890 var cb = function(){
23895 }.createDelegate(this);
23896 supr.setVisible.call(this, true, true, d, cb, e);
23899 this.hideUnders(true);
23908 }.createDelegate(this);
23910 supr.setVisible.call(this, v, a, d, cb, e);
23919 storeXY : function(xy){
23920 delete this.lastLT;
23924 storeLeftTop : function(left, top){
23925 delete this.lastXY;
23926 this.lastLT = [left, top];
23930 beforeFx : function(){
23931 this.beforeAction();
23932 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23936 afterFx : function(){
23937 Roo.Layer.superclass.afterFx.apply(this, arguments);
23938 this.sync(this.isVisible());
23942 beforeAction : function(){
23943 if(!this.updating && this.shadow){
23944 this.shadow.hide();
23948 // overridden Element method
23949 setLeft : function(left){
23950 this.storeLeftTop(left, this.getTop(true));
23951 supr.setLeft.apply(this, arguments);
23955 setTop : function(top){
23956 this.storeLeftTop(this.getLeft(true), top);
23957 supr.setTop.apply(this, arguments);
23961 setLeftTop : function(left, top){
23962 this.storeLeftTop(left, top);
23963 supr.setLeftTop.apply(this, arguments);
23967 setXY : function(xy, a, d, c, e){
23969 this.beforeAction();
23971 var cb = this.createCB(c);
23972 supr.setXY.call(this, xy, a, d, cb, e);
23979 createCB : function(c){
23990 // overridden Element method
23991 setX : function(x, a, d, c, e){
23992 this.setXY([x, this.getY()], a, d, c, e);
23995 // overridden Element method
23996 setY : function(y, a, d, c, e){
23997 this.setXY([this.getX(), y], a, d, c, e);
24000 // overridden Element method
24001 setSize : function(w, h, a, d, c, e){
24002 this.beforeAction();
24003 var cb = this.createCB(c);
24004 supr.setSize.call(this, w, h, a, d, cb, e);
24010 // overridden Element method
24011 setWidth : function(w, a, d, c, e){
24012 this.beforeAction();
24013 var cb = this.createCB(c);
24014 supr.setWidth.call(this, w, a, d, cb, e);
24020 // overridden Element method
24021 setHeight : function(h, a, d, c, e){
24022 this.beforeAction();
24023 var cb = this.createCB(c);
24024 supr.setHeight.call(this, h, a, d, cb, e);
24030 // overridden Element method
24031 setBounds : function(x, y, w, h, a, d, c, e){
24032 this.beforeAction();
24033 var cb = this.createCB(c);
24035 this.storeXY([x, y]);
24036 supr.setXY.call(this, [x, y]);
24037 supr.setSize.call(this, w, h, a, d, cb, e);
24040 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24046 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24047 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24048 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24049 * @param {Number} zindex The new z-index to set
24050 * @return {this} The Layer
24052 setZIndex : function(zindex){
24053 this.zindex = zindex;
24054 this.setStyle("z-index", zindex + 2);
24056 this.shadow.setZIndex(zindex + 1);
24059 this.shim.setStyle("z-index", zindex);
24065 * Ext JS Library 1.1.1
24066 * Copyright(c) 2006-2007, Ext JS, LLC.
24068 * Originally Released Under LGPL - original licence link has changed is not relivant.
24071 * <script type="text/javascript">
24076 * @class Roo.Shadow
24077 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24078 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24079 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24081 * Create a new Shadow
24082 * @param {Object} config The config object
24084 Roo.Shadow = function(config){
24085 Roo.apply(this, config);
24086 if(typeof this.mode != "string"){
24087 this.mode = this.defaultMode;
24089 var o = this.offset, a = {h: 0};
24090 var rad = Math.floor(this.offset/2);
24091 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24097 a.l -= this.offset + rad;
24098 a.t -= this.offset + rad;
24109 a.l -= (this.offset - rad);
24110 a.t -= this.offset + rad;
24112 a.w -= (this.offset - rad)*2;
24123 a.l -= (this.offset - rad);
24124 a.t -= (this.offset - rad);
24126 a.w -= (this.offset + rad + 1);
24127 a.h -= (this.offset + rad);
24136 Roo.Shadow.prototype = {
24138 * @cfg {String} mode
24139 * The shadow display mode. Supports the following options:<br />
24140 * sides: Shadow displays on both sides and bottom only<br />
24141 * frame: Shadow displays equally on all four sides<br />
24142 * drop: Traditional bottom-right drop shadow (default)
24145 * @cfg {String} offset
24146 * The number of pixels to offset the shadow from the element (defaults to 4)
24151 defaultMode: "drop",
24154 * Displays the shadow under the target element
24155 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24157 show : function(target){
24158 target = Roo.get(target);
24160 this.el = Roo.Shadow.Pool.pull();
24161 if(this.el.dom.nextSibling != target.dom){
24162 this.el.insertBefore(target);
24165 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24167 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24170 target.getLeft(true),
24171 target.getTop(true),
24175 this.el.dom.style.display = "block";
24179 * Returns true if the shadow is visible, else false
24181 isVisible : function(){
24182 return this.el ? true : false;
24186 * Direct alignment when values are already available. Show must be called at least once before
24187 * calling this method to ensure it is initialized.
24188 * @param {Number} left The target element left position
24189 * @param {Number} top The target element top position
24190 * @param {Number} width The target element width
24191 * @param {Number} height The target element height
24193 realign : function(l, t, w, h){
24197 var a = this.adjusts, d = this.el.dom, s = d.style;
24199 s.left = (l+a.l)+"px";
24200 s.top = (t+a.t)+"px";
24201 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24203 if(s.width != sws || s.height != shs){
24207 var cn = d.childNodes;
24208 var sww = Math.max(0, (sw-12))+"px";
24209 cn[0].childNodes[1].style.width = sww;
24210 cn[1].childNodes[1].style.width = sww;
24211 cn[2].childNodes[1].style.width = sww;
24212 cn[1].style.height = Math.max(0, (sh-12))+"px";
24218 * Hides this shadow
24222 this.el.dom.style.display = "none";
24223 Roo.Shadow.Pool.push(this.el);
24229 * Adjust the z-index of this shadow
24230 * @param {Number} zindex The new z-index
24232 setZIndex : function(z){
24235 this.el.setStyle("z-index", z);
24240 // Private utility class that manages the internal Shadow cache
24241 Roo.Shadow.Pool = function(){
24243 var markup = Roo.isIE ?
24244 '<div class="x-ie-shadow"></div>' :
24245 '<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>';
24248 var sh = p.shift();
24250 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24251 sh.autoBoxAdjust = false;
24256 push : function(sh){
24262 * Ext JS Library 1.1.1
24263 * Copyright(c) 2006-2007, Ext JS, LLC.
24265 * Originally Released Under LGPL - original licence link has changed is not relivant.
24268 * <script type="text/javascript">
24273 * @class Roo.SplitBar
24274 * @extends Roo.util.Observable
24275 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24279 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24280 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24281 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24282 split.minSize = 100;
24283 split.maxSize = 600;
24284 split.animate = true;
24285 split.on('moved', splitterMoved);
24288 * Create a new SplitBar
24289 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24290 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24291 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24292 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24293 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24294 position of the SplitBar).
24296 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24299 this.el = Roo.get(dragElement, true);
24300 this.el.dom.unselectable = "on";
24302 this.resizingEl = Roo.get(resizingElement, true);
24306 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24307 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24310 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24313 * The minimum size of the resizing element. (Defaults to 0)
24319 * The maximum size of the resizing element. (Defaults to 2000)
24322 this.maxSize = 2000;
24325 * Whether to animate the transition to the new size
24328 this.animate = false;
24331 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24334 this.useShim = false;
24339 if(!existingProxy){
24341 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24343 this.proxy = Roo.get(existingProxy).dom;
24346 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24349 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24352 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24355 this.dragSpecs = {};
24358 * @private The adapter to use to positon and resize elements
24360 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24361 this.adapter.init(this);
24363 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24365 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24366 this.el.addClass("x-splitbar-h");
24369 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24370 this.el.addClass("x-splitbar-v");
24376 * Fires when the splitter is moved (alias for {@link #event-moved})
24377 * @param {Roo.SplitBar} this
24378 * @param {Number} newSize the new width or height
24383 * Fires when the splitter is moved
24384 * @param {Roo.SplitBar} this
24385 * @param {Number} newSize the new width or height
24389 * @event beforeresize
24390 * Fires before the splitter is dragged
24391 * @param {Roo.SplitBar} this
24393 "beforeresize" : true,
24395 "beforeapply" : true
24398 Roo.util.Observable.call(this);
24401 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24402 onStartProxyDrag : function(x, y){
24403 this.fireEvent("beforeresize", this);
24405 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24407 o.enableDisplayMode("block");
24408 // all splitbars share the same overlay
24409 Roo.SplitBar.prototype.overlay = o;
24411 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24412 this.overlay.show();
24413 Roo.get(this.proxy).setDisplayed("block");
24414 var size = this.adapter.getElementSize(this);
24415 this.activeMinSize = this.getMinimumSize();;
24416 this.activeMaxSize = this.getMaximumSize();;
24417 var c1 = size - this.activeMinSize;
24418 var c2 = Math.max(this.activeMaxSize - size, 0);
24419 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24420 this.dd.resetConstraints();
24421 this.dd.setXConstraint(
24422 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24423 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24425 this.dd.setYConstraint(0, 0);
24427 this.dd.resetConstraints();
24428 this.dd.setXConstraint(0, 0);
24429 this.dd.setYConstraint(
24430 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24431 this.placement == Roo.SplitBar.TOP ? c2 : c1
24434 this.dragSpecs.startSize = size;
24435 this.dragSpecs.startPoint = [x, y];
24436 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24440 * @private Called after the drag operation by the DDProxy
24442 onEndProxyDrag : function(e){
24443 Roo.get(this.proxy).setDisplayed(false);
24444 var endPoint = Roo.lib.Event.getXY(e);
24446 this.overlay.hide();
24449 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24450 newSize = this.dragSpecs.startSize +
24451 (this.placement == Roo.SplitBar.LEFT ?
24452 endPoint[0] - this.dragSpecs.startPoint[0] :
24453 this.dragSpecs.startPoint[0] - endPoint[0]
24456 newSize = this.dragSpecs.startSize +
24457 (this.placement == Roo.SplitBar.TOP ?
24458 endPoint[1] - this.dragSpecs.startPoint[1] :
24459 this.dragSpecs.startPoint[1] - endPoint[1]
24462 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24463 if(newSize != this.dragSpecs.startSize){
24464 if(this.fireEvent('beforeapply', this, newSize) !== false){
24465 this.adapter.setElementSize(this, newSize);
24466 this.fireEvent("moved", this, newSize);
24467 this.fireEvent("resize", this, newSize);
24473 * Get the adapter this SplitBar uses
24474 * @return The adapter object
24476 getAdapter : function(){
24477 return this.adapter;
24481 * Set the adapter this SplitBar uses
24482 * @param {Object} adapter A SplitBar adapter object
24484 setAdapter : function(adapter){
24485 this.adapter = adapter;
24486 this.adapter.init(this);
24490 * Gets the minimum size for the resizing element
24491 * @return {Number} The minimum size
24493 getMinimumSize : function(){
24494 return this.minSize;
24498 * Sets the minimum size for the resizing element
24499 * @param {Number} minSize The minimum size
24501 setMinimumSize : function(minSize){
24502 this.minSize = minSize;
24506 * Gets the maximum size for the resizing element
24507 * @return {Number} The maximum size
24509 getMaximumSize : function(){
24510 return this.maxSize;
24514 * Sets the maximum size for the resizing element
24515 * @param {Number} maxSize The maximum size
24517 setMaximumSize : function(maxSize){
24518 this.maxSize = maxSize;
24522 * Sets the initialize size for the resizing element
24523 * @param {Number} size The initial size
24525 setCurrentSize : function(size){
24526 var oldAnimate = this.animate;
24527 this.animate = false;
24528 this.adapter.setElementSize(this, size);
24529 this.animate = oldAnimate;
24533 * Destroy this splitbar.
24534 * @param {Boolean} removeEl True to remove the element
24536 destroy : function(removeEl){
24538 this.shim.remove();
24541 this.proxy.parentNode.removeChild(this.proxy);
24549 * @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.
24551 Roo.SplitBar.createProxy = function(dir){
24552 var proxy = new Roo.Element(document.createElement("div"));
24553 proxy.unselectable();
24554 var cls = 'x-splitbar-proxy';
24555 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24556 document.body.appendChild(proxy.dom);
24561 * @class Roo.SplitBar.BasicLayoutAdapter
24562 * Default Adapter. It assumes the splitter and resizing element are not positioned
24563 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24565 Roo.SplitBar.BasicLayoutAdapter = function(){
24568 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24569 // do nothing for now
24570 init : function(s){
24574 * Called before drag operations to get the current size of the resizing element.
24575 * @param {Roo.SplitBar} s The SplitBar using this adapter
24577 getElementSize : function(s){
24578 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24579 return s.resizingEl.getWidth();
24581 return s.resizingEl.getHeight();
24586 * Called after drag operations to set the size of the resizing element.
24587 * @param {Roo.SplitBar} s The SplitBar using this adapter
24588 * @param {Number} newSize The new size to set
24589 * @param {Function} onComplete A function to be invoked when resizing is complete
24591 setElementSize : function(s, newSize, onComplete){
24592 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24594 s.resizingEl.setWidth(newSize);
24596 onComplete(s, newSize);
24599 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24604 s.resizingEl.setHeight(newSize);
24606 onComplete(s, newSize);
24609 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24616 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24617 * @extends Roo.SplitBar.BasicLayoutAdapter
24618 * Adapter that moves the splitter element to align with the resized sizing element.
24619 * Used with an absolute positioned SplitBar.
24620 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24621 * document.body, make sure you assign an id to the body element.
24623 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24624 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24625 this.container = Roo.get(container);
24628 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24629 init : function(s){
24630 this.basic.init(s);
24633 getElementSize : function(s){
24634 return this.basic.getElementSize(s);
24637 setElementSize : function(s, newSize, onComplete){
24638 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24641 moveSplitter : function(s){
24642 var yes = Roo.SplitBar;
24643 switch(s.placement){
24645 s.el.setX(s.resizingEl.getRight());
24648 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24651 s.el.setY(s.resizingEl.getBottom());
24654 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24661 * Orientation constant - Create a vertical SplitBar
24665 Roo.SplitBar.VERTICAL = 1;
24668 * Orientation constant - Create a horizontal SplitBar
24672 Roo.SplitBar.HORIZONTAL = 2;
24675 * Placement constant - The resizing element is to the left of the splitter element
24679 Roo.SplitBar.LEFT = 1;
24682 * Placement constant - The resizing element is to the right of the splitter element
24686 Roo.SplitBar.RIGHT = 2;
24689 * Placement constant - The resizing element is positioned above the splitter element
24693 Roo.SplitBar.TOP = 3;
24696 * Placement constant - The resizing element is positioned under splitter element
24700 Roo.SplitBar.BOTTOM = 4;
24703 * Ext JS Library 1.1.1
24704 * Copyright(c) 2006-2007, Ext JS, LLC.
24706 * Originally Released Under LGPL - original licence link has changed is not relivant.
24709 * <script type="text/javascript">
24714 * @extends Roo.util.Observable
24715 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24716 * This class also supports single and multi selection modes. <br>
24717 * Create a data model bound view:
24719 var store = new Roo.data.Store(...);
24721 var view = new Roo.View({
24723 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24725 singleSelect: true,
24726 selectedClass: "ydataview-selected",
24730 // listen for node click?
24731 view.on("click", function(vw, index, node, e){
24732 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24736 dataModel.load("foobar.xml");
24738 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24740 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24741 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24743 * Note: old style constructor is still suported (container, template, config)
24746 * Create a new View
24747 * @param {Object} config The config object
24750 Roo.View = function(config, depreciated_tpl, depreciated_config){
24752 if (typeof(depreciated_tpl) == 'undefined') {
24753 // new way.. - universal constructor.
24754 Roo.apply(this, config);
24755 this.el = Roo.get(this.el);
24758 this.el = Roo.get(config);
24759 this.tpl = depreciated_tpl;
24760 Roo.apply(this, depreciated_config);
24762 this.wrapEl = this.el.wrap().wrap();
24763 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24766 if(typeof(this.tpl) == "string"){
24767 this.tpl = new Roo.Template(this.tpl);
24769 // support xtype ctors..
24770 this.tpl = new Roo.factory(this.tpl, Roo);
24774 this.tpl.compile();
24782 * @event beforeclick
24783 * Fires before a click is processed. Returns false to cancel the default action.
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 "beforeclick" : true,
24792 * Fires when a template node is clicked.
24793 * @param {Roo.View} this
24794 * @param {Number} index The index of the target node
24795 * @param {HTMLElement} node The target node
24796 * @param {Roo.EventObject} e The raw event object
24801 * Fires when a template node is double clicked.
24802 * @param {Roo.View} this
24803 * @param {Number} index The index of the target node
24804 * @param {HTMLElement} node The target node
24805 * @param {Roo.EventObject} e The raw event object
24809 * @event contextmenu
24810 * Fires when a template node is right clicked.
24811 * @param {Roo.View} this
24812 * @param {Number} index The index of the target node
24813 * @param {HTMLElement} node The target node
24814 * @param {Roo.EventObject} e The raw event object
24816 "contextmenu" : true,
24818 * @event selectionchange
24819 * Fires when the selected nodes change.
24820 * @param {Roo.View} this
24821 * @param {Array} selections Array of the selected nodes
24823 "selectionchange" : true,
24826 * @event beforeselect
24827 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24828 * @param {Roo.View} this
24829 * @param {HTMLElement} node The node to be selected
24830 * @param {Array} selections Array of currently selected nodes
24832 "beforeselect" : true,
24834 * @event preparedata
24835 * Fires on every row to render, to allow you to change the data.
24836 * @param {Roo.View} this
24837 * @param {Object} data to be rendered (change this)
24839 "preparedata" : true
24847 "click": this.onClick,
24848 "dblclick": this.onDblClick,
24849 "contextmenu": this.onContextMenu,
24853 this.selections = [];
24855 this.cmp = new Roo.CompositeElementLite([]);
24857 this.store = Roo.factory(this.store, Roo.data);
24858 this.setStore(this.store, true);
24861 if ( this.footer && this.footer.xtype) {
24863 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24865 this.footer.dataSource = this.store
24866 this.footer.container = fctr;
24867 this.footer = Roo.factory(this.footer, Roo);
24868 fctr.insertFirst(this.el);
24870 // this is a bit insane - as the paging toolbar seems to detach the el..
24871 // dom.parentNode.parentNode.parentNode
24872 // they get detached?
24876 Roo.View.superclass.constructor.call(this);
24881 Roo.extend(Roo.View, Roo.util.Observable, {
24884 * @cfg {Roo.data.Store} store Data store to load data from.
24889 * @cfg {String|Roo.Element} el The container element.
24894 * @cfg {String|Roo.Template} tpl The template used by this View
24898 * @cfg {String} dataName the named area of the template to use as the data area
24899 * Works with domtemplates roo-name="name"
24903 * @cfg {String} selectedClass The css class to add to selected nodes
24905 selectedClass : "x-view-selected",
24907 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24912 * @cfg {String} text to display on mask (default Loading)
24916 * @cfg {Boolean} multiSelect Allow multiple selection
24918 multiSelect : false,
24920 * @cfg {Boolean} singleSelect Allow single selection
24922 singleSelect: false,
24925 * @cfg {Boolean} toggleSelect - selecting
24927 toggleSelect : false,
24930 * Returns the element this view is bound to.
24931 * @return {Roo.Element}
24933 getEl : function(){
24934 return this.wrapEl;
24940 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24942 refresh : function(){
24943 Roo.log('refresh');
24946 // if we are using something like 'domtemplate', then
24947 // the what gets used is:
24948 // t.applySubtemplate(NAME, data, wrapping data..)
24949 // the outer template then get' applied with
24950 // the store 'extra data'
24951 // and the body get's added to the
24952 // roo-name="data" node?
24953 // <span class='roo-tpl-{name}'></span> ?????
24957 this.clearSelections();
24958 this.el.update("");
24960 var records = this.store.getRange();
24961 if(records.length < 1) {
24963 // is this valid?? = should it render a template??
24965 this.el.update(this.emptyText);
24969 if (this.dataName) {
24970 this.el.update(t.apply(this.store.meta)); //????
24971 el = this.el.child('.roo-tpl-' + this.dataName);
24974 for(var i = 0, len = records.length; i < len; i++){
24975 var data = this.prepareData(records[i].data, i, records[i]);
24976 this.fireEvent("preparedata", this, data, i, records[i]);
24977 html[html.length] = Roo.util.Format.trim(
24979 t.applySubtemplate(this.dataName, data, this.store.meta) :
24986 el.update(html.join(""));
24987 this.nodes = el.dom.childNodes;
24988 this.updateIndexes(0);
24993 * Function to override to reformat the data that is sent to
24994 * the template for each node.
24995 * DEPRICATED - use the preparedata event handler.
24996 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24997 * a JSON object for an UpdateManager bound view).
24999 prepareData : function(data, index, record)
25001 this.fireEvent("preparedata", this, data, index, record);
25005 onUpdate : function(ds, record){
25006 Roo.log('on update');
25007 this.clearSelections();
25008 var index = this.store.indexOf(record);
25009 var n = this.nodes[index];
25010 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25011 n.parentNode.removeChild(n);
25012 this.updateIndexes(index, index);
25018 onAdd : function(ds, records, index)
25020 Roo.log(['on Add', ds, records, index] );
25021 this.clearSelections();
25022 if(this.nodes.length == 0){
25026 var n = this.nodes[index];
25027 for(var i = 0, len = records.length; i < len; i++){
25028 var d = this.prepareData(records[i].data, i, records[i]);
25030 this.tpl.insertBefore(n, d);
25033 this.tpl.append(this.el, d);
25036 this.updateIndexes(index);
25039 onRemove : function(ds, record, index){
25040 Roo.log('onRemove');
25041 this.clearSelections();
25042 var el = this.dataName ?
25043 this.el.child('.roo-tpl-' + this.dataName) :
25046 el.dom.removeChild(this.nodes[index]);
25047 this.updateIndexes(index);
25051 * Refresh an individual node.
25052 * @param {Number} index
25054 refreshNode : function(index){
25055 this.onUpdate(this.store, this.store.getAt(index));
25058 updateIndexes : function(startIndex, endIndex){
25059 var ns = this.nodes;
25060 startIndex = startIndex || 0;
25061 endIndex = endIndex || ns.length - 1;
25062 for(var i = startIndex; i <= endIndex; i++){
25063 ns[i].nodeIndex = i;
25068 * Changes the data store this view uses and refresh the view.
25069 * @param {Store} store
25071 setStore : function(store, initial){
25072 if(!initial && this.store){
25073 this.store.un("datachanged", this.refresh);
25074 this.store.un("add", this.onAdd);
25075 this.store.un("remove", this.onRemove);
25076 this.store.un("update", this.onUpdate);
25077 this.store.un("clear", this.refresh);
25078 this.store.un("beforeload", this.onBeforeLoad);
25079 this.store.un("load", this.onLoad);
25080 this.store.un("loadexception", this.onLoad);
25084 store.on("datachanged", this.refresh, this);
25085 store.on("add", this.onAdd, this);
25086 store.on("remove", this.onRemove, this);
25087 store.on("update", this.onUpdate, this);
25088 store.on("clear", this.refresh, this);
25089 store.on("beforeload", this.onBeforeLoad, this);
25090 store.on("load", this.onLoad, this);
25091 store.on("loadexception", this.onLoad, this);
25099 * onbeforeLoad - masks the loading area.
25102 onBeforeLoad : function(store,opts)
25104 Roo.log('onBeforeLoad');
25106 this.el.update("");
25108 this.el.mask(this.mask ? this.mask : "Loading" );
25110 onLoad : function ()
25117 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25118 * @param {HTMLElement} node
25119 * @return {HTMLElement} The template node
25121 findItemFromChild : function(node){
25122 var el = this.dataName ?
25123 this.el.child('.roo-tpl-' + this.dataName,true) :
25126 if(!node || node.parentNode == el){
25129 var p = node.parentNode;
25130 while(p && p != el){
25131 if(p.parentNode == el){
25140 onClick : function(e){
25141 var item = this.findItemFromChild(e.getTarget());
25143 var index = this.indexOf(item);
25144 if(this.onItemClick(item, index, e) !== false){
25145 this.fireEvent("click", this, index, item, e);
25148 this.clearSelections();
25153 onContextMenu : function(e){
25154 var item = this.findItemFromChild(e.getTarget());
25156 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25161 onDblClick : function(e){
25162 var item = this.findItemFromChild(e.getTarget());
25164 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25168 onItemClick : function(item, index, e)
25170 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25173 if (this.toggleSelect) {
25174 var m = this.isSelected(item) ? 'unselect' : 'select';
25177 _t[m](item, true, false);
25180 if(this.multiSelect || this.singleSelect){
25181 if(this.multiSelect && e.shiftKey && this.lastSelection){
25182 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25184 this.select(item, this.multiSelect && e.ctrlKey);
25185 this.lastSelection = item;
25187 e.preventDefault();
25193 * Get the number of selected nodes.
25196 getSelectionCount : function(){
25197 return this.selections.length;
25201 * Get the currently selected nodes.
25202 * @return {Array} An array of HTMLElements
25204 getSelectedNodes : function(){
25205 return this.selections;
25209 * Get the indexes of the selected nodes.
25212 getSelectedIndexes : function(){
25213 var indexes = [], s = this.selections;
25214 for(var i = 0, len = s.length; i < len; i++){
25215 indexes.push(s[i].nodeIndex);
25221 * Clear all selections
25222 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25224 clearSelections : function(suppressEvent){
25225 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25226 this.cmp.elements = this.selections;
25227 this.cmp.removeClass(this.selectedClass);
25228 this.selections = [];
25229 if(!suppressEvent){
25230 this.fireEvent("selectionchange", this, this.selections);
25236 * Returns true if the passed node is selected
25237 * @param {HTMLElement/Number} node The node or node index
25238 * @return {Boolean}
25240 isSelected : function(node){
25241 var s = this.selections;
25245 node = this.getNode(node);
25246 return s.indexOf(node) !== -1;
25251 * @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
25252 * @param {Boolean} keepExisting (optional) true to keep existing selections
25253 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25255 select : function(nodeInfo, keepExisting, suppressEvent){
25256 if(nodeInfo instanceof Array){
25258 this.clearSelections(true);
25260 for(var i = 0, len = nodeInfo.length; i < len; i++){
25261 this.select(nodeInfo[i], true, true);
25265 var node = this.getNode(nodeInfo);
25266 if(!node || this.isSelected(node)){
25267 return; // already selected.
25270 this.clearSelections(true);
25272 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25273 Roo.fly(node).addClass(this.selectedClass);
25274 this.selections.push(node);
25275 if(!suppressEvent){
25276 this.fireEvent("selectionchange", this, this.selections);
25284 * @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
25285 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25286 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25288 unselect : function(nodeInfo, keepExisting, suppressEvent)
25290 if(nodeInfo instanceof Array){
25291 Roo.each(this.selections, function(s) {
25292 this.unselect(s, nodeInfo);
25296 var node = this.getNode(nodeInfo);
25297 if(!node || !this.isSelected(node)){
25298 Roo.log("not selected");
25299 return; // not selected.
25303 Roo.each(this.selections, function(s) {
25305 Roo.fly(node).removeClass(this.selectedClass);
25312 this.selections= ns;
25313 this.fireEvent("selectionchange", this, this.selections);
25317 * Gets a template node.
25318 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25319 * @return {HTMLElement} The node or null if it wasn't found
25321 getNode : function(nodeInfo){
25322 if(typeof nodeInfo == "string"){
25323 return document.getElementById(nodeInfo);
25324 }else if(typeof nodeInfo == "number"){
25325 return this.nodes[nodeInfo];
25331 * Gets a range template nodes.
25332 * @param {Number} startIndex
25333 * @param {Number} endIndex
25334 * @return {Array} An array of nodes
25336 getNodes : function(start, end){
25337 var ns = this.nodes;
25338 start = start || 0;
25339 end = typeof end == "undefined" ? ns.length - 1 : end;
25342 for(var i = start; i <= end; i++){
25346 for(var i = start; i >= end; i--){
25354 * Finds the index of the passed node
25355 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25356 * @return {Number} The index of the node or -1
25358 indexOf : function(node){
25359 node = this.getNode(node);
25360 if(typeof node.nodeIndex == "number"){
25361 return node.nodeIndex;
25363 var ns = this.nodes;
25364 for(var i = 0, len = ns.length; i < len; i++){
25374 * Ext JS Library 1.1.1
25375 * Copyright(c) 2006-2007, Ext JS, LLC.
25377 * Originally Released Under LGPL - original licence link has changed is not relivant.
25380 * <script type="text/javascript">
25384 * @class Roo.JsonView
25385 * @extends Roo.View
25386 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25388 var view = new Roo.JsonView({
25389 container: "my-element",
25390 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25395 // listen for node click?
25396 view.on("click", function(vw, index, node, e){
25397 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25400 // direct load of JSON data
25401 view.load("foobar.php");
25403 // Example from my blog list
25404 var tpl = new Roo.Template(
25405 '<div class="entry">' +
25406 '<a class="entry-title" href="{link}">{title}</a>' +
25407 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25408 "</div><hr />"
25411 var moreView = new Roo.JsonView({
25412 container : "entry-list",
25416 moreView.on("beforerender", this.sortEntries, this);
25418 url: "/blog/get-posts.php",
25419 params: "allposts=true",
25420 text: "Loading Blog Entries..."
25424 * Note: old code is supported with arguments : (container, template, config)
25428 * Create a new JsonView
25430 * @param {Object} config The config object
25433 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25436 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25438 var um = this.el.getUpdateManager();
25439 um.setRenderer(this);
25440 um.on("update", this.onLoad, this);
25441 um.on("failure", this.onLoadException, this);
25444 * @event beforerender
25445 * Fires before rendering of the downloaded JSON data.
25446 * @param {Roo.JsonView} this
25447 * @param {Object} data The JSON data loaded
25451 * Fires when data is loaded.
25452 * @param {Roo.JsonView} this
25453 * @param {Object} data The JSON data loaded
25454 * @param {Object} response The raw Connect response object
25457 * @event loadexception
25458 * Fires when loading fails.
25459 * @param {Roo.JsonView} this
25460 * @param {Object} response The raw Connect response object
25463 'beforerender' : true,
25465 'loadexception' : true
25468 Roo.extend(Roo.JsonView, Roo.View, {
25470 * @type {String} The root property in the loaded JSON object that contains the data
25475 * Refreshes the view.
25477 refresh : function(){
25478 this.clearSelections();
25479 this.el.update("");
25481 var o = this.jsonData;
25482 if(o && o.length > 0){
25483 for(var i = 0, len = o.length; i < len; i++){
25484 var data = this.prepareData(o[i], i, o);
25485 html[html.length] = this.tpl.apply(data);
25488 html.push(this.emptyText);
25490 this.el.update(html.join(""));
25491 this.nodes = this.el.dom.childNodes;
25492 this.updateIndexes(0);
25496 * 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.
25497 * @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:
25500 url: "your-url.php",
25501 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25502 callback: yourFunction,
25503 scope: yourObject, //(optional scope)
25506 text: "Loading...",
25511 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25512 * 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.
25513 * @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}
25514 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25515 * @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.
25518 var um = this.el.getUpdateManager();
25519 um.update.apply(um, arguments);
25522 render : function(el, response){
25523 this.clearSelections();
25524 this.el.update("");
25527 o = Roo.util.JSON.decode(response.responseText);
25530 o = o[this.jsonRoot];
25535 * The current JSON data or null
25538 this.beforeRender();
25543 * Get the number of records in the current JSON dataset
25546 getCount : function(){
25547 return this.jsonData ? this.jsonData.length : 0;
25551 * Returns the JSON object for the specified node(s)
25552 * @param {HTMLElement/Array} node The node or an array of nodes
25553 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25554 * you get the JSON object for the node
25556 getNodeData : function(node){
25557 if(node instanceof Array){
25559 for(var i = 0, len = node.length; i < len; i++){
25560 data.push(this.getNodeData(node[i]));
25564 return this.jsonData[this.indexOf(node)] || null;
25567 beforeRender : function(){
25568 this.snapshot = this.jsonData;
25570 this.sort.apply(this, this.sortInfo);
25572 this.fireEvent("beforerender", this, this.jsonData);
25575 onLoad : function(el, o){
25576 this.fireEvent("load", this, this.jsonData, o);
25579 onLoadException : function(el, o){
25580 this.fireEvent("loadexception", this, o);
25584 * Filter the data by a specific property.
25585 * @param {String} property A property on your JSON objects
25586 * @param {String/RegExp} value Either string that the property values
25587 * should start with, or a RegExp to test against the property
25589 filter : function(property, value){
25592 var ss = this.snapshot;
25593 if(typeof value == "string"){
25594 var vlen = value.length;
25596 this.clearFilter();
25599 value = value.toLowerCase();
25600 for(var i = 0, len = ss.length; i < len; i++){
25602 if(o[property].substr(0, vlen).toLowerCase() == value){
25606 } else if(value.exec){ // regex?
25607 for(var i = 0, len = ss.length; i < len; i++){
25609 if(value.test(o[property])){
25616 this.jsonData = data;
25622 * Filter by a function. The passed function will be called with each
25623 * object in the current dataset. If the function returns true the value is kept,
25624 * otherwise it is filtered.
25625 * @param {Function} fn
25626 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25628 filterBy : function(fn, scope){
25631 var ss = this.snapshot;
25632 for(var i = 0, len = ss.length; i < len; i++){
25634 if(fn.call(scope || this, o)){
25638 this.jsonData = data;
25644 * Clears the current filter.
25646 clearFilter : function(){
25647 if(this.snapshot && this.jsonData != this.snapshot){
25648 this.jsonData = this.snapshot;
25655 * Sorts the data for this view and refreshes it.
25656 * @param {String} property A property on your JSON objects to sort on
25657 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25658 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25660 sort : function(property, dir, sortType){
25661 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25664 var dsc = dir && dir.toLowerCase() == "desc";
25665 var f = function(o1, o2){
25666 var v1 = sortType ? sortType(o1[p]) : o1[p];
25667 var v2 = sortType ? sortType(o2[p]) : o2[p];
25670 return dsc ? +1 : -1;
25671 } else if(v1 > v2){
25672 return dsc ? -1 : +1;
25677 this.jsonData.sort(f);
25679 if(this.jsonData != this.snapshot){
25680 this.snapshot.sort(f);
25686 * Ext JS Library 1.1.1
25687 * Copyright(c) 2006-2007, Ext JS, LLC.
25689 * Originally Released Under LGPL - original licence link has changed is not relivant.
25692 * <script type="text/javascript">
25697 * @class Roo.ColorPalette
25698 * @extends Roo.Component
25699 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25700 * Here's an example of typical usage:
25702 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25703 cp.render('my-div');
25705 cp.on('select', function(palette, selColor){
25706 // do something with selColor
25710 * Create a new ColorPalette
25711 * @param {Object} config The config object
25713 Roo.ColorPalette = function(config){
25714 Roo.ColorPalette.superclass.constructor.call(this, config);
25718 * Fires when a color is selected
25719 * @param {ColorPalette} this
25720 * @param {String} color The 6-digit color hex code (without the # symbol)
25726 this.on("select", this.handler, this.scope, true);
25729 Roo.extend(Roo.ColorPalette, Roo.Component, {
25731 * @cfg {String} itemCls
25732 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25734 itemCls : "x-color-palette",
25736 * @cfg {String} value
25737 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25738 * the hex codes are case-sensitive.
25741 clickEvent:'click',
25743 ctype: "Roo.ColorPalette",
25746 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25748 allowReselect : false,
25751 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25752 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25753 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25754 * of colors with the width setting until the box is symmetrical.</p>
25755 * <p>You can override individual colors if needed:</p>
25757 var cp = new Roo.ColorPalette();
25758 cp.colors[0] = "FF0000"; // change the first box to red
25761 Or you can provide a custom array of your own for complete control:
25763 var cp = new Roo.ColorPalette();
25764 cp.colors = ["000000", "993300", "333300"];
25769 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25770 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25771 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25772 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25773 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25777 onRender : function(container, position){
25778 var t = new Roo.MasterTemplate(
25779 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25781 var c = this.colors;
25782 for(var i = 0, len = c.length; i < len; i++){
25785 var el = document.createElement("div");
25786 el.className = this.itemCls;
25788 container.dom.insertBefore(el, position);
25789 this.el = Roo.get(el);
25790 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25791 if(this.clickEvent != 'click'){
25792 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25797 afterRender : function(){
25798 Roo.ColorPalette.superclass.afterRender.call(this);
25800 var s = this.value;
25807 handleClick : function(e, t){
25808 e.preventDefault();
25809 if(!this.disabled){
25810 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25811 this.select(c.toUpperCase());
25816 * Selects the specified color in the palette (fires the select event)
25817 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25819 select : function(color){
25820 color = color.replace("#", "");
25821 if(color != this.value || this.allowReselect){
25824 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25826 el.child("a.color-"+color).addClass("x-color-palette-sel");
25827 this.value = color;
25828 this.fireEvent("select", this, color);
25833 * Ext JS Library 1.1.1
25834 * Copyright(c) 2006-2007, Ext JS, LLC.
25836 * Originally Released Under LGPL - original licence link has changed is not relivant.
25839 * <script type="text/javascript">
25843 * @class Roo.DatePicker
25844 * @extends Roo.Component
25845 * Simple date picker class.
25847 * Create a new DatePicker
25848 * @param {Object} config The config object
25850 Roo.DatePicker = function(config){
25851 Roo.DatePicker.superclass.constructor.call(this, config);
25853 this.value = config && config.value ?
25854 config.value.clearTime() : new Date().clearTime();
25859 * Fires when a date is selected
25860 * @param {DatePicker} this
25861 * @param {Date} date The selected date
25865 * @event monthchange
25866 * Fires when the displayed month changes
25867 * @param {DatePicker} this
25868 * @param {Date} date The selected month
25870 'monthchange': true
25874 this.on("select", this.handler, this.scope || this);
25876 // build the disabledDatesRE
25877 if(!this.disabledDatesRE && this.disabledDates){
25878 var dd = this.disabledDates;
25880 for(var i = 0; i < dd.length; i++){
25882 if(i != dd.length-1) re += "|";
25884 this.disabledDatesRE = new RegExp(re + ")");
25888 Roo.extend(Roo.DatePicker, Roo.Component, {
25890 * @cfg {String} todayText
25891 * The text to display on the button that selects the current date (defaults to "Today")
25893 todayText : "Today",
25895 * @cfg {String} okText
25896 * The text to display on the ok button
25898 okText : " OK ", //   to give the user extra clicking room
25900 * @cfg {String} cancelText
25901 * The text to display on the cancel button
25903 cancelText : "Cancel",
25905 * @cfg {String} todayTip
25906 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25908 todayTip : "{0} (Spacebar)",
25910 * @cfg {Date} minDate
25911 * Minimum allowable date (JavaScript date object, defaults to null)
25915 * @cfg {Date} maxDate
25916 * Maximum allowable date (JavaScript date object, defaults to null)
25920 * @cfg {String} minText
25921 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25923 minText : "This date is before the minimum date",
25925 * @cfg {String} maxText
25926 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25928 maxText : "This date is after the maximum date",
25930 * @cfg {String} format
25931 * The default date format string which can be overriden for localization support. The format must be
25932 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25936 * @cfg {Array} disabledDays
25937 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25939 disabledDays : null,
25941 * @cfg {String} disabledDaysText
25942 * The tooltip to display when the date falls on a disabled day (defaults to "")
25944 disabledDaysText : "",
25946 * @cfg {RegExp} disabledDatesRE
25947 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25949 disabledDatesRE : null,
25951 * @cfg {String} disabledDatesText
25952 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25954 disabledDatesText : "",
25956 * @cfg {Boolean} constrainToViewport
25957 * True to constrain the date picker to the viewport (defaults to true)
25959 constrainToViewport : true,
25961 * @cfg {Array} monthNames
25962 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25964 monthNames : Date.monthNames,
25966 * @cfg {Array} dayNames
25967 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25969 dayNames : Date.dayNames,
25971 * @cfg {String} nextText
25972 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25974 nextText: 'Next Month (Control+Right)',
25976 * @cfg {String} prevText
25977 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25979 prevText: 'Previous Month (Control+Left)',
25981 * @cfg {String} monthYearText
25982 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25984 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25986 * @cfg {Number} startDay
25987 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25991 * @cfg {Bool} showClear
25992 * Show a clear button (usefull for date form elements that can be blank.)
25998 * Sets the value of the date field
25999 * @param {Date} value The date to set
26001 setValue : function(value){
26002 var old = this.value;
26004 if (typeof(value) == 'string') {
26006 value = Date.parseDate(value, this.format);
26009 value = new Date();
26012 this.value = value.clearTime(true);
26014 this.update(this.value);
26019 * Gets the current selected value of the date field
26020 * @return {Date} The selected date
26022 getValue : function(){
26027 focus : function(){
26029 this.update(this.activeDate);
26034 onRender : function(container, position){
26037 '<table cellspacing="0">',
26038 '<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>',
26039 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26040 var dn = this.dayNames;
26041 for(var i = 0; i < 7; i++){
26042 var d = this.startDay+i;
26046 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26048 m[m.length] = "</tr></thead><tbody><tr>";
26049 for(var i = 0; i < 42; i++) {
26050 if(i % 7 == 0 && i != 0){
26051 m[m.length] = "</tr><tr>";
26053 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26055 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26056 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26058 var el = document.createElement("div");
26059 el.className = "x-date-picker";
26060 el.innerHTML = m.join("");
26062 container.dom.insertBefore(el, position);
26064 this.el = Roo.get(el);
26065 this.eventEl = Roo.get(el.firstChild);
26067 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26068 handler: this.showPrevMonth,
26070 preventDefault:true,
26074 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26075 handler: this.showNextMonth,
26077 preventDefault:true,
26081 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26083 this.monthPicker = this.el.down('div.x-date-mp');
26084 this.monthPicker.enableDisplayMode('block');
26086 var kn = new Roo.KeyNav(this.eventEl, {
26087 "left" : function(e){
26089 this.showPrevMonth() :
26090 this.update(this.activeDate.add("d", -1));
26093 "right" : function(e){
26095 this.showNextMonth() :
26096 this.update(this.activeDate.add("d", 1));
26099 "up" : function(e){
26101 this.showNextYear() :
26102 this.update(this.activeDate.add("d", -7));
26105 "down" : function(e){
26107 this.showPrevYear() :
26108 this.update(this.activeDate.add("d", 7));
26111 "pageUp" : function(e){
26112 this.showNextMonth();
26115 "pageDown" : function(e){
26116 this.showPrevMonth();
26119 "enter" : function(e){
26120 e.stopPropagation();
26127 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26129 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26131 this.el.unselectable();
26133 this.cells = this.el.select("table.x-date-inner tbody td");
26134 this.textNodes = this.el.query("table.x-date-inner tbody span");
26136 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26138 tooltip: this.monthYearText
26141 this.mbtn.on('click', this.showMonthPicker, this);
26142 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26145 var today = (new Date()).dateFormat(this.format);
26147 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26148 if (this.showClear) {
26149 baseTb.add( new Roo.Toolbar.Fill());
26152 text: String.format(this.todayText, today),
26153 tooltip: String.format(this.todayTip, today),
26154 handler: this.selectToday,
26158 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26161 if (this.showClear) {
26163 baseTb.add( new Roo.Toolbar.Fill());
26166 cls: 'x-btn-icon x-btn-clear',
26167 handler: function() {
26169 this.fireEvent("select", this, '');
26179 this.update(this.value);
26182 createMonthPicker : function(){
26183 if(!this.monthPicker.dom.firstChild){
26184 var buf = ['<table border="0" cellspacing="0">'];
26185 for(var i = 0; i < 6; i++){
26187 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26188 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26190 '<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>' :
26191 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26195 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26197 '</button><button type="button" class="x-date-mp-cancel">',
26199 '</button></td></tr>',
26202 this.monthPicker.update(buf.join(''));
26203 this.monthPicker.on('click', this.onMonthClick, this);
26204 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26206 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26207 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26209 this.mpMonths.each(function(m, a, i){
26212 m.dom.xmonth = 5 + Math.round(i * .5);
26214 m.dom.xmonth = Math.round((i-1) * .5);
26220 showMonthPicker : function(){
26221 this.createMonthPicker();
26222 var size = this.el.getSize();
26223 this.monthPicker.setSize(size);
26224 this.monthPicker.child('table').setSize(size);
26226 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26227 this.updateMPMonth(this.mpSelMonth);
26228 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26229 this.updateMPYear(this.mpSelYear);
26231 this.monthPicker.slideIn('t', {duration:.2});
26234 updateMPYear : function(y){
26236 var ys = this.mpYears.elements;
26237 for(var i = 1; i <= 10; i++){
26238 var td = ys[i-1], y2;
26240 y2 = y + Math.round(i * .5);
26241 td.firstChild.innerHTML = y2;
26244 y2 = y - (5-Math.round(i * .5));
26245 td.firstChild.innerHTML = y2;
26248 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26252 updateMPMonth : function(sm){
26253 this.mpMonths.each(function(m, a, i){
26254 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26258 selectMPMonth: function(m){
26262 onMonthClick : function(e, t){
26264 var el = new Roo.Element(t), pn;
26265 if(el.is('button.x-date-mp-cancel')){
26266 this.hideMonthPicker();
26268 else if(el.is('button.x-date-mp-ok')){
26269 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26270 this.hideMonthPicker();
26272 else if(pn = el.up('td.x-date-mp-month', 2)){
26273 this.mpMonths.removeClass('x-date-mp-sel');
26274 pn.addClass('x-date-mp-sel');
26275 this.mpSelMonth = pn.dom.xmonth;
26277 else if(pn = el.up('td.x-date-mp-year', 2)){
26278 this.mpYears.removeClass('x-date-mp-sel');
26279 pn.addClass('x-date-mp-sel');
26280 this.mpSelYear = pn.dom.xyear;
26282 else if(el.is('a.x-date-mp-prev')){
26283 this.updateMPYear(this.mpyear-10);
26285 else if(el.is('a.x-date-mp-next')){
26286 this.updateMPYear(this.mpyear+10);
26290 onMonthDblClick : function(e, t){
26292 var el = new Roo.Element(t), pn;
26293 if(pn = el.up('td.x-date-mp-month', 2)){
26294 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26295 this.hideMonthPicker();
26297 else if(pn = el.up('td.x-date-mp-year', 2)){
26298 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26299 this.hideMonthPicker();
26303 hideMonthPicker : function(disableAnim){
26304 if(this.monthPicker){
26305 if(disableAnim === true){
26306 this.monthPicker.hide();
26308 this.monthPicker.slideOut('t', {duration:.2});
26314 showPrevMonth : function(e){
26315 this.update(this.activeDate.add("mo", -1));
26319 showNextMonth : function(e){
26320 this.update(this.activeDate.add("mo", 1));
26324 showPrevYear : function(){
26325 this.update(this.activeDate.add("y", -1));
26329 showNextYear : function(){
26330 this.update(this.activeDate.add("y", 1));
26334 handleMouseWheel : function(e){
26335 var delta = e.getWheelDelta();
26337 this.showPrevMonth();
26339 } else if(delta < 0){
26340 this.showNextMonth();
26346 handleDateClick : function(e, t){
26348 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26349 this.setValue(new Date(t.dateValue));
26350 this.fireEvent("select", this, this.value);
26355 selectToday : function(){
26356 this.setValue(new Date().clearTime());
26357 this.fireEvent("select", this, this.value);
26361 update : function(date)
26363 var vd = this.activeDate;
26364 this.activeDate = date;
26366 var t = date.getTime();
26367 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26368 this.cells.removeClass("x-date-selected");
26369 this.cells.each(function(c){
26370 if(c.dom.firstChild.dateValue == t){
26371 c.addClass("x-date-selected");
26372 setTimeout(function(){
26373 try{c.dom.firstChild.focus();}catch(e){}
26382 var days = date.getDaysInMonth();
26383 var firstOfMonth = date.getFirstDateOfMonth();
26384 var startingPos = firstOfMonth.getDay()-this.startDay;
26386 if(startingPos <= this.startDay){
26390 var pm = date.add("mo", -1);
26391 var prevStart = pm.getDaysInMonth()-startingPos;
26393 var cells = this.cells.elements;
26394 var textEls = this.textNodes;
26395 days += startingPos;
26397 // convert everything to numbers so it's fast
26398 var day = 86400000;
26399 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26400 var today = new Date().clearTime().getTime();
26401 var sel = date.clearTime().getTime();
26402 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26403 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26404 var ddMatch = this.disabledDatesRE;
26405 var ddText = this.disabledDatesText;
26406 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26407 var ddaysText = this.disabledDaysText;
26408 var format = this.format;
26410 var setCellClass = function(cal, cell){
26412 var t = d.getTime();
26413 cell.firstChild.dateValue = t;
26415 cell.className += " x-date-today";
26416 cell.title = cal.todayText;
26419 cell.className += " x-date-selected";
26420 setTimeout(function(){
26421 try{cell.firstChild.focus();}catch(e){}
26426 cell.className = " x-date-disabled";
26427 cell.title = cal.minText;
26431 cell.className = " x-date-disabled";
26432 cell.title = cal.maxText;
26436 if(ddays.indexOf(d.getDay()) != -1){
26437 cell.title = ddaysText;
26438 cell.className = " x-date-disabled";
26441 if(ddMatch && format){
26442 var fvalue = d.dateFormat(format);
26443 if(ddMatch.test(fvalue)){
26444 cell.title = ddText.replace("%0", fvalue);
26445 cell.className = " x-date-disabled";
26451 for(; i < startingPos; i++) {
26452 textEls[i].innerHTML = (++prevStart);
26453 d.setDate(d.getDate()+1);
26454 cells[i].className = "x-date-prevday";
26455 setCellClass(this, cells[i]);
26457 for(; i < days; i++){
26458 intDay = i - startingPos + 1;
26459 textEls[i].innerHTML = (intDay);
26460 d.setDate(d.getDate()+1);
26461 cells[i].className = "x-date-active";
26462 setCellClass(this, cells[i]);
26465 for(; i < 42; i++) {
26466 textEls[i].innerHTML = (++extraDays);
26467 d.setDate(d.getDate()+1);
26468 cells[i].className = "x-date-nextday";
26469 setCellClass(this, cells[i]);
26472 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26473 this.fireEvent('monthchange', this, date);
26475 if(!this.internalRender){
26476 var main = this.el.dom.firstChild;
26477 var w = main.offsetWidth;
26478 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26479 Roo.fly(main).setWidth(w);
26480 this.internalRender = true;
26481 // opera does not respect the auto grow header center column
26482 // then, after it gets a width opera refuses to recalculate
26483 // without a second pass
26484 if(Roo.isOpera && !this.secondPass){
26485 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26486 this.secondPass = true;
26487 this.update.defer(10, this, [date]);
26495 * Ext JS Library 1.1.1
26496 * Copyright(c) 2006-2007, Ext JS, LLC.
26498 * Originally Released Under LGPL - original licence link has changed is not relivant.
26501 * <script type="text/javascript">
26504 * @class Roo.TabPanel
26505 * @extends Roo.util.Observable
26506 * A lightweight tab container.
26510 // basic tabs 1, built from existing content
26511 var tabs = new Roo.TabPanel("tabs1");
26512 tabs.addTab("script", "View Script");
26513 tabs.addTab("markup", "View Markup");
26514 tabs.activate("script");
26516 // more advanced tabs, built from javascript
26517 var jtabs = new Roo.TabPanel("jtabs");
26518 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26520 // set up the UpdateManager
26521 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26522 var updater = tab2.getUpdateManager();
26523 updater.setDefaultUrl("ajax1.htm");
26524 tab2.on('activate', updater.refresh, updater, true);
26526 // Use setUrl for Ajax loading
26527 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26528 tab3.setUrl("ajax2.htm", null, true);
26531 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26534 jtabs.activate("jtabs-1");
26537 * Create a new TabPanel.
26538 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26539 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26541 Roo.TabPanel = function(container, config){
26543 * The container element for this TabPanel.
26544 * @type Roo.Element
26546 this.el = Roo.get(container, true);
26548 if(typeof config == "boolean"){
26549 this.tabPosition = config ? "bottom" : "top";
26551 Roo.apply(this, config);
26554 if(this.tabPosition == "bottom"){
26555 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26556 this.el.addClass("x-tabs-bottom");
26558 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26559 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26560 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26562 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26564 if(this.tabPosition != "bottom"){
26565 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26566 * @type Roo.Element
26568 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26569 this.el.addClass("x-tabs-top");
26573 this.bodyEl.setStyle("position", "relative");
26575 this.active = null;
26576 this.activateDelegate = this.activate.createDelegate(this);
26581 * Fires when the active tab changes
26582 * @param {Roo.TabPanel} this
26583 * @param {Roo.TabPanelItem} activePanel The new active tab
26587 * @event beforetabchange
26588 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26589 * @param {Roo.TabPanel} this
26590 * @param {Object} e Set cancel to true on this object to cancel the tab change
26591 * @param {Roo.TabPanelItem} tab The tab being changed to
26593 "beforetabchange" : true
26596 Roo.EventManager.onWindowResize(this.onResize, this);
26597 this.cpad = this.el.getPadding("lr");
26598 this.hiddenCount = 0;
26601 // toolbar on the tabbar support...
26602 if (this.toolbar) {
26603 var tcfg = this.toolbar;
26604 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26605 this.toolbar = new Roo.Toolbar(tcfg);
26606 if (Roo.isSafari) {
26607 var tbl = tcfg.container.child('table', true);
26608 tbl.setAttribute('width', '100%');
26615 Roo.TabPanel.superclass.constructor.call(this);
26618 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26620 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26622 tabPosition : "top",
26624 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26626 currentTabWidth : 0,
26628 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26632 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26636 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26638 preferredTabWidth : 175,
26640 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26642 resizeTabs : false,
26644 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26646 monitorResize : true,
26648 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26653 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26654 * @param {String} id The id of the div to use <b>or create</b>
26655 * @param {String} text The text for the tab
26656 * @param {String} content (optional) Content to put in the TabPanelItem body
26657 * @param {Boolean} closable (optional) True to create a close icon on the tab
26658 * @return {Roo.TabPanelItem} The created TabPanelItem
26660 addTab : function(id, text, content, closable){
26661 var item = new Roo.TabPanelItem(this, id, text, closable);
26662 this.addTabItem(item);
26664 item.setContent(content);
26670 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26671 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26672 * @return {Roo.TabPanelItem}
26674 getTab : function(id){
26675 return this.items[id];
26679 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26680 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26682 hideTab : function(id){
26683 var t = this.items[id];
26686 this.hiddenCount++;
26687 this.autoSizeTabs();
26692 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26693 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26695 unhideTab : function(id){
26696 var t = this.items[id];
26698 t.setHidden(false);
26699 this.hiddenCount--;
26700 this.autoSizeTabs();
26705 * Adds an existing {@link Roo.TabPanelItem}.
26706 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26708 addTabItem : function(item){
26709 this.items[item.id] = item;
26710 this.items.push(item);
26711 if(this.resizeTabs){
26712 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26713 this.autoSizeTabs();
26720 * Removes a {@link Roo.TabPanelItem}.
26721 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26723 removeTab : function(id){
26724 var items = this.items;
26725 var tab = items[id];
26726 if(!tab) { return; }
26727 var index = items.indexOf(tab);
26728 if(this.active == tab && items.length > 1){
26729 var newTab = this.getNextAvailable(index);
26734 this.stripEl.dom.removeChild(tab.pnode.dom);
26735 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26736 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26738 items.splice(index, 1);
26739 delete this.items[tab.id];
26740 tab.fireEvent("close", tab);
26741 tab.purgeListeners();
26742 this.autoSizeTabs();
26745 getNextAvailable : function(start){
26746 var items = this.items;
26748 // look for a next tab that will slide over to
26749 // replace the one being removed
26750 while(index < items.length){
26751 var item = items[++index];
26752 if(item && !item.isHidden()){
26756 // if one isn't found select the previous tab (on the left)
26759 var item = items[--index];
26760 if(item && !item.isHidden()){
26768 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26769 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26771 disableTab : function(id){
26772 var tab = this.items[id];
26773 if(tab && this.active != tab){
26779 * Enables a {@link Roo.TabPanelItem} that is disabled.
26780 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26782 enableTab : function(id){
26783 var tab = this.items[id];
26788 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26789 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26790 * @return {Roo.TabPanelItem} The TabPanelItem.
26792 activate : function(id){
26793 var tab = this.items[id];
26797 if(tab == this.active || tab.disabled){
26801 this.fireEvent("beforetabchange", this, e, tab);
26802 if(e.cancel !== true && !tab.disabled){
26804 this.active.hide();
26806 this.active = this.items[id];
26807 this.active.show();
26808 this.fireEvent("tabchange", this, this.active);
26814 * Gets the active {@link Roo.TabPanelItem}.
26815 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26817 getActiveTab : function(){
26818 return this.active;
26822 * Updates the tab body element to fit the height of the container element
26823 * for overflow scrolling
26824 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26826 syncHeight : function(targetHeight){
26827 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26828 var bm = this.bodyEl.getMargins();
26829 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26830 this.bodyEl.setHeight(newHeight);
26834 onResize : function(){
26835 if(this.monitorResize){
26836 this.autoSizeTabs();
26841 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26843 beginUpdate : function(){
26844 this.updating = true;
26848 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26850 endUpdate : function(){
26851 this.updating = false;
26852 this.autoSizeTabs();
26856 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26858 autoSizeTabs : function(){
26859 var count = this.items.length;
26860 var vcount = count - this.hiddenCount;
26861 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26862 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26863 var availWidth = Math.floor(w / vcount);
26864 var b = this.stripBody;
26865 if(b.getWidth() > w){
26866 var tabs = this.items;
26867 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26868 if(availWidth < this.minTabWidth){
26869 /*if(!this.sleft){ // incomplete scrolling code
26870 this.createScrollButtons();
26873 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26876 if(this.currentTabWidth < this.preferredTabWidth){
26877 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26883 * Returns the number of tabs in this TabPanel.
26886 getCount : function(){
26887 return this.items.length;
26891 * Resizes all the tabs to the passed width
26892 * @param {Number} The new width
26894 setTabWidth : function(width){
26895 this.currentTabWidth = width;
26896 for(var i = 0, len = this.items.length; i < len; i++) {
26897 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26902 * Destroys this TabPanel
26903 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26905 destroy : function(removeEl){
26906 Roo.EventManager.removeResizeListener(this.onResize, this);
26907 for(var i = 0, len = this.items.length; i < len; i++){
26908 this.items[i].purgeListeners();
26910 if(removeEl === true){
26911 this.el.update("");
26918 * @class Roo.TabPanelItem
26919 * @extends Roo.util.Observable
26920 * Represents an individual item (tab plus body) in a TabPanel.
26921 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26922 * @param {String} id The id of this TabPanelItem
26923 * @param {String} text The text for the tab of this TabPanelItem
26924 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26926 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26928 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26929 * @type Roo.TabPanel
26931 this.tabPanel = tabPanel;
26933 * The id for this TabPanelItem
26938 this.disabled = false;
26942 this.loaded = false;
26943 this.closable = closable;
26946 * The body element for this TabPanelItem.
26947 * @type Roo.Element
26949 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26950 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26951 this.bodyEl.setStyle("display", "block");
26952 this.bodyEl.setStyle("zoom", "1");
26955 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26957 this.el = Roo.get(els.el, true);
26958 this.inner = Roo.get(els.inner, true);
26959 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26960 this.pnode = Roo.get(els.el.parentNode, true);
26961 this.el.on("mousedown", this.onTabMouseDown, this);
26962 this.el.on("click", this.onTabClick, this);
26965 var c = Roo.get(els.close, true);
26966 c.dom.title = this.closeText;
26967 c.addClassOnOver("close-over");
26968 c.on("click", this.closeClick, this);
26974 * Fires when this tab becomes the active tab.
26975 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26976 * @param {Roo.TabPanelItem} this
26980 * @event beforeclose
26981 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26982 * @param {Roo.TabPanelItem} this
26983 * @param {Object} e Set cancel to true on this object to cancel the close.
26985 "beforeclose": true,
26988 * Fires when this tab is closed.
26989 * @param {Roo.TabPanelItem} this
26993 * @event deactivate
26994 * Fires when this tab is no longer the active tab.
26995 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26996 * @param {Roo.TabPanelItem} this
26998 "deactivate" : true
27000 this.hidden = false;
27002 Roo.TabPanelItem.superclass.constructor.call(this);
27005 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27006 purgeListeners : function(){
27007 Roo.util.Observable.prototype.purgeListeners.call(this);
27008 this.el.removeAllListeners();
27011 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27014 this.pnode.addClass("on");
27017 this.tabPanel.stripWrap.repaint();
27019 this.fireEvent("activate", this.tabPanel, this);
27023 * Returns true if this tab is the active tab.
27024 * @return {Boolean}
27026 isActive : function(){
27027 return this.tabPanel.getActiveTab() == this;
27031 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27034 this.pnode.removeClass("on");
27036 this.fireEvent("deactivate", this.tabPanel, this);
27039 hideAction : function(){
27040 this.bodyEl.hide();
27041 this.bodyEl.setStyle("position", "absolute");
27042 this.bodyEl.setLeft("-20000px");
27043 this.bodyEl.setTop("-20000px");
27046 showAction : function(){
27047 this.bodyEl.setStyle("position", "relative");
27048 this.bodyEl.setTop("");
27049 this.bodyEl.setLeft("");
27050 this.bodyEl.show();
27054 * Set the tooltip for the tab.
27055 * @param {String} tooltip The tab's tooltip
27057 setTooltip : function(text){
27058 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27059 this.textEl.dom.qtip = text;
27060 this.textEl.dom.removeAttribute('title');
27062 this.textEl.dom.title = text;
27066 onTabClick : function(e){
27067 e.preventDefault();
27068 this.tabPanel.activate(this.id);
27071 onTabMouseDown : function(e){
27072 e.preventDefault();
27073 this.tabPanel.activate(this.id);
27076 getWidth : function(){
27077 return this.inner.getWidth();
27080 setWidth : function(width){
27081 var iwidth = width - this.pnode.getPadding("lr");
27082 this.inner.setWidth(iwidth);
27083 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27084 this.pnode.setWidth(width);
27088 * Show or hide the tab
27089 * @param {Boolean} hidden True to hide or false to show.
27091 setHidden : function(hidden){
27092 this.hidden = hidden;
27093 this.pnode.setStyle("display", hidden ? "none" : "");
27097 * Returns true if this tab is "hidden"
27098 * @return {Boolean}
27100 isHidden : function(){
27101 return this.hidden;
27105 * Returns the text for this tab
27108 getText : function(){
27112 autoSize : function(){
27113 //this.el.beginMeasure();
27114 this.textEl.setWidth(1);
27115 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
27116 //this.el.endMeasure();
27120 * Sets the text for the tab (Note: this also sets the tooltip text)
27121 * @param {String} text The tab's text and tooltip
27123 setText : function(text){
27125 this.textEl.update(text);
27126 this.setTooltip(text);
27127 if(!this.tabPanel.resizeTabs){
27132 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27134 activate : function(){
27135 this.tabPanel.activate(this.id);
27139 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27141 disable : function(){
27142 if(this.tabPanel.active != this){
27143 this.disabled = true;
27144 this.pnode.addClass("disabled");
27149 * Enables this TabPanelItem if it was previously disabled.
27151 enable : function(){
27152 this.disabled = false;
27153 this.pnode.removeClass("disabled");
27157 * Sets the content for this TabPanelItem.
27158 * @param {String} content The content
27159 * @param {Boolean} loadScripts true to look for and load scripts
27161 setContent : function(content, loadScripts){
27162 this.bodyEl.update(content, loadScripts);
27166 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27167 * @return {Roo.UpdateManager} The UpdateManager
27169 getUpdateManager : function(){
27170 return this.bodyEl.getUpdateManager();
27174 * Set a URL to be used to load the content for this TabPanelItem.
27175 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27176 * @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)
27177 * @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)
27178 * @return {Roo.UpdateManager} The UpdateManager
27180 setUrl : function(url, params, loadOnce){
27181 if(this.refreshDelegate){
27182 this.un('activate', this.refreshDelegate);
27184 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27185 this.on("activate", this.refreshDelegate);
27186 return this.bodyEl.getUpdateManager();
27190 _handleRefresh : function(url, params, loadOnce){
27191 if(!loadOnce || !this.loaded){
27192 var updater = this.bodyEl.getUpdateManager();
27193 updater.update(url, params, this._setLoaded.createDelegate(this));
27198 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27199 * Will fail silently if the setUrl method has not been called.
27200 * This does not activate the panel, just updates its content.
27202 refresh : function(){
27203 if(this.refreshDelegate){
27204 this.loaded = false;
27205 this.refreshDelegate();
27210 _setLoaded : function(){
27211 this.loaded = true;
27215 closeClick : function(e){
27218 this.fireEvent("beforeclose", this, o);
27219 if(o.cancel !== true){
27220 this.tabPanel.removeTab(this.id);
27224 * The text displayed in the tooltip for the close icon.
27227 closeText : "Close this tab"
27231 Roo.TabPanel.prototype.createStrip = function(container){
27232 var strip = document.createElement("div");
27233 strip.className = "x-tabs-wrap";
27234 container.appendChild(strip);
27238 Roo.TabPanel.prototype.createStripList = function(strip){
27239 // div wrapper for retard IE
27240 // returns the "tr" element.
27241 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27242 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27243 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27244 return strip.firstChild.firstChild.firstChild.firstChild;
27247 Roo.TabPanel.prototype.createBody = function(container){
27248 var body = document.createElement("div");
27249 Roo.id(body, "tab-body");
27250 Roo.fly(body).addClass("x-tabs-body");
27251 container.appendChild(body);
27255 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27256 var body = Roo.getDom(id);
27258 body = document.createElement("div");
27261 Roo.fly(body).addClass("x-tabs-item-body");
27262 bodyEl.insertBefore(body, bodyEl.firstChild);
27266 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27267 var td = document.createElement("td");
27268 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27269 //stripEl.appendChild(td);
27271 td.className = "x-tabs-closable";
27272 if(!this.closeTpl){
27273 this.closeTpl = new Roo.Template(
27274 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27275 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27276 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27279 var el = this.closeTpl.overwrite(td, {"text": text});
27280 var close = el.getElementsByTagName("div")[0];
27281 var inner = el.getElementsByTagName("em")[0];
27282 return {"el": el, "close": close, "inner": inner};
27285 this.tabTpl = new Roo.Template(
27286 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27287 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27290 var el = this.tabTpl.overwrite(td, {"text": text});
27291 var inner = el.getElementsByTagName("em")[0];
27292 return {"el": el, "inner": inner};
27296 * Ext JS Library 1.1.1
27297 * Copyright(c) 2006-2007, Ext JS, LLC.
27299 * Originally Released Under LGPL - original licence link has changed is not relivant.
27302 * <script type="text/javascript">
27306 * @class Roo.Button
27307 * @extends Roo.util.Observable
27308 * Simple Button class
27309 * @cfg {String} text The button text
27310 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27311 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27312 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27313 * @cfg {Object} scope The scope of the handler
27314 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27315 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27316 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27317 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27318 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27319 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27320 applies if enableToggle = true)
27321 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27322 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27323 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27325 * Create a new button
27326 * @param {Object} config The config object
27328 Roo.Button = function(renderTo, config)
27332 renderTo = config.renderTo || false;
27335 Roo.apply(this, config);
27339 * Fires when this button is clicked
27340 * @param {Button} this
27341 * @param {EventObject} e The click event
27346 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27347 * @param {Button} this
27348 * @param {Boolean} pressed
27353 * Fires when the mouse hovers over the button
27354 * @param {Button} this
27355 * @param {Event} e The event object
27357 'mouseover' : true,
27360 * Fires when the mouse exits the button
27361 * @param {Button} this
27362 * @param {Event} e The event object
27367 * Fires when the button is rendered
27368 * @param {Button} this
27373 this.menu = Roo.menu.MenuMgr.get(this.menu);
27375 // register listeners first!! - so render can be captured..
27376 Roo.util.Observable.call(this);
27378 this.render(renderTo);
27384 Roo.extend(Roo.Button, Roo.util.Observable, {
27390 * Read-only. True if this button is hidden
27395 * Read-only. True if this button is disabled
27400 * Read-only. True if this button is pressed (only if enableToggle = true)
27406 * @cfg {Number} tabIndex
27407 * The DOM tabIndex for this button (defaults to undefined)
27409 tabIndex : undefined,
27412 * @cfg {Boolean} enableToggle
27413 * True to enable pressed/not pressed toggling (defaults to false)
27415 enableToggle: false,
27417 * @cfg {Mixed} menu
27418 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27422 * @cfg {String} menuAlign
27423 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27425 menuAlign : "tl-bl?",
27428 * @cfg {String} iconCls
27429 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27431 iconCls : undefined,
27433 * @cfg {String} type
27434 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27439 menuClassTarget: 'tr',
27442 * @cfg {String} clickEvent
27443 * The type of event to map to the button's event handler (defaults to 'click')
27445 clickEvent : 'click',
27448 * @cfg {Boolean} handleMouseEvents
27449 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27451 handleMouseEvents : true,
27454 * @cfg {String} tooltipType
27455 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27457 tooltipType : 'qtip',
27460 * @cfg {String} cls
27461 * A CSS class to apply to the button's main element.
27465 * @cfg {Roo.Template} template (Optional)
27466 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27467 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27468 * require code modifications if required elements (e.g. a button) aren't present.
27472 render : function(renderTo){
27474 if(this.hideParent){
27475 this.parentEl = Roo.get(renderTo);
27477 if(!this.dhconfig){
27478 if(!this.template){
27479 if(!Roo.Button.buttonTemplate){
27480 // hideous table template
27481 Roo.Button.buttonTemplate = new Roo.Template(
27482 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27483 '<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>',
27484 "</tr></tbody></table>");
27486 this.template = Roo.Button.buttonTemplate;
27488 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27489 var btnEl = btn.child("button:first");
27490 btnEl.on('focus', this.onFocus, this);
27491 btnEl.on('blur', this.onBlur, this);
27493 btn.addClass(this.cls);
27496 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27499 btnEl.addClass(this.iconCls);
27501 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27504 if(this.tabIndex !== undefined){
27505 btnEl.dom.tabIndex = this.tabIndex;
27508 if(typeof this.tooltip == 'object'){
27509 Roo.QuickTips.tips(Roo.apply({
27513 btnEl.dom[this.tooltipType] = this.tooltip;
27517 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27521 this.el.dom.id = this.el.id = this.id;
27524 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27525 this.menu.on("show", this.onMenuShow, this);
27526 this.menu.on("hide", this.onMenuHide, this);
27528 btn.addClass("x-btn");
27529 if(Roo.isIE && !Roo.isIE7){
27530 this.autoWidth.defer(1, this);
27534 if(this.handleMouseEvents){
27535 btn.on("mouseover", this.onMouseOver, this);
27536 btn.on("mouseout", this.onMouseOut, this);
27537 btn.on("mousedown", this.onMouseDown, this);
27539 btn.on(this.clickEvent, this.onClick, this);
27540 //btn.on("mouseup", this.onMouseUp, this);
27547 Roo.ButtonToggleMgr.register(this);
27549 this.el.addClass("x-btn-pressed");
27552 var repeater = new Roo.util.ClickRepeater(btn,
27553 typeof this.repeat == "object" ? this.repeat : {}
27555 repeater.on("click", this.onClick, this);
27558 this.fireEvent('render', this);
27562 * Returns the button's underlying element
27563 * @return {Roo.Element} The element
27565 getEl : function(){
27570 * Destroys this Button and removes any listeners.
27572 destroy : function(){
27573 Roo.ButtonToggleMgr.unregister(this);
27574 this.el.removeAllListeners();
27575 this.purgeListeners();
27580 autoWidth : function(){
27582 this.el.setWidth("auto");
27583 if(Roo.isIE7 && Roo.isStrict){
27584 var ib = this.el.child('button');
27585 if(ib && ib.getWidth() > 20){
27587 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27592 this.el.beginMeasure();
27594 if(this.el.getWidth() < this.minWidth){
27595 this.el.setWidth(this.minWidth);
27598 this.el.endMeasure();
27605 * Assigns this button's click handler
27606 * @param {Function} handler The function to call when the button is clicked
27607 * @param {Object} scope (optional) Scope for the function passed in
27609 setHandler : function(handler, scope){
27610 this.handler = handler;
27611 this.scope = scope;
27615 * Sets this button's text
27616 * @param {String} text The button text
27618 setText : function(text){
27621 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27627 * Gets the text for this button
27628 * @return {String} The button text
27630 getText : function(){
27638 this.hidden = false;
27640 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27648 this.hidden = true;
27650 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27655 * Convenience function for boolean show/hide
27656 * @param {Boolean} visible True to show, false to hide
27658 setVisible: function(visible){
27667 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27668 * @param {Boolean} state (optional) Force a particular state
27670 toggle : function(state){
27671 state = state === undefined ? !this.pressed : state;
27672 if(state != this.pressed){
27674 this.el.addClass("x-btn-pressed");
27675 this.pressed = true;
27676 this.fireEvent("toggle", this, true);
27678 this.el.removeClass("x-btn-pressed");
27679 this.pressed = false;
27680 this.fireEvent("toggle", this, false);
27682 if(this.toggleHandler){
27683 this.toggleHandler.call(this.scope || this, this, state);
27691 focus : function(){
27692 this.el.child('button:first').focus();
27696 * Disable this button
27698 disable : function(){
27700 this.el.addClass("x-btn-disabled");
27702 this.disabled = true;
27706 * Enable this button
27708 enable : function(){
27710 this.el.removeClass("x-btn-disabled");
27712 this.disabled = false;
27716 * Convenience function for boolean enable/disable
27717 * @param {Boolean} enabled True to enable, false to disable
27719 setDisabled : function(v){
27720 this[v !== true ? "enable" : "disable"]();
27724 onClick : function(e){
27726 e.preventDefault();
27731 if(!this.disabled){
27732 if(this.enableToggle){
27735 if(this.menu && !this.menu.isVisible()){
27736 this.menu.show(this.el, this.menuAlign);
27738 this.fireEvent("click", this, e);
27740 this.el.removeClass("x-btn-over");
27741 this.handler.call(this.scope || this, this, e);
27746 onMouseOver : function(e){
27747 if(!this.disabled){
27748 this.el.addClass("x-btn-over");
27749 this.fireEvent('mouseover', this, e);
27753 onMouseOut : function(e){
27754 if(!e.within(this.el, true)){
27755 this.el.removeClass("x-btn-over");
27756 this.fireEvent('mouseout', this, e);
27760 onFocus : function(e){
27761 if(!this.disabled){
27762 this.el.addClass("x-btn-focus");
27766 onBlur : function(e){
27767 this.el.removeClass("x-btn-focus");
27770 onMouseDown : function(e){
27771 if(!this.disabled && e.button == 0){
27772 this.el.addClass("x-btn-click");
27773 Roo.get(document).on('mouseup', this.onMouseUp, this);
27777 onMouseUp : function(e){
27779 this.el.removeClass("x-btn-click");
27780 Roo.get(document).un('mouseup', this.onMouseUp, this);
27784 onMenuShow : function(e){
27785 this.el.addClass("x-btn-menu-active");
27788 onMenuHide : function(e){
27789 this.el.removeClass("x-btn-menu-active");
27793 // Private utility class used by Button
27794 Roo.ButtonToggleMgr = function(){
27797 function toggleGroup(btn, state){
27799 var g = groups[btn.toggleGroup];
27800 for(var i = 0, l = g.length; i < l; i++){
27802 g[i].toggle(false);
27809 register : function(btn){
27810 if(!btn.toggleGroup){
27813 var g = groups[btn.toggleGroup];
27815 g = groups[btn.toggleGroup] = [];
27818 btn.on("toggle", toggleGroup);
27821 unregister : function(btn){
27822 if(!btn.toggleGroup){
27825 var g = groups[btn.toggleGroup];
27828 btn.un("toggle", toggleGroup);
27834 * Ext JS Library 1.1.1
27835 * Copyright(c) 2006-2007, Ext JS, LLC.
27837 * Originally Released Under LGPL - original licence link has changed is not relivant.
27840 * <script type="text/javascript">
27844 * @class Roo.SplitButton
27845 * @extends Roo.Button
27846 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27847 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27848 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27849 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27850 * @cfg {String} arrowTooltip The title attribute of the arrow
27852 * Create a new menu button
27853 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27854 * @param {Object} config The config object
27856 Roo.SplitButton = function(renderTo, config){
27857 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27859 * @event arrowclick
27860 * Fires when this button's arrow is clicked
27861 * @param {SplitButton} this
27862 * @param {EventObject} e The click event
27864 this.addEvents({"arrowclick":true});
27867 Roo.extend(Roo.SplitButton, Roo.Button, {
27868 render : function(renderTo){
27869 // this is one sweet looking template!
27870 var tpl = new Roo.Template(
27871 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27872 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27873 '<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>',
27874 "</tbody></table></td><td>",
27875 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27876 '<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>',
27877 "</tbody></table></td></tr></table>"
27879 var btn = tpl.append(renderTo, [this.text, this.type], true);
27880 var btnEl = btn.child("button");
27882 btn.addClass(this.cls);
27885 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27888 btnEl.addClass(this.iconCls);
27890 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27894 if(this.handleMouseEvents){
27895 btn.on("mouseover", this.onMouseOver, this);
27896 btn.on("mouseout", this.onMouseOut, this);
27897 btn.on("mousedown", this.onMouseDown, this);
27898 btn.on("mouseup", this.onMouseUp, this);
27900 btn.on(this.clickEvent, this.onClick, this);
27902 if(typeof this.tooltip == 'object'){
27903 Roo.QuickTips.tips(Roo.apply({
27907 btnEl.dom[this.tooltipType] = this.tooltip;
27910 if(this.arrowTooltip){
27911 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27920 this.el.addClass("x-btn-pressed");
27922 if(Roo.isIE && !Roo.isIE7){
27923 this.autoWidth.defer(1, this);
27928 this.menu.on("show", this.onMenuShow, this);
27929 this.menu.on("hide", this.onMenuHide, this);
27931 this.fireEvent('render', this);
27935 autoWidth : function(){
27937 var tbl = this.el.child("table:first");
27938 var tbl2 = this.el.child("table:last");
27939 this.el.setWidth("auto");
27940 tbl.setWidth("auto");
27941 if(Roo.isIE7 && Roo.isStrict){
27942 var ib = this.el.child('button:first');
27943 if(ib && ib.getWidth() > 20){
27945 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27950 this.el.beginMeasure();
27952 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27953 tbl.setWidth(this.minWidth-tbl2.getWidth());
27956 this.el.endMeasure();
27959 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27963 * Sets this button's click handler
27964 * @param {Function} handler The function to call when the button is clicked
27965 * @param {Object} scope (optional) Scope for the function passed above
27967 setHandler : function(handler, scope){
27968 this.handler = handler;
27969 this.scope = scope;
27973 * Sets this button's arrow click handler
27974 * @param {Function} handler The function to call when the arrow is clicked
27975 * @param {Object} scope (optional) Scope for the function passed above
27977 setArrowHandler : function(handler, scope){
27978 this.arrowHandler = handler;
27979 this.scope = scope;
27985 focus : function(){
27987 this.el.child("button:first").focus();
27992 onClick : function(e){
27993 e.preventDefault();
27994 if(!this.disabled){
27995 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27996 if(this.menu && !this.menu.isVisible()){
27997 this.menu.show(this.el, this.menuAlign);
27999 this.fireEvent("arrowclick", this, e);
28000 if(this.arrowHandler){
28001 this.arrowHandler.call(this.scope || this, this, e);
28004 this.fireEvent("click", this, e);
28006 this.handler.call(this.scope || this, this, e);
28012 onMouseDown : function(e){
28013 if(!this.disabled){
28014 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28018 onMouseUp : function(e){
28019 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28024 // backwards compat
28025 Roo.MenuButton = Roo.SplitButton;/*
28027 * Ext JS Library 1.1.1
28028 * Copyright(c) 2006-2007, Ext JS, LLC.
28030 * Originally Released Under LGPL - original licence link has changed is not relivant.
28033 * <script type="text/javascript">
28037 * @class Roo.Toolbar
28038 * Basic Toolbar class.
28040 * Creates a new Toolbar
28041 * @param {Object} container The config object
28043 Roo.Toolbar = function(container, buttons, config)
28045 /// old consturctor format still supported..
28046 if(container instanceof Array){ // omit the container for later rendering
28047 buttons = container;
28051 if (typeof(container) == 'object' && container.xtype) {
28052 config = container;
28053 container = config.container;
28054 buttons = config.buttons || []; // not really - use items!!
28057 if (config && config.items) {
28058 xitems = config.items;
28059 delete config.items;
28061 Roo.apply(this, config);
28062 this.buttons = buttons;
28065 this.render(container);
28067 this.xitems = xitems;
28068 Roo.each(xitems, function(b) {
28074 Roo.Toolbar.prototype = {
28076 * @cfg {Array} items
28077 * array of button configs or elements to add (will be converted to a MixedCollection)
28081 * @cfg {String/HTMLElement/Element} container
28082 * The id or element that will contain the toolbar
28085 render : function(ct){
28086 this.el = Roo.get(ct);
28088 this.el.addClass(this.cls);
28090 // using a table allows for vertical alignment
28091 // 100% width is needed by Safari...
28092 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28093 this.tr = this.el.child("tr", true);
28095 this.items = new Roo.util.MixedCollection(false, function(o){
28096 return o.id || ("item" + (++autoId));
28099 this.add.apply(this, this.buttons);
28100 delete this.buttons;
28105 * Adds element(s) to the toolbar -- this function takes a variable number of
28106 * arguments of mixed type and adds them to the toolbar.
28107 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28109 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28110 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28111 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28112 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28113 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28114 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28115 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28116 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28117 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28119 * @param {Mixed} arg2
28120 * @param {Mixed} etc.
28123 var a = arguments, l = a.length;
28124 for(var i = 0; i < l; i++){
28129 _add : function(el) {
28132 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28135 if (el.applyTo){ // some kind of form field
28136 return this.addField(el);
28138 if (el.render){ // some kind of Toolbar.Item
28139 return this.addItem(el);
28141 if (typeof el == "string"){ // string
28142 if(el == "separator" || el == "-"){
28143 return this.addSeparator();
28146 return this.addSpacer();
28149 return this.addFill();
28151 return this.addText(el);
28154 if(el.tagName){ // element
28155 return this.addElement(el);
28157 if(typeof el == "object"){ // must be button config?
28158 return this.addButton(el);
28160 // and now what?!?!
28166 * Add an Xtype element
28167 * @param {Object} xtype Xtype Object
28168 * @return {Object} created Object
28170 addxtype : function(e){
28171 return this.add(e);
28175 * Returns the Element for this toolbar.
28176 * @return {Roo.Element}
28178 getEl : function(){
28184 * @return {Roo.Toolbar.Item} The separator item
28186 addSeparator : function(){
28187 return this.addItem(new Roo.Toolbar.Separator());
28191 * Adds a spacer element
28192 * @return {Roo.Toolbar.Spacer} The spacer item
28194 addSpacer : function(){
28195 return this.addItem(new Roo.Toolbar.Spacer());
28199 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28200 * @return {Roo.Toolbar.Fill} The fill item
28202 addFill : function(){
28203 return this.addItem(new Roo.Toolbar.Fill());
28207 * Adds any standard HTML element to the toolbar
28208 * @param {String/HTMLElement/Element} el The element or id of the element to add
28209 * @return {Roo.Toolbar.Item} The element's item
28211 addElement : function(el){
28212 return this.addItem(new Roo.Toolbar.Item(el));
28215 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28216 * @type Roo.util.MixedCollection
28221 * Adds any Toolbar.Item or subclass
28222 * @param {Roo.Toolbar.Item} item
28223 * @return {Roo.Toolbar.Item} The item
28225 addItem : function(item){
28226 var td = this.nextBlock();
28228 this.items.add(item);
28233 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28234 * @param {Object/Array} config A button config or array of configs
28235 * @return {Roo.Toolbar.Button/Array}
28237 addButton : function(config){
28238 if(config instanceof Array){
28240 for(var i = 0, len = config.length; i < len; i++) {
28241 buttons.push(this.addButton(config[i]));
28246 if(!(config instanceof Roo.Toolbar.Button)){
28248 new Roo.Toolbar.SplitButton(config) :
28249 new Roo.Toolbar.Button(config);
28251 var td = this.nextBlock();
28258 * Adds text to the toolbar
28259 * @param {String} text The text to add
28260 * @return {Roo.Toolbar.Item} The element's item
28262 addText : function(text){
28263 return this.addItem(new Roo.Toolbar.TextItem(text));
28267 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28268 * @param {Number} index The index where the item is to be inserted
28269 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28270 * @return {Roo.Toolbar.Button/Item}
28272 insertButton : function(index, item){
28273 if(item instanceof Array){
28275 for(var i = 0, len = item.length; i < len; i++) {
28276 buttons.push(this.insertButton(index + i, item[i]));
28280 if (!(item instanceof Roo.Toolbar.Button)){
28281 item = new Roo.Toolbar.Button(item);
28283 var td = document.createElement("td");
28284 this.tr.insertBefore(td, this.tr.childNodes[index]);
28286 this.items.insert(index, item);
28291 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28292 * @param {Object} config
28293 * @return {Roo.Toolbar.Item} The element's item
28295 addDom : function(config, returnEl){
28296 var td = this.nextBlock();
28297 Roo.DomHelper.overwrite(td, config);
28298 var ti = new Roo.Toolbar.Item(td.firstChild);
28300 this.items.add(ti);
28305 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28306 * @type Roo.util.MixedCollection
28311 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28312 * Note: the field should not have been rendered yet. For a field that has already been
28313 * rendered, use {@link #addElement}.
28314 * @param {Roo.form.Field} field
28315 * @return {Roo.ToolbarItem}
28319 addField : function(field) {
28320 if (!this.fields) {
28322 this.fields = new Roo.util.MixedCollection(false, function(o){
28323 return o.id || ("item" + (++autoId));
28328 var td = this.nextBlock();
28330 var ti = new Roo.Toolbar.Item(td.firstChild);
28332 this.items.add(ti);
28333 this.fields.add(field);
28344 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28345 this.el.child('div').hide();
28353 this.el.child('div').show();
28357 nextBlock : function(){
28358 var td = document.createElement("td");
28359 this.tr.appendChild(td);
28364 destroy : function(){
28365 if(this.items){ // rendered?
28366 Roo.destroy.apply(Roo, this.items.items);
28368 if(this.fields){ // rendered?
28369 Roo.destroy.apply(Roo, this.fields.items);
28371 Roo.Element.uncache(this.el, this.tr);
28376 * @class Roo.Toolbar.Item
28377 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28379 * Creates a new Item
28380 * @param {HTMLElement} el
28382 Roo.Toolbar.Item = function(el){
28383 this.el = Roo.getDom(el);
28384 this.id = Roo.id(this.el);
28385 this.hidden = false;
28388 Roo.Toolbar.Item.prototype = {
28391 * Get this item's HTML Element
28392 * @return {HTMLElement}
28394 getEl : function(){
28399 render : function(td){
28401 td.appendChild(this.el);
28405 * Removes and destroys this item.
28407 destroy : function(){
28408 this.td.parentNode.removeChild(this.td);
28415 this.hidden = false;
28416 this.td.style.display = "";
28423 this.hidden = true;
28424 this.td.style.display = "none";
28428 * Convenience function for boolean show/hide.
28429 * @param {Boolean} visible true to show/false to hide
28431 setVisible: function(visible){
28440 * Try to focus this item.
28442 focus : function(){
28443 Roo.fly(this.el).focus();
28447 * Disables this item.
28449 disable : function(){
28450 Roo.fly(this.td).addClass("x-item-disabled");
28451 this.disabled = true;
28452 this.el.disabled = true;
28456 * Enables this item.
28458 enable : function(){
28459 Roo.fly(this.td).removeClass("x-item-disabled");
28460 this.disabled = false;
28461 this.el.disabled = false;
28467 * @class Roo.Toolbar.Separator
28468 * @extends Roo.Toolbar.Item
28469 * A simple toolbar separator class
28471 * Creates a new Separator
28473 Roo.Toolbar.Separator = function(){
28474 var s = document.createElement("span");
28475 s.className = "ytb-sep";
28476 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28478 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28479 enable:Roo.emptyFn,
28480 disable:Roo.emptyFn,
28485 * @class Roo.Toolbar.Spacer
28486 * @extends Roo.Toolbar.Item
28487 * A simple element that adds extra horizontal space to a toolbar.
28489 * Creates a new Spacer
28491 Roo.Toolbar.Spacer = function(){
28492 var s = document.createElement("div");
28493 s.className = "ytb-spacer";
28494 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28496 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28497 enable:Roo.emptyFn,
28498 disable:Roo.emptyFn,
28503 * @class Roo.Toolbar.Fill
28504 * @extends Roo.Toolbar.Spacer
28505 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28507 * Creates a new Spacer
28509 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28511 render : function(td){
28512 td.style.width = '100%';
28513 Roo.Toolbar.Fill.superclass.render.call(this, td);
28518 * @class Roo.Toolbar.TextItem
28519 * @extends Roo.Toolbar.Item
28520 * A simple class that renders text directly into a toolbar.
28522 * Creates a new TextItem
28523 * @param {String} text
28525 Roo.Toolbar.TextItem = function(text){
28526 if (typeof(text) == 'object') {
28529 var s = document.createElement("span");
28530 s.className = "ytb-text";
28531 s.innerHTML = text;
28532 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28534 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28535 enable:Roo.emptyFn,
28536 disable:Roo.emptyFn,
28541 * @class Roo.Toolbar.Button
28542 * @extends Roo.Button
28543 * A button that renders into a toolbar.
28545 * Creates a new Button
28546 * @param {Object} config A standard {@link Roo.Button} config object
28548 Roo.Toolbar.Button = function(config){
28549 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28551 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28552 render : function(td){
28554 Roo.Toolbar.Button.superclass.render.call(this, td);
28558 * Removes and destroys this button
28560 destroy : function(){
28561 Roo.Toolbar.Button.superclass.destroy.call(this);
28562 this.td.parentNode.removeChild(this.td);
28566 * Shows this button
28569 this.hidden = false;
28570 this.td.style.display = "";
28574 * Hides this button
28577 this.hidden = true;
28578 this.td.style.display = "none";
28582 * Disables this item
28584 disable : function(){
28585 Roo.fly(this.td).addClass("x-item-disabled");
28586 this.disabled = true;
28590 * Enables this item
28592 enable : function(){
28593 Roo.fly(this.td).removeClass("x-item-disabled");
28594 this.disabled = false;
28597 // backwards compat
28598 Roo.ToolbarButton = Roo.Toolbar.Button;
28601 * @class Roo.Toolbar.SplitButton
28602 * @extends Roo.SplitButton
28603 * A menu button that renders into a toolbar.
28605 * Creates a new SplitButton
28606 * @param {Object} config A standard {@link Roo.SplitButton} config object
28608 Roo.Toolbar.SplitButton = function(config){
28609 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28611 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28612 render : function(td){
28614 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28618 * Removes and destroys this button
28620 destroy : function(){
28621 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28622 this.td.parentNode.removeChild(this.td);
28626 * Shows this button
28629 this.hidden = false;
28630 this.td.style.display = "";
28634 * Hides this button
28637 this.hidden = true;
28638 this.td.style.display = "none";
28642 // backwards compat
28643 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28645 * Ext JS Library 1.1.1
28646 * Copyright(c) 2006-2007, Ext JS, LLC.
28648 * Originally Released Under LGPL - original licence link has changed is not relivant.
28651 * <script type="text/javascript">
28655 * @class Roo.PagingToolbar
28656 * @extends Roo.Toolbar
28657 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28659 * Create a new PagingToolbar
28660 * @param {Object} config The config object
28662 Roo.PagingToolbar = function(el, ds, config)
28664 // old args format still supported... - xtype is prefered..
28665 if (typeof(el) == 'object' && el.xtype) {
28666 // created from xtype...
28668 ds = el.dataSource;
28669 el = config.container;
28672 if (config.items) {
28673 items = config.items;
28677 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28680 this.renderButtons(this.el);
28683 // supprot items array.
28685 Roo.each(items, function(e) {
28686 this.add(Roo.factory(e));
28691 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28693 * @cfg {Roo.data.Store} dataSource
28694 * The underlying data store providing the paged data
28697 * @cfg {String/HTMLElement/Element} container
28698 * container The id or element that will contain the toolbar
28701 * @cfg {Boolean} displayInfo
28702 * True to display the displayMsg (defaults to false)
28705 * @cfg {Number} pageSize
28706 * The number of records to display per page (defaults to 20)
28710 * @cfg {String} displayMsg
28711 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28713 displayMsg : 'Displaying {0} - {1} of {2}',
28715 * @cfg {String} emptyMsg
28716 * The message to display when no records are found (defaults to "No data to display")
28718 emptyMsg : 'No data to display',
28720 * Customizable piece of the default paging text (defaults to "Page")
28723 beforePageText : "Page",
28725 * Customizable piece of the default paging text (defaults to "of %0")
28728 afterPageText : "of {0}",
28730 * Customizable piece of the default paging text (defaults to "First Page")
28733 firstText : "First Page",
28735 * Customizable piece of the default paging text (defaults to "Previous Page")
28738 prevText : "Previous Page",
28740 * Customizable piece of the default paging text (defaults to "Next Page")
28743 nextText : "Next Page",
28745 * Customizable piece of the default paging text (defaults to "Last Page")
28748 lastText : "Last Page",
28750 * Customizable piece of the default paging text (defaults to "Refresh")
28753 refreshText : "Refresh",
28756 renderButtons : function(el){
28757 Roo.PagingToolbar.superclass.render.call(this, el);
28758 this.first = this.addButton({
28759 tooltip: this.firstText,
28760 cls: "x-btn-icon x-grid-page-first",
28762 handler: this.onClick.createDelegate(this, ["first"])
28764 this.prev = this.addButton({
28765 tooltip: this.prevText,
28766 cls: "x-btn-icon x-grid-page-prev",
28768 handler: this.onClick.createDelegate(this, ["prev"])
28770 //this.addSeparator();
28771 this.add(this.beforePageText);
28772 this.field = Roo.get(this.addDom({
28777 cls: "x-grid-page-number"
28779 this.field.on("keydown", this.onPagingKeydown, this);
28780 this.field.on("focus", function(){this.dom.select();});
28781 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28782 this.field.setHeight(18);
28783 //this.addSeparator();
28784 this.next = this.addButton({
28785 tooltip: this.nextText,
28786 cls: "x-btn-icon x-grid-page-next",
28788 handler: this.onClick.createDelegate(this, ["next"])
28790 this.last = this.addButton({
28791 tooltip: this.lastText,
28792 cls: "x-btn-icon x-grid-page-last",
28794 handler: this.onClick.createDelegate(this, ["last"])
28796 //this.addSeparator();
28797 this.loading = this.addButton({
28798 tooltip: this.refreshText,
28799 cls: "x-btn-icon x-grid-loading",
28800 handler: this.onClick.createDelegate(this, ["refresh"])
28803 if(this.displayInfo){
28804 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28809 updateInfo : function(){
28810 if(this.displayEl){
28811 var count = this.ds.getCount();
28812 var msg = count == 0 ?
28816 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28818 this.displayEl.update(msg);
28823 onLoad : function(ds, r, o){
28824 this.cursor = o.params ? o.params.start : 0;
28825 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28827 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28828 this.field.dom.value = ap;
28829 this.first.setDisabled(ap == 1);
28830 this.prev.setDisabled(ap == 1);
28831 this.next.setDisabled(ap == ps);
28832 this.last.setDisabled(ap == ps);
28833 this.loading.enable();
28838 getPageData : function(){
28839 var total = this.ds.getTotalCount();
28842 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28843 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28848 onLoadError : function(){
28849 this.loading.enable();
28853 onPagingKeydown : function(e){
28854 var k = e.getKey();
28855 var d = this.getPageData();
28857 var v = this.field.dom.value, pageNum;
28858 if(!v || isNaN(pageNum = parseInt(v, 10))){
28859 this.field.dom.value = d.activePage;
28862 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28863 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28866 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))
28868 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28869 this.field.dom.value = pageNum;
28870 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28873 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28875 var v = this.field.dom.value, pageNum;
28876 var increment = (e.shiftKey) ? 10 : 1;
28877 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28879 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28880 this.field.dom.value = d.activePage;
28883 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28885 this.field.dom.value = parseInt(v, 10) + increment;
28886 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28887 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28894 beforeLoad : function(){
28896 this.loading.disable();
28901 onClick : function(which){
28905 ds.load({params:{start: 0, limit: this.pageSize}});
28908 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28911 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28914 var total = ds.getTotalCount();
28915 var extra = total % this.pageSize;
28916 var lastStart = extra ? (total - extra) : total-this.pageSize;
28917 ds.load({params:{start: lastStart, limit: this.pageSize}});
28920 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28926 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28927 * @param {Roo.data.Store} store The data store to unbind
28929 unbind : function(ds){
28930 ds.un("beforeload", this.beforeLoad, this);
28931 ds.un("load", this.onLoad, this);
28932 ds.un("loadexception", this.onLoadError, this);
28933 ds.un("remove", this.updateInfo, this);
28934 ds.un("add", this.updateInfo, this);
28935 this.ds = undefined;
28939 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28940 * @param {Roo.data.Store} store The data store to bind
28942 bind : function(ds){
28943 ds.on("beforeload", this.beforeLoad, this);
28944 ds.on("load", this.onLoad, this);
28945 ds.on("loadexception", this.onLoadError, this);
28946 ds.on("remove", this.updateInfo, this);
28947 ds.on("add", this.updateInfo, this);
28952 * Ext JS Library 1.1.1
28953 * Copyright(c) 2006-2007, Ext JS, LLC.
28955 * Originally Released Under LGPL - original licence link has changed is not relivant.
28958 * <script type="text/javascript">
28962 * @class Roo.Resizable
28963 * @extends Roo.util.Observable
28964 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28965 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28966 * 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
28967 * the element will be wrapped for you automatically.</p>
28968 * <p>Here is the list of valid resize handles:</p>
28971 ------ -------------------
28980 'hd' horizontal drag
28983 * <p>Here's an example showing the creation of a typical Resizable:</p>
28985 var resizer = new Roo.Resizable("element-id", {
28993 resizer.on("resize", myHandler);
28995 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28996 * resizer.east.setDisplayed(false);</p>
28997 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28998 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28999 * resize operation's new size (defaults to [0, 0])
29000 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29001 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29002 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29003 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29004 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29005 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29006 * @cfg {Number} width The width of the element in pixels (defaults to null)
29007 * @cfg {Number} height The height of the element in pixels (defaults to null)
29008 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29009 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29010 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29011 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29012 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29013 * in favor of the handles config option (defaults to false)
29014 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29015 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29016 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29017 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29018 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29019 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29020 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29021 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29022 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29023 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29024 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29026 * Create a new resizable component
29027 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29028 * @param {Object} config configuration options
29030 Roo.Resizable = function(el, config)
29032 this.el = Roo.get(el);
29034 if(config && config.wrap){
29035 config.resizeChild = this.el;
29036 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29037 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29038 this.el.setStyle("overflow", "hidden");
29039 this.el.setPositioning(config.resizeChild.getPositioning());
29040 config.resizeChild.clearPositioning();
29041 if(!config.width || !config.height){
29042 var csize = config.resizeChild.getSize();
29043 this.el.setSize(csize.width, csize.height);
29045 if(config.pinned && !config.adjustments){
29046 config.adjustments = "auto";
29050 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29051 this.proxy.unselectable();
29052 this.proxy.enableDisplayMode('block');
29054 Roo.apply(this, config);
29057 this.disableTrackOver = true;
29058 this.el.addClass("x-resizable-pinned");
29060 // if the element isn't positioned, make it relative
29061 var position = this.el.getStyle("position");
29062 if(position != "absolute" && position != "fixed"){
29063 this.el.setStyle("position", "relative");
29065 if(!this.handles){ // no handles passed, must be legacy style
29066 this.handles = 's,e,se';
29067 if(this.multiDirectional){
29068 this.handles += ',n,w';
29071 if(this.handles == "all"){
29072 this.handles = "n s e w ne nw se sw";
29074 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29075 var ps = Roo.Resizable.positions;
29076 for(var i = 0, len = hs.length; i < len; i++){
29077 if(hs[i] && ps[hs[i]]){
29078 var pos = ps[hs[i]];
29079 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29083 this.corner = this.southeast;
29085 // updateBox = the box can move..
29086 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29087 this.updateBox = true;
29090 this.activeHandle = null;
29092 if(this.resizeChild){
29093 if(typeof this.resizeChild == "boolean"){
29094 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29096 this.resizeChild = Roo.get(this.resizeChild, true);
29100 if(this.adjustments == "auto"){
29101 var rc = this.resizeChild;
29102 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29103 if(rc && (hw || hn)){
29104 rc.position("relative");
29105 rc.setLeft(hw ? hw.el.getWidth() : 0);
29106 rc.setTop(hn ? hn.el.getHeight() : 0);
29108 this.adjustments = [
29109 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29110 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29114 if(this.draggable){
29115 this.dd = this.dynamic ?
29116 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29117 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29123 * @event beforeresize
29124 * Fired before resize is allowed. Set enabled to false to cancel resize.
29125 * @param {Roo.Resizable} this
29126 * @param {Roo.EventObject} e The mousedown event
29128 "beforeresize" : true,
29131 * Fired a resizing.
29132 * @param {Roo.Resizable} this
29133 * @param {Number} x The new x position
29134 * @param {Number} y The new y position
29135 * @param {Number} w The new w width
29136 * @param {Number} h The new h hight
29137 * @param {Roo.EventObject} e The mouseup event
29142 * Fired after a resize.
29143 * @param {Roo.Resizable} this
29144 * @param {Number} width The new width
29145 * @param {Number} height The new height
29146 * @param {Roo.EventObject} e The mouseup event
29151 if(this.width !== null && this.height !== null){
29152 this.resizeTo(this.width, this.height);
29154 this.updateChildSize();
29157 this.el.dom.style.zoom = 1;
29159 Roo.Resizable.superclass.constructor.call(this);
29162 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29163 resizeChild : false,
29164 adjustments : [0, 0],
29174 multiDirectional : false,
29175 disableTrackOver : false,
29176 easing : 'easeOutStrong',
29177 widthIncrement : 0,
29178 heightIncrement : 0,
29182 preserveRatio : false,
29183 transparent: false,
29189 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29191 constrainTo: undefined,
29193 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29195 resizeRegion: undefined,
29199 * Perform a manual resize
29200 * @param {Number} width
29201 * @param {Number} height
29203 resizeTo : function(width, height){
29204 this.el.setSize(width, height);
29205 this.updateChildSize();
29206 this.fireEvent("resize", this, width, height, null);
29210 startSizing : function(e, handle){
29211 this.fireEvent("beforeresize", this, e);
29212 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29215 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29216 this.overlay.unselectable();
29217 this.overlay.enableDisplayMode("block");
29218 this.overlay.on("mousemove", this.onMouseMove, this);
29219 this.overlay.on("mouseup", this.onMouseUp, this);
29221 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29223 this.resizing = true;
29224 this.startBox = this.el.getBox();
29225 this.startPoint = e.getXY();
29226 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29227 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29229 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29230 this.overlay.show();
29232 if(this.constrainTo) {
29233 var ct = Roo.get(this.constrainTo);
29234 this.resizeRegion = ct.getRegion().adjust(
29235 ct.getFrameWidth('t'),
29236 ct.getFrameWidth('l'),
29237 -ct.getFrameWidth('b'),
29238 -ct.getFrameWidth('r')
29242 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29244 this.proxy.setBox(this.startBox);
29246 this.proxy.setStyle('visibility', 'visible');
29252 onMouseDown : function(handle, e){
29255 this.activeHandle = handle;
29256 this.startSizing(e, handle);
29261 onMouseUp : function(e){
29262 var size = this.resizeElement();
29263 this.resizing = false;
29265 this.overlay.hide();
29267 this.fireEvent("resize", this, size.width, size.height, e);
29271 updateChildSize : function(){
29273 if(this.resizeChild){
29275 var child = this.resizeChild;
29276 var adj = this.adjustments;
29277 if(el.dom.offsetWidth){
29278 var b = el.getSize(true);
29279 child.setSize(b.width+adj[0], b.height+adj[1]);
29281 // Second call here for IE
29282 // The first call enables instant resizing and
29283 // the second call corrects scroll bars if they
29286 setTimeout(function(){
29287 if(el.dom.offsetWidth){
29288 var b = el.getSize(true);
29289 child.setSize(b.width+adj[0], b.height+adj[1]);
29297 snap : function(value, inc, min){
29298 if(!inc || !value) return value;
29299 var newValue = value;
29300 var m = value % inc;
29303 newValue = value + (inc-m);
29305 newValue = value - m;
29308 return Math.max(min, newValue);
29312 resizeElement : function(){
29313 var box = this.proxy.getBox();
29314 if(this.updateBox){
29315 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29317 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29319 this.updateChildSize();
29327 constrain : function(v, diff, m, mx){
29330 }else if(v - diff > mx){
29337 onMouseMove : function(e){
29340 try{// try catch so if something goes wrong the user doesn't get hung
29342 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29346 //var curXY = this.startPoint;
29347 var curSize = this.curSize || this.startBox;
29348 var x = this.startBox.x, y = this.startBox.y;
29349 var ox = x, oy = y;
29350 var w = curSize.width, h = curSize.height;
29351 var ow = w, oh = h;
29352 var mw = this.minWidth, mh = this.minHeight;
29353 var mxw = this.maxWidth, mxh = this.maxHeight;
29354 var wi = this.widthIncrement;
29355 var hi = this.heightIncrement;
29357 var eventXY = e.getXY();
29358 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29359 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29361 var pos = this.activeHandle.position;
29366 w = Math.min(Math.max(mw, w), mxw);
29371 h = Math.min(Math.max(mh, h), mxh);
29376 w = Math.min(Math.max(mw, w), mxw);
29377 h = Math.min(Math.max(mh, h), mxh);
29380 diffY = this.constrain(h, diffY, mh, mxh);
29387 var adiffX = Math.abs(diffX);
29388 var sub = (adiffX % wi); // how much
29389 if (sub > (wi/2)) { // far enough to snap
29390 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29392 // remove difference..
29393 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29397 x = Math.max(this.minX, x);
29400 diffX = this.constrain(w, diffX, mw, mxw);
29406 w = Math.min(Math.max(mw, w), mxw);
29407 diffY = this.constrain(h, diffY, mh, mxh);
29412 diffX = this.constrain(w, diffX, mw, mxw);
29413 diffY = this.constrain(h, diffY, mh, mxh);
29420 diffX = this.constrain(w, diffX, mw, mxw);
29422 h = Math.min(Math.max(mh, h), mxh);
29428 var sw = this.snap(w, wi, mw);
29429 var sh = this.snap(h, hi, mh);
29430 if(sw != w || sh != h){
29453 if(this.preserveRatio){
29458 h = Math.min(Math.max(mh, h), mxh);
29463 w = Math.min(Math.max(mw, w), mxw);
29468 w = Math.min(Math.max(mw, w), mxw);
29474 w = Math.min(Math.max(mw, w), mxw);
29480 h = Math.min(Math.max(mh, h), mxh);
29488 h = Math.min(Math.max(mh, h), mxh);
29498 h = Math.min(Math.max(mh, h), mxh);
29506 if (pos == 'hdrag') {
29509 this.proxy.setBounds(x, y, w, h);
29511 this.resizeElement();
29515 this.fireEvent("resizing", this, x, y, w, h, e);
29519 handleOver : function(){
29521 this.el.addClass("x-resizable-over");
29526 handleOut : function(){
29527 if(!this.resizing){
29528 this.el.removeClass("x-resizable-over");
29533 * Returns the element this component is bound to.
29534 * @return {Roo.Element}
29536 getEl : function(){
29541 * Returns the resizeChild element (or null).
29542 * @return {Roo.Element}
29544 getResizeChild : function(){
29545 return this.resizeChild;
29547 groupHandler : function()
29552 * Destroys this resizable. If the element was wrapped and
29553 * removeEl is not true then the element remains.
29554 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29556 destroy : function(removeEl){
29557 this.proxy.remove();
29559 this.overlay.removeAllListeners();
29560 this.overlay.remove();
29562 var ps = Roo.Resizable.positions;
29564 if(typeof ps[k] != "function" && this[ps[k]]){
29565 var h = this[ps[k]];
29566 h.el.removeAllListeners();
29571 this.el.update("");
29578 // hash to map config positions to true positions
29579 Roo.Resizable.positions = {
29580 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29585 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29587 // only initialize the template if resizable is used
29588 var tpl = Roo.DomHelper.createTemplate(
29589 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29592 Roo.Resizable.Handle.prototype.tpl = tpl;
29594 this.position = pos;
29596 // show north drag fro topdra
29597 var handlepos = pos == 'hdrag' ? 'north' : pos;
29599 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29600 if (pos == 'hdrag') {
29601 this.el.setStyle('cursor', 'pointer');
29603 this.el.unselectable();
29605 this.el.setOpacity(0);
29607 this.el.on("mousedown", this.onMouseDown, this);
29608 if(!disableTrackOver){
29609 this.el.on("mouseover", this.onMouseOver, this);
29610 this.el.on("mouseout", this.onMouseOut, this);
29615 Roo.Resizable.Handle.prototype = {
29616 afterResize : function(rz){
29621 onMouseDown : function(e){
29622 this.rz.onMouseDown(this, e);
29625 onMouseOver : function(e){
29626 this.rz.handleOver(this, e);
29629 onMouseOut : function(e){
29630 this.rz.handleOut(this, e);
29634 * Ext JS Library 1.1.1
29635 * Copyright(c) 2006-2007, Ext JS, LLC.
29637 * Originally Released Under LGPL - original licence link has changed is not relivant.
29640 * <script type="text/javascript">
29644 * @class Roo.Editor
29645 * @extends Roo.Component
29646 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29648 * Create a new Editor
29649 * @param {Roo.form.Field} field The Field object (or descendant)
29650 * @param {Object} config The config object
29652 Roo.Editor = function(field, config){
29653 Roo.Editor.superclass.constructor.call(this, config);
29654 this.field = field;
29657 * @event beforestartedit
29658 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29659 * false from the handler of this event.
29660 * @param {Editor} this
29661 * @param {Roo.Element} boundEl The underlying element bound to this editor
29662 * @param {Mixed} value The field value being set
29664 "beforestartedit" : true,
29667 * Fires when this editor is displayed
29668 * @param {Roo.Element} boundEl The underlying element bound to this editor
29669 * @param {Mixed} value The starting field value
29671 "startedit" : true,
29673 * @event beforecomplete
29674 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29675 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29676 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29677 * event will not fire since no edit actually occurred.
29678 * @param {Editor} this
29679 * @param {Mixed} value The current field value
29680 * @param {Mixed} startValue The original field value
29682 "beforecomplete" : true,
29685 * Fires after editing is complete and any changed value has been written to the underlying field.
29686 * @param {Editor} this
29687 * @param {Mixed} value The current field value
29688 * @param {Mixed} startValue The original field value
29692 * @event specialkey
29693 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29694 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29695 * @param {Roo.form.Field} this
29696 * @param {Roo.EventObject} e The event object
29698 "specialkey" : true
29702 Roo.extend(Roo.Editor, Roo.Component, {
29704 * @cfg {Boolean/String} autosize
29705 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29706 * or "height" to adopt the height only (defaults to false)
29709 * @cfg {Boolean} revertInvalid
29710 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29711 * validation fails (defaults to true)
29714 * @cfg {Boolean} ignoreNoChange
29715 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29716 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29717 * will never be ignored.
29720 * @cfg {Boolean} hideEl
29721 * False to keep the bound element visible while the editor is displayed (defaults to true)
29724 * @cfg {Mixed} value
29725 * The data value of the underlying field (defaults to "")
29729 * @cfg {String} alignment
29730 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29734 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29735 * for bottom-right shadow (defaults to "frame")
29739 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29743 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29745 completeOnEnter : false,
29747 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29749 cancelOnEsc : false,
29751 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29756 onRender : function(ct, position){
29757 this.el = new Roo.Layer({
29758 shadow: this.shadow,
29764 constrain: this.constrain
29766 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29767 if(this.field.msgTarget != 'title'){
29768 this.field.msgTarget = 'qtip';
29770 this.field.render(this.el);
29772 this.field.el.dom.setAttribute('autocomplete', 'off');
29774 this.field.on("specialkey", this.onSpecialKey, this);
29775 if(this.swallowKeys){
29776 this.field.el.swallowEvent(['keydown','keypress']);
29779 this.field.on("blur", this.onBlur, this);
29780 if(this.field.grow){
29781 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29785 onSpecialKey : function(field, e)
29787 //Roo.log('editor onSpecialKey');
29788 if(this.completeOnEnter && e.getKey() == e.ENTER){
29790 this.completeEdit();
29793 // do not fire special key otherwise it might hide close the editor...
29794 if(e.getKey() == e.ENTER){
29797 if(this.cancelOnEsc && e.getKey() == e.ESC){
29801 this.fireEvent('specialkey', field, e);
29806 * Starts the editing process and shows the editor.
29807 * @param {String/HTMLElement/Element} el The element to edit
29808 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29809 * to the innerHTML of el.
29811 startEdit : function(el, value){
29813 this.completeEdit();
29815 this.boundEl = Roo.get(el);
29816 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29817 if(!this.rendered){
29818 this.render(this.parentEl || document.body);
29820 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29823 this.startValue = v;
29824 this.field.setValue(v);
29826 var sz = this.boundEl.getSize();
29827 switch(this.autoSize){
29829 this.setSize(sz.width, "");
29832 this.setSize("", sz.height);
29835 this.setSize(sz.width, sz.height);
29838 this.el.alignTo(this.boundEl, this.alignment);
29839 this.editing = true;
29841 Roo.QuickTips.disable();
29847 * Sets the height and width of this editor.
29848 * @param {Number} width The new width
29849 * @param {Number} height The new height
29851 setSize : function(w, h){
29852 this.field.setSize(w, h);
29859 * Realigns the editor to the bound field based on the current alignment config value.
29861 realign : function(){
29862 this.el.alignTo(this.boundEl, this.alignment);
29866 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29867 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29869 completeEdit : function(remainVisible){
29873 var v = this.getValue();
29874 if(this.revertInvalid !== false && !this.field.isValid()){
29875 v = this.startValue;
29876 this.cancelEdit(true);
29878 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29879 this.editing = false;
29883 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29884 this.editing = false;
29885 if(this.updateEl && this.boundEl){
29886 this.boundEl.update(v);
29888 if(remainVisible !== true){
29891 this.fireEvent("complete", this, v, this.startValue);
29896 onShow : function(){
29898 if(this.hideEl !== false){
29899 this.boundEl.hide();
29902 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29903 this.fixIEFocus = true;
29904 this.deferredFocus.defer(50, this);
29906 this.field.focus();
29908 this.fireEvent("startedit", this.boundEl, this.startValue);
29911 deferredFocus : function(){
29913 this.field.focus();
29918 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29919 * reverted to the original starting value.
29920 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29921 * cancel (defaults to false)
29923 cancelEdit : function(remainVisible){
29925 this.setValue(this.startValue);
29926 if(remainVisible !== true){
29933 onBlur : function(){
29934 if(this.allowBlur !== true && this.editing){
29935 this.completeEdit();
29940 onHide : function(){
29942 this.completeEdit();
29946 if(this.field.collapse){
29947 this.field.collapse();
29950 if(this.hideEl !== false){
29951 this.boundEl.show();
29954 Roo.QuickTips.enable();
29959 * Sets the data value of the editor
29960 * @param {Mixed} value Any valid value supported by the underlying field
29962 setValue : function(v){
29963 this.field.setValue(v);
29967 * Gets the data value of the editor
29968 * @return {Mixed} The data value
29970 getValue : function(){
29971 return this.field.getValue();
29975 * Ext JS Library 1.1.1
29976 * Copyright(c) 2006-2007, Ext JS, LLC.
29978 * Originally Released Under LGPL - original licence link has changed is not relivant.
29981 * <script type="text/javascript">
29985 * @class Roo.BasicDialog
29986 * @extends Roo.util.Observable
29987 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29989 var dlg = new Roo.BasicDialog("my-dlg", {
29998 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29999 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30000 dlg.addButton('Cancel', dlg.hide, dlg);
30003 <b>A Dialog should always be a direct child of the body element.</b>
30004 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30005 * @cfg {String} title Default text to display in the title bar (defaults to null)
30006 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30007 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30008 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30009 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30010 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30011 * (defaults to null with no animation)
30012 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30013 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30014 * property for valid values (defaults to 'all')
30015 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30016 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30017 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30018 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30019 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30020 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30021 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30022 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30023 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30024 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30025 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30026 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30027 * draggable = true (defaults to false)
30028 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30029 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30030 * shadow (defaults to false)
30031 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30032 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30033 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30034 * @cfg {Array} buttons Array of buttons
30035 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30037 * Create a new BasicDialog.
30038 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30039 * @param {Object} config Configuration options
30041 Roo.BasicDialog = function(el, config){
30042 this.el = Roo.get(el);
30043 var dh = Roo.DomHelper;
30044 if(!this.el && config && config.autoCreate){
30045 if(typeof config.autoCreate == "object"){
30046 if(!config.autoCreate.id){
30047 config.autoCreate.id = el;
30049 this.el = dh.append(document.body,
30050 config.autoCreate, true);
30052 this.el = dh.append(document.body,
30053 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30057 el.setDisplayed(true);
30058 el.hide = this.hideAction;
30060 el.addClass("x-dlg");
30062 Roo.apply(this, config);
30064 this.proxy = el.createProxy("x-dlg-proxy");
30065 this.proxy.hide = this.hideAction;
30066 this.proxy.setOpacity(.5);
30070 el.setWidth(config.width);
30073 el.setHeight(config.height);
30075 this.size = el.getSize();
30076 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30077 this.xy = [config.x,config.y];
30079 this.xy = el.getCenterXY(true);
30081 /** The header element @type Roo.Element */
30082 this.header = el.child("> .x-dlg-hd");
30083 /** The body element @type Roo.Element */
30084 this.body = el.child("> .x-dlg-bd");
30085 /** The footer element @type Roo.Element */
30086 this.footer = el.child("> .x-dlg-ft");
30089 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30092 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30095 this.header.unselectable();
30097 this.header.update(this.title);
30099 // this element allows the dialog to be focused for keyboard event
30100 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30101 this.focusEl.swallowEvent("click", true);
30103 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30105 // wrap the body and footer for special rendering
30106 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30108 this.bwrap.dom.appendChild(this.footer.dom);
30111 this.bg = this.el.createChild({
30112 tag: "div", cls:"x-dlg-bg",
30113 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30115 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30118 if(this.autoScroll !== false && !this.autoTabs){
30119 this.body.setStyle("overflow", "auto");
30122 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30124 if(this.closable !== false){
30125 this.el.addClass("x-dlg-closable");
30126 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30127 this.close.on("click", this.closeClick, this);
30128 this.close.addClassOnOver("x-dlg-close-over");
30130 if(this.collapsible !== false){
30131 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30132 this.collapseBtn.on("click", this.collapseClick, this);
30133 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30134 this.header.on("dblclick", this.collapseClick, this);
30136 if(this.resizable !== false){
30137 this.el.addClass("x-dlg-resizable");
30138 this.resizer = new Roo.Resizable(el, {
30139 minWidth: this.minWidth || 80,
30140 minHeight:this.minHeight || 80,
30141 handles: this.resizeHandles || "all",
30144 this.resizer.on("beforeresize", this.beforeResize, this);
30145 this.resizer.on("resize", this.onResize, this);
30147 if(this.draggable !== false){
30148 el.addClass("x-dlg-draggable");
30149 if (!this.proxyDrag) {
30150 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30153 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30155 dd.setHandleElId(this.header.id);
30156 dd.endDrag = this.endMove.createDelegate(this);
30157 dd.startDrag = this.startMove.createDelegate(this);
30158 dd.onDrag = this.onDrag.createDelegate(this);
30163 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30164 this.mask.enableDisplayMode("block");
30166 this.el.addClass("x-dlg-modal");
30169 this.shadow = new Roo.Shadow({
30170 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30171 offset : this.shadowOffset
30174 this.shadowOffset = 0;
30176 if(Roo.useShims && this.shim !== false){
30177 this.shim = this.el.createShim();
30178 this.shim.hide = this.hideAction;
30186 if (this.buttons) {
30187 var bts= this.buttons;
30189 Roo.each(bts, function(b) {
30198 * Fires when a key is pressed
30199 * @param {Roo.BasicDialog} this
30200 * @param {Roo.EventObject} e
30205 * Fires when this dialog is moved by the user.
30206 * @param {Roo.BasicDialog} this
30207 * @param {Number} x The new page X
30208 * @param {Number} y The new page Y
30213 * Fires when this dialog is resized by the user.
30214 * @param {Roo.BasicDialog} this
30215 * @param {Number} width The new width
30216 * @param {Number} height The new height
30220 * @event beforehide
30221 * Fires before this dialog is hidden.
30222 * @param {Roo.BasicDialog} this
30224 "beforehide" : true,
30227 * Fires when this dialog is hidden.
30228 * @param {Roo.BasicDialog} this
30232 * @event beforeshow
30233 * Fires before this dialog is shown.
30234 * @param {Roo.BasicDialog} this
30236 "beforeshow" : true,
30239 * Fires when this dialog is shown.
30240 * @param {Roo.BasicDialog} this
30244 el.on("keydown", this.onKeyDown, this);
30245 el.on("mousedown", this.toFront, this);
30246 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30248 Roo.DialogManager.register(this);
30249 Roo.BasicDialog.superclass.constructor.call(this);
30252 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30253 shadowOffset: Roo.isIE ? 6 : 5,
30256 minButtonWidth: 75,
30257 defaultButton: null,
30258 buttonAlign: "right",
30263 * Sets the dialog title text
30264 * @param {String} text The title text to display
30265 * @return {Roo.BasicDialog} this
30267 setTitle : function(text){
30268 this.header.update(text);
30273 closeClick : function(){
30278 collapseClick : function(){
30279 this[this.collapsed ? "expand" : "collapse"]();
30283 * Collapses the dialog to its minimized state (only the title bar is visible).
30284 * Equivalent to the user clicking the collapse dialog button.
30286 collapse : function(){
30287 if(!this.collapsed){
30288 this.collapsed = true;
30289 this.el.addClass("x-dlg-collapsed");
30290 this.restoreHeight = this.el.getHeight();
30291 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30296 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30297 * clicking the expand dialog button.
30299 expand : function(){
30300 if(this.collapsed){
30301 this.collapsed = false;
30302 this.el.removeClass("x-dlg-collapsed");
30303 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30308 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30309 * @return {Roo.TabPanel} The tabs component
30311 initTabs : function(){
30312 var tabs = this.getTabs();
30313 while(tabs.getTab(0)){
30316 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30318 tabs.addTab(Roo.id(dom), dom.title);
30326 beforeResize : function(){
30327 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30331 onResize : function(){
30332 this.refreshSize();
30333 this.syncBodyHeight();
30334 this.adjustAssets();
30336 this.fireEvent("resize", this, this.size.width, this.size.height);
30340 onKeyDown : function(e){
30341 if(this.isVisible()){
30342 this.fireEvent("keydown", this, e);
30347 * Resizes the dialog.
30348 * @param {Number} width
30349 * @param {Number} height
30350 * @return {Roo.BasicDialog} this
30352 resizeTo : function(width, height){
30353 this.el.setSize(width, height);
30354 this.size = {width: width, height: height};
30355 this.syncBodyHeight();
30356 if(this.fixedcenter){
30359 if(this.isVisible()){
30360 this.constrainXY();
30361 this.adjustAssets();
30363 this.fireEvent("resize", this, width, height);
30369 * Resizes the dialog to fit the specified content size.
30370 * @param {Number} width
30371 * @param {Number} height
30372 * @return {Roo.BasicDialog} this
30374 setContentSize : function(w, h){
30375 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30376 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30377 //if(!this.el.isBorderBox()){
30378 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30379 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30382 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30383 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30385 this.resizeTo(w, h);
30390 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30391 * executed in response to a particular key being pressed while the dialog is active.
30392 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30393 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30394 * @param {Function} fn The function to call
30395 * @param {Object} scope (optional) The scope of the function
30396 * @return {Roo.BasicDialog} this
30398 addKeyListener : function(key, fn, scope){
30399 var keyCode, shift, ctrl, alt;
30400 if(typeof key == "object" && !(key instanceof Array)){
30401 keyCode = key["key"];
30402 shift = key["shift"];
30403 ctrl = key["ctrl"];
30408 var handler = function(dlg, e){
30409 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30410 var k = e.getKey();
30411 if(keyCode instanceof Array){
30412 for(var i = 0, len = keyCode.length; i < len; i++){
30413 if(keyCode[i] == k){
30414 fn.call(scope || window, dlg, k, e);
30420 fn.call(scope || window, dlg, k, e);
30425 this.on("keydown", handler);
30430 * Returns the TabPanel component (creates it if it doesn't exist).
30431 * Note: If you wish to simply check for the existence of tabs without creating them,
30432 * check for a null 'tabs' property.
30433 * @return {Roo.TabPanel} The tabs component
30435 getTabs : function(){
30437 this.el.addClass("x-dlg-auto-tabs");
30438 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30439 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30445 * Adds a button to the footer section of the dialog.
30446 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30447 * object or a valid Roo.DomHelper element config
30448 * @param {Function} handler The function called when the button is clicked
30449 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30450 * @return {Roo.Button} The new button
30452 addButton : function(config, handler, scope){
30453 var dh = Roo.DomHelper;
30455 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30457 if(!this.btnContainer){
30458 var tb = this.footer.createChild({
30460 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30461 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30463 this.btnContainer = tb.firstChild.firstChild.firstChild;
30468 minWidth: this.minButtonWidth,
30471 if(typeof config == "string"){
30472 bconfig.text = config;
30475 bconfig.dhconfig = config;
30477 Roo.apply(bconfig, config);
30481 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30482 bconfig.position = Math.max(0, bconfig.position);
30483 fc = this.btnContainer.childNodes[bconfig.position];
30486 var btn = new Roo.Button(
30488 this.btnContainer.insertBefore(document.createElement("td"),fc)
30489 : this.btnContainer.appendChild(document.createElement("td")),
30490 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30493 this.syncBodyHeight();
30496 * Array of all the buttons that have been added to this dialog via addButton
30501 this.buttons.push(btn);
30506 * Sets the default button to be focused when the dialog is displayed.
30507 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30508 * @return {Roo.BasicDialog} this
30510 setDefaultButton : function(btn){
30511 this.defaultButton = btn;
30516 getHeaderFooterHeight : function(safe){
30519 height += this.header.getHeight();
30522 var fm = this.footer.getMargins();
30523 height += (this.footer.getHeight()+fm.top+fm.bottom);
30525 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30526 height += this.centerBg.getPadding("tb");
30531 syncBodyHeight : function()
30533 var bd = this.body, // the text
30534 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30536 var height = this.size.height - this.getHeaderFooterHeight(false);
30537 bd.setHeight(height-bd.getMargins("tb"));
30538 var hh = this.header.getHeight();
30539 var h = this.size.height-hh;
30542 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30543 bw.setHeight(h-cb.getPadding("tb"));
30545 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30546 bd.setWidth(bw.getWidth(true));
30548 this.tabs.syncHeight();
30550 this.tabs.el.repaint();
30556 * Restores the previous state of the dialog if Roo.state is configured.
30557 * @return {Roo.BasicDialog} this
30559 restoreState : function(){
30560 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30561 if(box && box.width){
30562 this.xy = [box.x, box.y];
30563 this.resizeTo(box.width, box.height);
30569 beforeShow : function(){
30571 if(this.fixedcenter){
30572 this.xy = this.el.getCenterXY(true);
30575 Roo.get(document.body).addClass("x-body-masked");
30576 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30579 this.constrainXY();
30583 animShow : function(){
30584 var b = Roo.get(this.animateTarget).getBox();
30585 this.proxy.setSize(b.width, b.height);
30586 this.proxy.setLocation(b.x, b.y);
30588 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30589 true, .35, this.showEl.createDelegate(this));
30593 * Shows the dialog.
30594 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30595 * @return {Roo.BasicDialog} this
30597 show : function(animateTarget){
30598 if (this.fireEvent("beforeshow", this) === false){
30601 if(this.syncHeightBeforeShow){
30602 this.syncBodyHeight();
30603 }else if(this.firstShow){
30604 this.firstShow = false;
30605 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30607 this.animateTarget = animateTarget || this.animateTarget;
30608 if(!this.el.isVisible()){
30610 if(this.animateTarget && Roo.get(this.animateTarget)){
30620 showEl : function(){
30622 this.el.setXY(this.xy);
30624 this.adjustAssets(true);
30627 // IE peekaboo bug - fix found by Dave Fenwick
30631 this.fireEvent("show", this);
30635 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30636 * dialog itself will receive focus.
30638 focus : function(){
30639 if(this.defaultButton){
30640 this.defaultButton.focus();
30642 this.focusEl.focus();
30647 constrainXY : function(){
30648 if(this.constraintoviewport !== false){
30649 if(!this.viewSize){
30650 if(this.container){
30651 var s = this.container.getSize();
30652 this.viewSize = [s.width, s.height];
30654 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30657 var s = Roo.get(this.container||document).getScroll();
30659 var x = this.xy[0], y = this.xy[1];
30660 var w = this.size.width, h = this.size.height;
30661 var vw = this.viewSize[0], vh = this.viewSize[1];
30662 // only move it if it needs it
30664 // first validate right/bottom
30665 if(x + w > vw+s.left){
30669 if(y + h > vh+s.top){
30673 // then make sure top/left isn't negative
30685 if(this.isVisible()){
30686 this.el.setLocation(x, y);
30687 this.adjustAssets();
30694 onDrag : function(){
30695 if(!this.proxyDrag){
30696 this.xy = this.el.getXY();
30697 this.adjustAssets();
30702 adjustAssets : function(doShow){
30703 var x = this.xy[0], y = this.xy[1];
30704 var w = this.size.width, h = this.size.height;
30705 if(doShow === true){
30707 this.shadow.show(this.el);
30713 if(this.shadow && this.shadow.isVisible()){
30714 this.shadow.show(this.el);
30716 if(this.shim && this.shim.isVisible()){
30717 this.shim.setBounds(x, y, w, h);
30722 adjustViewport : function(w, h){
30724 w = Roo.lib.Dom.getViewWidth();
30725 h = Roo.lib.Dom.getViewHeight();
30728 this.viewSize = [w, h];
30729 if(this.modal && this.mask.isVisible()){
30730 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30731 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30733 if(this.isVisible()){
30734 this.constrainXY();
30739 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30740 * shadow, proxy, mask, etc.) Also removes all event listeners.
30741 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30743 destroy : function(removeEl){
30744 if(this.isVisible()){
30745 this.animateTarget = null;
30748 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30750 this.tabs.destroy(removeEl);
30763 for(var i = 0, len = this.buttons.length; i < len; i++){
30764 this.buttons[i].destroy();
30767 this.el.removeAllListeners();
30768 if(removeEl === true){
30769 this.el.update("");
30772 Roo.DialogManager.unregister(this);
30776 startMove : function(){
30777 if(this.proxyDrag){
30780 if(this.constraintoviewport !== false){
30781 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30786 endMove : function(){
30787 if(!this.proxyDrag){
30788 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30790 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30793 this.refreshSize();
30794 this.adjustAssets();
30796 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30800 * Brings this dialog to the front of any other visible dialogs
30801 * @return {Roo.BasicDialog} this
30803 toFront : function(){
30804 Roo.DialogManager.bringToFront(this);
30809 * Sends this dialog to the back (under) of any other visible dialogs
30810 * @return {Roo.BasicDialog} this
30812 toBack : function(){
30813 Roo.DialogManager.sendToBack(this);
30818 * Centers this dialog in the viewport
30819 * @return {Roo.BasicDialog} this
30821 center : function(){
30822 var xy = this.el.getCenterXY(true);
30823 this.moveTo(xy[0], xy[1]);
30828 * Moves the dialog's top-left corner to the specified point
30829 * @param {Number} x
30830 * @param {Number} y
30831 * @return {Roo.BasicDialog} this
30833 moveTo : function(x, y){
30835 if(this.isVisible()){
30836 this.el.setXY(this.xy);
30837 this.adjustAssets();
30843 * Aligns the dialog to the specified element
30844 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30845 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30846 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30847 * @return {Roo.BasicDialog} this
30849 alignTo : function(element, position, offsets){
30850 this.xy = this.el.getAlignToXY(element, position, offsets);
30851 if(this.isVisible()){
30852 this.el.setXY(this.xy);
30853 this.adjustAssets();
30859 * Anchors an element to another element and realigns it when the window is resized.
30860 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30861 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30862 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30863 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30864 * is a number, it is used as the buffer delay (defaults to 50ms).
30865 * @return {Roo.BasicDialog} this
30867 anchorTo : function(el, alignment, offsets, monitorScroll){
30868 var action = function(){
30869 this.alignTo(el, alignment, offsets);
30871 Roo.EventManager.onWindowResize(action, this);
30872 var tm = typeof monitorScroll;
30873 if(tm != 'undefined'){
30874 Roo.EventManager.on(window, 'scroll', action, this,
30875 {buffer: tm == 'number' ? monitorScroll : 50});
30882 * Returns true if the dialog is visible
30883 * @return {Boolean}
30885 isVisible : function(){
30886 return this.el.isVisible();
30890 animHide : function(callback){
30891 var b = Roo.get(this.animateTarget).getBox();
30893 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30895 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30896 this.hideEl.createDelegate(this, [callback]));
30900 * Hides the dialog.
30901 * @param {Function} callback (optional) Function to call when the dialog is hidden
30902 * @return {Roo.BasicDialog} this
30904 hide : function(callback){
30905 if (this.fireEvent("beforehide", this) === false){
30909 this.shadow.hide();
30914 // sometimes animateTarget seems to get set.. causing problems...
30915 // this just double checks..
30916 if(this.animateTarget && Roo.get(this.animateTarget)) {
30917 this.animHide(callback);
30920 this.hideEl(callback);
30926 hideEl : function(callback){
30930 Roo.get(document.body).removeClass("x-body-masked");
30932 this.fireEvent("hide", this);
30933 if(typeof callback == "function"){
30939 hideAction : function(){
30940 this.setLeft("-10000px");
30941 this.setTop("-10000px");
30942 this.setStyle("visibility", "hidden");
30946 refreshSize : function(){
30947 this.size = this.el.getSize();
30948 this.xy = this.el.getXY();
30949 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30953 // z-index is managed by the DialogManager and may be overwritten at any time
30954 setZIndex : function(index){
30956 this.mask.setStyle("z-index", index);
30959 this.shim.setStyle("z-index", ++index);
30962 this.shadow.setZIndex(++index);
30964 this.el.setStyle("z-index", ++index);
30966 this.proxy.setStyle("z-index", ++index);
30969 this.resizer.proxy.setStyle("z-index", ++index);
30972 this.lastZIndex = index;
30976 * Returns the element for this dialog
30977 * @return {Roo.Element} The underlying dialog Element
30979 getEl : function(){
30985 * @class Roo.DialogManager
30986 * Provides global access to BasicDialogs that have been created and
30987 * support for z-indexing (layering) multiple open dialogs.
30989 Roo.DialogManager = function(){
30991 var accessList = [];
30995 var sortDialogs = function(d1, d2){
30996 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31000 var orderDialogs = function(){
31001 accessList.sort(sortDialogs);
31002 var seed = Roo.DialogManager.zseed;
31003 for(var i = 0, len = accessList.length; i < len; i++){
31004 var dlg = accessList[i];
31006 dlg.setZIndex(seed + (i*10));
31013 * The starting z-index for BasicDialogs (defaults to 9000)
31014 * @type Number The z-index value
31019 register : function(dlg){
31020 list[dlg.id] = dlg;
31021 accessList.push(dlg);
31025 unregister : function(dlg){
31026 delete list[dlg.id];
31029 if(!accessList.indexOf){
31030 for( i = 0, len = accessList.length; i < len; i++){
31031 if(accessList[i] == dlg){
31032 accessList.splice(i, 1);
31037 i = accessList.indexOf(dlg);
31039 accessList.splice(i, 1);
31045 * Gets a registered dialog by id
31046 * @param {String/Object} id The id of the dialog or a dialog
31047 * @return {Roo.BasicDialog} this
31049 get : function(id){
31050 return typeof id == "object" ? id : list[id];
31054 * Brings the specified dialog to the front
31055 * @param {String/Object} dlg The id of the dialog or a dialog
31056 * @return {Roo.BasicDialog} this
31058 bringToFront : function(dlg){
31059 dlg = this.get(dlg);
31062 dlg._lastAccess = new Date().getTime();
31069 * Sends the specified dialog to the back
31070 * @param {String/Object} dlg The id of the dialog or a dialog
31071 * @return {Roo.BasicDialog} this
31073 sendToBack : function(dlg){
31074 dlg = this.get(dlg);
31075 dlg._lastAccess = -(new Date().getTime());
31081 * Hides all dialogs
31083 hideAll : function(){
31084 for(var id in list){
31085 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31094 * @class Roo.LayoutDialog
31095 * @extends Roo.BasicDialog
31096 * Dialog which provides adjustments for working with a layout in a Dialog.
31097 * Add your necessary layout config options to the dialog's config.<br>
31098 * Example usage (including a nested layout):
31101 dialog = new Roo.LayoutDialog("download-dlg", {
31110 // layout config merges with the dialog config
31112 tabPosition: "top",
31113 alwaysShowTabs: true
31116 dialog.addKeyListener(27, dialog.hide, dialog);
31117 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31118 dialog.addButton("Build It!", this.getDownload, this);
31120 // we can even add nested layouts
31121 var innerLayout = new Roo.BorderLayout("dl-inner", {
31131 innerLayout.beginUpdate();
31132 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31133 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31134 innerLayout.endUpdate(true);
31136 var layout = dialog.getLayout();
31137 layout.beginUpdate();
31138 layout.add("center", new Roo.ContentPanel("standard-panel",
31139 {title: "Download the Source", fitToFrame:true}));
31140 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31141 {title: "Build your own roo.js"}));
31142 layout.getRegion("center").showPanel(sp);
31143 layout.endUpdate();
31147 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31148 * @param {Object} config configuration options
31150 Roo.LayoutDialog = function(el, cfg){
31153 if (typeof(cfg) == 'undefined') {
31154 config = Roo.apply({}, el);
31155 // not sure why we use documentElement here.. - it should always be body.
31156 // IE7 borks horribly if we use documentElement.
31157 // webkit also does not like documentElement - it creates a body element...
31158 el = Roo.get( document.body || document.documentElement ).createChild();
31159 //config.autoCreate = true;
31163 config.autoTabs = false;
31164 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31165 this.body.setStyle({overflow:"hidden", position:"relative"});
31166 this.layout = new Roo.BorderLayout(this.body.dom, config);
31167 this.layout.monitorWindowResize = false;
31168 this.el.addClass("x-dlg-auto-layout");
31169 // fix case when center region overwrites center function
31170 this.center = Roo.BasicDialog.prototype.center;
31171 this.on("show", this.layout.layout, this.layout, true);
31172 if (config.items) {
31173 var xitems = config.items;
31174 delete config.items;
31175 Roo.each(xitems, this.addxtype, this);
31180 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31182 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31185 endUpdate : function(){
31186 this.layout.endUpdate();
31190 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31193 beginUpdate : function(){
31194 this.layout.beginUpdate();
31198 * Get the BorderLayout for this dialog
31199 * @return {Roo.BorderLayout}
31201 getLayout : function(){
31202 return this.layout;
31205 showEl : function(){
31206 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31208 this.layout.layout();
31213 // Use the syncHeightBeforeShow config option to control this automatically
31214 syncBodyHeight : function(){
31215 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31216 if(this.layout){this.layout.layout();}
31220 * Add an xtype element (actually adds to the layout.)
31221 * @return {Object} xdata xtype object data.
31224 addxtype : function(c) {
31225 return this.layout.addxtype(c);
31229 * Ext JS Library 1.1.1
31230 * Copyright(c) 2006-2007, Ext JS, LLC.
31232 * Originally Released Under LGPL - original licence link has changed is not relivant.
31235 * <script type="text/javascript">
31239 * @class Roo.MessageBox
31240 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31244 Roo.Msg.alert('Status', 'Changes saved successfully.');
31246 // Prompt for user data:
31247 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31249 // process text value...
31253 // Show a dialog using config options:
31255 title:'Save Changes?',
31256 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31257 buttons: Roo.Msg.YESNOCANCEL,
31264 Roo.MessageBox = function(){
31265 var dlg, opt, mask, waitTimer;
31266 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31267 var buttons, activeTextEl, bwidth;
31270 var handleButton = function(button){
31272 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31276 var handleHide = function(){
31277 if(opt && opt.cls){
31278 dlg.el.removeClass(opt.cls);
31281 Roo.TaskMgr.stop(waitTimer);
31287 var updateButtons = function(b){
31290 buttons["ok"].hide();
31291 buttons["cancel"].hide();
31292 buttons["yes"].hide();
31293 buttons["no"].hide();
31294 dlg.footer.dom.style.display = 'none';
31297 dlg.footer.dom.style.display = '';
31298 for(var k in buttons){
31299 if(typeof buttons[k] != "function"){
31302 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31303 width += buttons[k].el.getWidth()+15;
31313 var handleEsc = function(d, k, e){
31314 if(opt && opt.closable !== false){
31324 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31325 * @return {Roo.BasicDialog} The BasicDialog element
31327 getDialog : function(){
31329 dlg = new Roo.BasicDialog("x-msg-box", {
31334 constraintoviewport:false,
31336 collapsible : false,
31339 width:400, height:100,
31340 buttonAlign:"center",
31341 closeClick : function(){
31342 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31343 handleButton("no");
31345 handleButton("cancel");
31349 dlg.on("hide", handleHide);
31351 dlg.addKeyListener(27, handleEsc);
31353 var bt = this.buttonText;
31354 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31355 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31356 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31357 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31358 bodyEl = dlg.body.createChild({
31360 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>'
31362 msgEl = bodyEl.dom.firstChild;
31363 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31364 textboxEl.enableDisplayMode();
31365 textboxEl.addKeyListener([10,13], function(){
31366 if(dlg.isVisible() && opt && opt.buttons){
31367 if(opt.buttons.ok){
31368 handleButton("ok");
31369 }else if(opt.buttons.yes){
31370 handleButton("yes");
31374 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31375 textareaEl.enableDisplayMode();
31376 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31377 progressEl.enableDisplayMode();
31378 var pf = progressEl.dom.firstChild;
31380 pp = Roo.get(pf.firstChild);
31381 pp.setHeight(pf.offsetHeight);
31389 * Updates the message box body text
31390 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31391 * the XHTML-compliant non-breaking space character '&#160;')
31392 * @return {Roo.MessageBox} This message box
31394 updateText : function(text){
31395 if(!dlg.isVisible() && !opt.width){
31396 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31398 msgEl.innerHTML = text || ' ';
31400 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31401 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31403 Math.min(opt.width || cw , this.maxWidth),
31404 Math.max(opt.minWidth || this.minWidth, bwidth)
31407 activeTextEl.setWidth(w);
31409 if(dlg.isVisible()){
31410 dlg.fixedcenter = false;
31412 // to big, make it scroll. = But as usual stupid IE does not support
31415 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31416 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31417 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31419 bodyEl.dom.style.height = '';
31420 bodyEl.dom.style.overflowY = '';
31423 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31425 bodyEl.dom.style.overflowX = '';
31428 dlg.setContentSize(w, bodyEl.getHeight());
31429 if(dlg.isVisible()){
31430 dlg.fixedcenter = true;
31436 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31437 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31438 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31439 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31440 * @return {Roo.MessageBox} This message box
31442 updateProgress : function(value, text){
31444 this.updateText(text);
31446 if (pp) { // weird bug on my firefox - for some reason this is not defined
31447 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31453 * Returns true if the message box is currently displayed
31454 * @return {Boolean} True if the message box is visible, else false
31456 isVisible : function(){
31457 return dlg && dlg.isVisible();
31461 * Hides the message box if it is displayed
31464 if(this.isVisible()){
31470 * Displays a new message box, or reinitializes an existing message box, based on the config options
31471 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31472 * The following config object properties are supported:
31474 Property Type Description
31475 ---------- --------------- ------------------------------------------------------------------------------------
31476 animEl String/Element An id or Element from which the message box should animate as it opens and
31477 closes (defaults to undefined)
31478 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31479 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31480 closable Boolean False to hide the top-right close button (defaults to true). Note that
31481 progress and wait dialogs will ignore this property and always hide the
31482 close button as they can only be closed programmatically.
31483 cls String A custom CSS class to apply to the message box element
31484 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31485 displayed (defaults to 75)
31486 fn Function A callback function to execute after closing the dialog. The arguments to the
31487 function will be btn (the name of the button that was clicked, if applicable,
31488 e.g. "ok"), and text (the value of the active text field, if applicable).
31489 Progress and wait dialogs will ignore this option since they do not respond to
31490 user actions and can only be closed programmatically, so any required function
31491 should be called by the same code after it closes the dialog.
31492 icon String A CSS class that provides a background image to be used as an icon for
31493 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31494 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31495 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31496 modal Boolean False to allow user interaction with the page while the message box is
31497 displayed (defaults to true)
31498 msg String A string that will replace the existing message box body text (defaults
31499 to the XHTML-compliant non-breaking space character ' ')
31500 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31501 progress Boolean True to display a progress bar (defaults to false)
31502 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31503 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31504 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31505 title String The title text
31506 value String The string value to set into the active textbox element if displayed
31507 wait Boolean True to display a progress bar (defaults to false)
31508 width Number The width of the dialog in pixels
31515 msg: 'Please enter your address:',
31517 buttons: Roo.MessageBox.OKCANCEL,
31520 animEl: 'addAddressBtn'
31523 * @param {Object} config Configuration options
31524 * @return {Roo.MessageBox} This message box
31526 show : function(options)
31529 // this causes nightmares if you show one dialog after another
31530 // especially on callbacks..
31532 if(this.isVisible()){
31535 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31536 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31537 Roo.log("New Dialog Message:" + options.msg )
31538 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31539 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31542 var d = this.getDialog();
31544 d.setTitle(opt.title || " ");
31545 d.close.setDisplayed(opt.closable !== false);
31546 activeTextEl = textboxEl;
31547 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31552 textareaEl.setHeight(typeof opt.multiline == "number" ?
31553 opt.multiline : this.defaultTextHeight);
31554 activeTextEl = textareaEl;
31563 progressEl.setDisplayed(opt.progress === true);
31564 this.updateProgress(0);
31565 activeTextEl.dom.value = opt.value || "";
31567 dlg.setDefaultButton(activeTextEl);
31569 var bs = opt.buttons;
31572 db = buttons["ok"];
31573 }else if(bs && bs.yes){
31574 db = buttons["yes"];
31576 dlg.setDefaultButton(db);
31578 bwidth = updateButtons(opt.buttons);
31579 this.updateText(opt.msg);
31581 d.el.addClass(opt.cls);
31583 d.proxyDrag = opt.proxyDrag === true;
31584 d.modal = opt.modal !== false;
31585 d.mask = opt.modal !== false ? mask : false;
31586 if(!d.isVisible()){
31587 // force it to the end of the z-index stack so it gets a cursor in FF
31588 document.body.appendChild(dlg.el.dom);
31589 d.animateTarget = null;
31590 d.show(options.animEl);
31596 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31597 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31598 * and closing the message box when the process is complete.
31599 * @param {String} title The title bar text
31600 * @param {String} msg The message box body text
31601 * @return {Roo.MessageBox} This message box
31603 progress : function(title, msg){
31610 minWidth: this.minProgressWidth,
31617 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31618 * If a callback function is passed it will be called after the user clicks the button, and the
31619 * id of the button that was clicked will be passed as the only parameter to the callback
31620 * (could also be the top-right close button).
31621 * @param {String} title The title bar text
31622 * @param {String} msg The message box body text
31623 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31624 * @param {Object} scope (optional) The scope of the callback function
31625 * @return {Roo.MessageBox} This message box
31627 alert : function(title, msg, fn, scope){
31640 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31641 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31642 * You are responsible for closing the message box when the process is complete.
31643 * @param {String} msg The message box body text
31644 * @param {String} title (optional) The title bar text
31645 * @return {Roo.MessageBox} This message box
31647 wait : function(msg, title){
31658 waitTimer = Roo.TaskMgr.start({
31660 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31668 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31669 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31670 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31671 * @param {String} title The title bar text
31672 * @param {String} msg The message box body text
31673 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31674 * @param {Object} scope (optional) The scope of the callback function
31675 * @return {Roo.MessageBox} This message box
31677 confirm : function(title, msg, fn, scope){
31681 buttons: this.YESNO,
31690 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31691 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31692 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31693 * (could also be the top-right close button) and the text that was entered will be passed as the two
31694 * parameters to the callback.
31695 * @param {String} title The title bar text
31696 * @param {String} msg The message box body text
31697 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31698 * @param {Object} scope (optional) The scope of the callback function
31699 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31700 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31701 * @return {Roo.MessageBox} This message box
31703 prompt : function(title, msg, fn, scope, multiline){
31707 buttons: this.OKCANCEL,
31712 multiline: multiline,
31719 * Button config that displays a single OK button
31724 * Button config that displays Yes and No buttons
31727 YESNO : {yes:true, no:true},
31729 * Button config that displays OK and Cancel buttons
31732 OKCANCEL : {ok:true, cancel:true},
31734 * Button config that displays Yes, No and Cancel buttons
31737 YESNOCANCEL : {yes:true, no:true, cancel:true},
31740 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31743 defaultTextHeight : 75,
31745 * The maximum width in pixels of the message box (defaults to 600)
31750 * The minimum width in pixels of the message box (defaults to 100)
31755 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31756 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31759 minProgressWidth : 250,
31761 * An object containing the default button text strings that can be overriden for localized language support.
31762 * Supported properties are: ok, cancel, yes and no.
31763 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31776 * Shorthand for {@link Roo.MessageBox}
31778 Roo.Msg = Roo.MessageBox;/*
31780 * Ext JS Library 1.1.1
31781 * Copyright(c) 2006-2007, Ext JS, LLC.
31783 * Originally Released Under LGPL - original licence link has changed is not relivant.
31786 * <script type="text/javascript">
31789 * @class Roo.QuickTips
31790 * Provides attractive and customizable tooltips for any element.
31793 Roo.QuickTips = function(){
31794 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31795 var ce, bd, xy, dd;
31796 var visible = false, disabled = true, inited = false;
31797 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31799 var onOver = function(e){
31803 var t = e.getTarget();
31804 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31807 if(ce && t == ce.el){
31808 clearTimeout(hideProc);
31811 if(t && tagEls[t.id]){
31812 tagEls[t.id].el = t;
31813 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31816 var ttp, et = Roo.fly(t);
31817 var ns = cfg.namespace;
31818 if(tm.interceptTitles && t.title){
31821 t.removeAttribute("title");
31822 e.preventDefault();
31824 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31827 showProc = show.defer(tm.showDelay, tm, [{
31830 width: et.getAttributeNS(ns, cfg.width),
31831 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31832 title: et.getAttributeNS(ns, cfg.title),
31833 cls: et.getAttributeNS(ns, cfg.cls)
31838 var onOut = function(e){
31839 clearTimeout(showProc);
31840 var t = e.getTarget();
31841 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31842 hideProc = setTimeout(hide, tm.hideDelay);
31846 var onMove = function(e){
31852 if(tm.trackMouse && ce){
31857 var onDown = function(e){
31858 clearTimeout(showProc);
31859 clearTimeout(hideProc);
31861 if(tm.hideOnClick){
31864 tm.enable.defer(100, tm);
31869 var getPad = function(){
31870 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31873 var show = function(o){
31877 clearTimeout(dismissProc);
31879 if(removeCls){ // in case manually hidden
31880 el.removeClass(removeCls);
31884 el.addClass(ce.cls);
31885 removeCls = ce.cls;
31888 tipTitle.update(ce.title);
31891 tipTitle.update('');
31894 el.dom.style.width = tm.maxWidth+'px';
31895 //tipBody.dom.style.width = '';
31896 tipBodyText.update(o.text);
31897 var p = getPad(), w = ce.width;
31899 var td = tipBodyText.dom;
31900 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31901 if(aw > tm.maxWidth){
31903 }else if(aw < tm.minWidth){
31909 //tipBody.setWidth(w);
31910 el.setWidth(parseInt(w, 10) + p);
31911 if(ce.autoHide === false){
31912 close.setDisplayed(true);
31917 close.setDisplayed(false);
31923 el.avoidY = xy[1]-18;
31928 el.setStyle("visibility", "visible");
31929 el.fadeIn({callback: afterShow});
31935 var afterShow = function(){
31939 if(tm.autoDismiss && ce.autoHide !== false){
31940 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31945 var hide = function(noanim){
31946 clearTimeout(dismissProc);
31947 clearTimeout(hideProc);
31949 if(el.isVisible()){
31951 if(noanim !== true && tm.animate){
31952 el.fadeOut({callback: afterHide});
31959 var afterHide = function(){
31962 el.removeClass(removeCls);
31969 * @cfg {Number} minWidth
31970 * The minimum width of the quick tip (defaults to 40)
31974 * @cfg {Number} maxWidth
31975 * The maximum width of the quick tip (defaults to 300)
31979 * @cfg {Boolean} interceptTitles
31980 * True to automatically use the element's DOM title value if available (defaults to false)
31982 interceptTitles : false,
31984 * @cfg {Boolean} trackMouse
31985 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31987 trackMouse : false,
31989 * @cfg {Boolean} hideOnClick
31990 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31992 hideOnClick : true,
31994 * @cfg {Number} showDelay
31995 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31999 * @cfg {Number} hideDelay
32000 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32004 * @cfg {Boolean} autoHide
32005 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32006 * Used in conjunction with hideDelay.
32011 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32012 * (defaults to true). Used in conjunction with autoDismissDelay.
32014 autoDismiss : true,
32017 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32019 autoDismissDelay : 5000,
32021 * @cfg {Boolean} animate
32022 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32027 * @cfg {String} title
32028 * Title text to display (defaults to ''). This can be any valid HTML markup.
32032 * @cfg {String} text
32033 * Body text to display (defaults to ''). This can be any valid HTML markup.
32037 * @cfg {String} cls
32038 * A CSS class to apply to the base quick tip element (defaults to '').
32042 * @cfg {Number} width
32043 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32044 * minWidth or maxWidth.
32049 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32050 * or display QuickTips in a page.
32053 tm = Roo.QuickTips;
32054 cfg = tm.tagConfig;
32056 if(!Roo.isReady){ // allow calling of init() before onReady
32057 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32060 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32061 el.fxDefaults = {stopFx: true};
32062 // maximum custom styling
32063 //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>');
32064 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>');
32065 tipTitle = el.child('h3');
32066 tipTitle.enableDisplayMode("block");
32067 tipBody = el.child('div.x-tip-bd');
32068 tipBodyText = el.child('div.x-tip-bd-inner');
32069 //bdLeft = el.child('div.x-tip-bd-left');
32070 //bdRight = el.child('div.x-tip-bd-right');
32071 close = el.child('div.x-tip-close');
32072 close.enableDisplayMode("block");
32073 close.on("click", hide);
32074 var d = Roo.get(document);
32075 d.on("mousedown", onDown);
32076 d.on("mouseover", onOver);
32077 d.on("mouseout", onOut);
32078 d.on("mousemove", onMove);
32079 esc = d.addKeyListener(27, hide);
32082 dd = el.initDD("default", null, {
32083 onDrag : function(){
32087 dd.setHandleElId(tipTitle.id);
32096 * Configures a new quick tip instance and assigns it to a target element. The following config options
32099 Property Type Description
32100 ---------- --------------------- ------------------------------------------------------------------------
32101 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32103 * @param {Object} config The config object
32105 register : function(config){
32106 var cs = config instanceof Array ? config : arguments;
32107 for(var i = 0, len = cs.length; i < len; i++) {
32109 var target = c.target;
32111 if(target instanceof Array){
32112 for(var j = 0, jlen = target.length; j < jlen; j++){
32113 tagEls[target[j]] = c;
32116 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32123 * Removes this quick tip from its element and destroys it.
32124 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32126 unregister : function(el){
32127 delete tagEls[Roo.id(el)];
32131 * Enable this quick tip.
32133 enable : function(){
32134 if(inited && disabled){
32136 if(locks.length < 1){
32143 * Disable this quick tip.
32145 disable : function(){
32147 clearTimeout(showProc);
32148 clearTimeout(hideProc);
32149 clearTimeout(dismissProc);
32157 * Returns true if the quick tip is enabled, else false.
32159 isEnabled : function(){
32166 attribute : "qtip",
32176 // backwards compat
32177 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32179 * Ext JS Library 1.1.1
32180 * Copyright(c) 2006-2007, Ext JS, LLC.
32182 * Originally Released Under LGPL - original licence link has changed is not relivant.
32185 * <script type="text/javascript">
32190 * @class Roo.tree.TreePanel
32191 * @extends Roo.data.Tree
32193 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32194 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32195 * @cfg {Boolean} enableDD true to enable drag and drop
32196 * @cfg {Boolean} enableDrag true to enable just drag
32197 * @cfg {Boolean} enableDrop true to enable just drop
32198 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32199 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32200 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32201 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32202 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32203 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32204 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32205 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32206 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32207 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32208 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32209 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32210 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32211 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32212 * @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>
32213 * @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>
32216 * @param {String/HTMLElement/Element} el The container element
32217 * @param {Object} config
32219 Roo.tree.TreePanel = function(el, config){
32221 var loader = false;
32223 root = config.root;
32224 delete config.root;
32226 if (config.loader) {
32227 loader = config.loader;
32228 delete config.loader;
32231 Roo.apply(this, config);
32232 Roo.tree.TreePanel.superclass.constructor.call(this);
32233 this.el = Roo.get(el);
32234 this.el.addClass('x-tree');
32235 //console.log(root);
32237 this.setRootNode( Roo.factory(root, Roo.tree));
32240 this.loader = Roo.factory(loader, Roo.tree);
32243 * Read-only. The id of the container element becomes this TreePanel's id.
32245 this.id = this.el.id;
32248 * @event beforeload
32249 * Fires before a node is loaded, return false to cancel
32250 * @param {Node} node The node being loaded
32252 "beforeload" : true,
32255 * Fires when a node is loaded
32256 * @param {Node} node The node that was loaded
32260 * @event textchange
32261 * Fires when the text for a node is changed
32262 * @param {Node} node The node
32263 * @param {String} text The new text
32264 * @param {String} oldText The old text
32266 "textchange" : true,
32268 * @event beforeexpand
32269 * Fires before a node is expanded, return false to cancel.
32270 * @param {Node} node The node
32271 * @param {Boolean} deep
32272 * @param {Boolean} anim
32274 "beforeexpand" : true,
32276 * @event beforecollapse
32277 * Fires before a node is collapsed, return false to cancel.
32278 * @param {Node} node The node
32279 * @param {Boolean} deep
32280 * @param {Boolean} anim
32282 "beforecollapse" : true,
32285 * Fires when a node is expanded
32286 * @param {Node} node The node
32290 * @event disabledchange
32291 * Fires when the disabled status of a node changes
32292 * @param {Node} node The node
32293 * @param {Boolean} disabled
32295 "disabledchange" : true,
32298 * Fires when a node is collapsed
32299 * @param {Node} node The node
32303 * @event beforeclick
32304 * Fires before click processing on a node. Return false to cancel the default action.
32305 * @param {Node} node The node
32306 * @param {Roo.EventObject} e The event object
32308 "beforeclick":true,
32310 * @event checkchange
32311 * Fires when a node with a checkbox's checked property changes
32312 * @param {Node} this This node
32313 * @param {Boolean} checked
32315 "checkchange":true,
32318 * Fires when a node is clicked
32319 * @param {Node} node The node
32320 * @param {Roo.EventObject} e The event object
32325 * Fires when a node is double clicked
32326 * @param {Node} node The node
32327 * @param {Roo.EventObject} e The event object
32331 * @event contextmenu
32332 * Fires when a node is right clicked
32333 * @param {Node} node The node
32334 * @param {Roo.EventObject} e The event object
32336 "contextmenu":true,
32338 * @event beforechildrenrendered
32339 * Fires right before the child nodes for a node are rendered
32340 * @param {Node} node The node
32342 "beforechildrenrendered":true,
32345 * Fires when a node starts being dragged
32346 * @param {Roo.tree.TreePanel} this
32347 * @param {Roo.tree.TreeNode} node
32348 * @param {event} e The raw browser event
32350 "startdrag" : true,
32353 * Fires when a drag operation is complete
32354 * @param {Roo.tree.TreePanel} this
32355 * @param {Roo.tree.TreeNode} node
32356 * @param {event} e The raw browser event
32361 * Fires when a dragged node is dropped on a valid DD target
32362 * @param {Roo.tree.TreePanel} this
32363 * @param {Roo.tree.TreeNode} node
32364 * @param {DD} dd The dd it was dropped on
32365 * @param {event} e The raw browser event
32369 * @event beforenodedrop
32370 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32371 * passed to handlers has the following properties:<br />
32372 * <ul style="padding:5px;padding-left:16px;">
32373 * <li>tree - The TreePanel</li>
32374 * <li>target - The node being targeted for the drop</li>
32375 * <li>data - The drag data from the drag source</li>
32376 * <li>point - The point of the drop - append, above or below</li>
32377 * <li>source - The drag source</li>
32378 * <li>rawEvent - Raw mouse event</li>
32379 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32380 * to be inserted by setting them on this object.</li>
32381 * <li>cancel - Set this to true to cancel the drop.</li>
32383 * @param {Object} dropEvent
32385 "beforenodedrop" : true,
32388 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32389 * passed to handlers has the following properties:<br />
32390 * <ul style="padding:5px;padding-left:16px;">
32391 * <li>tree - The TreePanel</li>
32392 * <li>target - The node being targeted for the drop</li>
32393 * <li>data - The drag data from the drag source</li>
32394 * <li>point - The point of the drop - append, above or below</li>
32395 * <li>source - The drag source</li>
32396 * <li>rawEvent - Raw mouse event</li>
32397 * <li>dropNode - Dropped node(s).</li>
32399 * @param {Object} dropEvent
32403 * @event nodedragover
32404 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32405 * passed to handlers has the following properties:<br />
32406 * <ul style="padding:5px;padding-left:16px;">
32407 * <li>tree - The TreePanel</li>
32408 * <li>target - The node being targeted for the drop</li>
32409 * <li>data - The drag data from the drag source</li>
32410 * <li>point - The point of the drop - append, above or below</li>
32411 * <li>source - The drag source</li>
32412 * <li>rawEvent - Raw mouse event</li>
32413 * <li>dropNode - Drop node(s) provided by the source.</li>
32414 * <li>cancel - Set this to true to signal drop not allowed.</li>
32416 * @param {Object} dragOverEvent
32418 "nodedragover" : true
32421 if(this.singleExpand){
32422 this.on("beforeexpand", this.restrictExpand, this);
32425 this.editor.tree = this;
32426 this.editor = Roo.factory(this.editor, Roo.tree);
32429 if (this.selModel) {
32430 this.selModel = Roo.factory(this.selModel, Roo.tree);
32434 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32435 rootVisible : true,
32436 animate: Roo.enableFx,
32439 hlDrop : Roo.enableFx,
32443 rendererTip: false,
32445 restrictExpand : function(node){
32446 var p = node.parentNode;
32448 if(p.expandedChild && p.expandedChild.parentNode == p){
32449 p.expandedChild.collapse();
32451 p.expandedChild = node;
32455 // private override
32456 setRootNode : function(node){
32457 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32458 if(!this.rootVisible){
32459 node.ui = new Roo.tree.RootTreeNodeUI(node);
32465 * Returns the container element for this TreePanel
32467 getEl : function(){
32472 * Returns the default TreeLoader for this TreePanel
32474 getLoader : function(){
32475 return this.loader;
32481 expandAll : function(){
32482 this.root.expand(true);
32486 * Collapse all nodes
32488 collapseAll : function(){
32489 this.root.collapse(true);
32493 * Returns the selection model used by this TreePanel
32495 getSelectionModel : function(){
32496 if(!this.selModel){
32497 this.selModel = new Roo.tree.DefaultSelectionModel();
32499 return this.selModel;
32503 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32504 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32505 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32508 getChecked : function(a, startNode){
32509 startNode = startNode || this.root;
32511 var f = function(){
32512 if(this.attributes.checked){
32513 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32516 startNode.cascade(f);
32521 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32522 * @param {String} path
32523 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32524 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32525 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32527 expandPath : function(path, attr, callback){
32528 attr = attr || "id";
32529 var keys = path.split(this.pathSeparator);
32530 var curNode = this.root;
32531 if(curNode.attributes[attr] != keys[1]){ // invalid root
32533 callback(false, null);
32538 var f = function(){
32539 if(++index == keys.length){
32541 callback(true, curNode);
32545 var c = curNode.findChild(attr, keys[index]);
32548 callback(false, curNode);
32553 c.expand(false, false, f);
32555 curNode.expand(false, false, f);
32559 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32560 * @param {String} path
32561 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32562 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32563 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32565 selectPath : function(path, attr, callback){
32566 attr = attr || "id";
32567 var keys = path.split(this.pathSeparator);
32568 var v = keys.pop();
32569 if(keys.length > 0){
32570 var f = function(success, node){
32571 if(success && node){
32572 var n = node.findChild(attr, v);
32578 }else if(callback){
32579 callback(false, n);
32583 callback(false, n);
32587 this.expandPath(keys.join(this.pathSeparator), attr, f);
32589 this.root.select();
32591 callback(true, this.root);
32596 getTreeEl : function(){
32601 * Trigger rendering of this TreePanel
32603 render : function(){
32604 if (this.innerCt) {
32605 return this; // stop it rendering more than once!!
32608 this.innerCt = this.el.createChild({tag:"ul",
32609 cls:"x-tree-root-ct " +
32610 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32612 if(this.containerScroll){
32613 Roo.dd.ScrollManager.register(this.el);
32615 if((this.enableDD || this.enableDrop) && !this.dropZone){
32617 * The dropZone used by this tree if drop is enabled
32618 * @type Roo.tree.TreeDropZone
32620 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32621 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32624 if((this.enableDD || this.enableDrag) && !this.dragZone){
32626 * The dragZone used by this tree if drag is enabled
32627 * @type Roo.tree.TreeDragZone
32629 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32630 ddGroup: this.ddGroup || "TreeDD",
32631 scroll: this.ddScroll
32634 this.getSelectionModel().init(this);
32636 Roo.log("ROOT not set in tree");
32639 this.root.render();
32640 if(!this.rootVisible){
32641 this.root.renderChildren();
32647 * Ext JS Library 1.1.1
32648 * Copyright(c) 2006-2007, Ext JS, LLC.
32650 * Originally Released Under LGPL - original licence link has changed is not relivant.
32653 * <script type="text/javascript">
32658 * @class Roo.tree.DefaultSelectionModel
32659 * @extends Roo.util.Observable
32660 * The default single selection for a TreePanel.
32661 * @param {Object} cfg Configuration
32663 Roo.tree.DefaultSelectionModel = function(cfg){
32664 this.selNode = null;
32670 * @event selectionchange
32671 * Fires when the selected node changes
32672 * @param {DefaultSelectionModel} this
32673 * @param {TreeNode} node the new selection
32675 "selectionchange" : true,
32678 * @event beforeselect
32679 * Fires before the selected node changes, return false to cancel the change
32680 * @param {DefaultSelectionModel} this
32681 * @param {TreeNode} node the new selection
32682 * @param {TreeNode} node the old selection
32684 "beforeselect" : true
32687 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32690 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32691 init : function(tree){
32693 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32694 tree.on("click", this.onNodeClick, this);
32697 onNodeClick : function(node, e){
32698 if (e.ctrlKey && this.selNode == node) {
32699 this.unselect(node);
32707 * @param {TreeNode} node The node to select
32708 * @return {TreeNode} The selected node
32710 select : function(node){
32711 var last = this.selNode;
32712 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32714 last.ui.onSelectedChange(false);
32716 this.selNode = node;
32717 node.ui.onSelectedChange(true);
32718 this.fireEvent("selectionchange", this, node, last);
32725 * @param {TreeNode} node The node to unselect
32727 unselect : function(node){
32728 if(this.selNode == node){
32729 this.clearSelections();
32734 * Clear all selections
32736 clearSelections : function(){
32737 var n = this.selNode;
32739 n.ui.onSelectedChange(false);
32740 this.selNode = null;
32741 this.fireEvent("selectionchange", this, null);
32747 * Get the selected node
32748 * @return {TreeNode} The selected node
32750 getSelectedNode : function(){
32751 return this.selNode;
32755 * Returns true if the node is selected
32756 * @param {TreeNode} node The node to check
32757 * @return {Boolean}
32759 isSelected : function(node){
32760 return this.selNode == node;
32764 * Selects the node above the selected node in the tree, intelligently walking the nodes
32765 * @return TreeNode The new selection
32767 selectPrevious : function(){
32768 var s = this.selNode || this.lastSelNode;
32772 var ps = s.previousSibling;
32774 if(!ps.isExpanded() || ps.childNodes.length < 1){
32775 return this.select(ps);
32777 var lc = ps.lastChild;
32778 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32781 return this.select(lc);
32783 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32784 return this.select(s.parentNode);
32790 * Selects the node above the selected node in the tree, intelligently walking the nodes
32791 * @return TreeNode The new selection
32793 selectNext : function(){
32794 var s = this.selNode || this.lastSelNode;
32798 if(s.firstChild && s.isExpanded()){
32799 return this.select(s.firstChild);
32800 }else if(s.nextSibling){
32801 return this.select(s.nextSibling);
32802 }else if(s.parentNode){
32804 s.parentNode.bubble(function(){
32805 if(this.nextSibling){
32806 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32815 onKeyDown : function(e){
32816 var s = this.selNode || this.lastSelNode;
32817 // undesirable, but required
32822 var k = e.getKey();
32830 this.selectPrevious();
32833 e.preventDefault();
32834 if(s.hasChildNodes()){
32835 if(!s.isExpanded()){
32837 }else if(s.firstChild){
32838 this.select(s.firstChild, e);
32843 e.preventDefault();
32844 if(s.hasChildNodes() && s.isExpanded()){
32846 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32847 this.select(s.parentNode, e);
32855 * @class Roo.tree.MultiSelectionModel
32856 * @extends Roo.util.Observable
32857 * Multi selection for a TreePanel.
32858 * @param {Object} cfg Configuration
32860 Roo.tree.MultiSelectionModel = function(){
32861 this.selNodes = [];
32865 * @event selectionchange
32866 * Fires when the selected nodes change
32867 * @param {MultiSelectionModel} this
32868 * @param {Array} nodes Array of the selected nodes
32870 "selectionchange" : true
32872 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32876 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32877 init : function(tree){
32879 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32880 tree.on("click", this.onNodeClick, this);
32883 onNodeClick : function(node, e){
32884 this.select(node, e, e.ctrlKey);
32889 * @param {TreeNode} node The node to select
32890 * @param {EventObject} e (optional) An event associated with the selection
32891 * @param {Boolean} keepExisting True to retain existing selections
32892 * @return {TreeNode} The selected node
32894 select : function(node, e, keepExisting){
32895 if(keepExisting !== true){
32896 this.clearSelections(true);
32898 if(this.isSelected(node)){
32899 this.lastSelNode = node;
32902 this.selNodes.push(node);
32903 this.selMap[node.id] = node;
32904 this.lastSelNode = node;
32905 node.ui.onSelectedChange(true);
32906 this.fireEvent("selectionchange", this, this.selNodes);
32912 * @param {TreeNode} node The node to unselect
32914 unselect : function(node){
32915 if(this.selMap[node.id]){
32916 node.ui.onSelectedChange(false);
32917 var sn = this.selNodes;
32920 index = sn.indexOf(node);
32922 for(var i = 0, len = sn.length; i < len; i++){
32930 this.selNodes.splice(index, 1);
32932 delete this.selMap[node.id];
32933 this.fireEvent("selectionchange", this, this.selNodes);
32938 * Clear all selections
32940 clearSelections : function(suppressEvent){
32941 var sn = this.selNodes;
32943 for(var i = 0, len = sn.length; i < len; i++){
32944 sn[i].ui.onSelectedChange(false);
32946 this.selNodes = [];
32948 if(suppressEvent !== true){
32949 this.fireEvent("selectionchange", this, this.selNodes);
32955 * Returns true if the node is selected
32956 * @param {TreeNode} node The node to check
32957 * @return {Boolean}
32959 isSelected : function(node){
32960 return this.selMap[node.id] ? true : false;
32964 * Returns an array of the selected nodes
32967 getSelectedNodes : function(){
32968 return this.selNodes;
32971 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32973 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32975 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32978 * Ext JS Library 1.1.1
32979 * Copyright(c) 2006-2007, Ext JS, LLC.
32981 * Originally Released Under LGPL - original licence link has changed is not relivant.
32984 * <script type="text/javascript">
32988 * @class Roo.tree.TreeNode
32989 * @extends Roo.data.Node
32990 * @cfg {String} text The text for this node
32991 * @cfg {Boolean} expanded true to start the node expanded
32992 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32993 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32994 * @cfg {Boolean} disabled true to start the node disabled
32995 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32996 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32997 * @cfg {String} cls A css class to be added to the node
32998 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32999 * @cfg {String} href URL of the link used for the node (defaults to #)
33000 * @cfg {String} hrefTarget target frame for the link
33001 * @cfg {String} qtip An Ext QuickTip for the node
33002 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33003 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33004 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33005 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33006 * (defaults to undefined with no checkbox rendered)
33008 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33010 Roo.tree.TreeNode = function(attributes){
33011 attributes = attributes || {};
33012 if(typeof attributes == "string"){
33013 attributes = {text: attributes};
33015 this.childrenRendered = false;
33016 this.rendered = false;
33017 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33018 this.expanded = attributes.expanded === true;
33019 this.isTarget = attributes.isTarget !== false;
33020 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33021 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33024 * Read-only. The text for this node. To change it use setText().
33027 this.text = attributes.text;
33029 * True if this node is disabled.
33032 this.disabled = attributes.disabled === true;
33036 * @event textchange
33037 * Fires when the text for this node is changed
33038 * @param {Node} this This node
33039 * @param {String} text The new text
33040 * @param {String} oldText The old text
33042 "textchange" : true,
33044 * @event beforeexpand
33045 * Fires before this node is expanded, return false to cancel.
33046 * @param {Node} this This node
33047 * @param {Boolean} deep
33048 * @param {Boolean} anim
33050 "beforeexpand" : true,
33052 * @event beforecollapse
33053 * Fires before this node is collapsed, return false to cancel.
33054 * @param {Node} this This node
33055 * @param {Boolean} deep
33056 * @param {Boolean} anim
33058 "beforecollapse" : true,
33061 * Fires when this node is expanded
33062 * @param {Node} this This node
33066 * @event disabledchange
33067 * Fires when the disabled status of this node changes
33068 * @param {Node} this This node
33069 * @param {Boolean} disabled
33071 "disabledchange" : true,
33074 * Fires when this node is collapsed
33075 * @param {Node} this This node
33079 * @event beforeclick
33080 * Fires before click processing. Return false to cancel the default action.
33081 * @param {Node} this This node
33082 * @param {Roo.EventObject} e The event object
33084 "beforeclick":true,
33086 * @event checkchange
33087 * Fires when a node with a checkbox's checked property changes
33088 * @param {Node} this This node
33089 * @param {Boolean} checked
33091 "checkchange":true,
33094 * Fires when this node is clicked
33095 * @param {Node} this This node
33096 * @param {Roo.EventObject} e The event object
33101 * Fires when this node is double clicked
33102 * @param {Node} this This node
33103 * @param {Roo.EventObject} e The event object
33107 * @event contextmenu
33108 * Fires when this node is right clicked
33109 * @param {Node} this This node
33110 * @param {Roo.EventObject} e The event object
33112 "contextmenu":true,
33114 * @event beforechildrenrendered
33115 * Fires right before the child nodes for this node are rendered
33116 * @param {Node} this This node
33118 "beforechildrenrendered":true
33121 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33124 * Read-only. The UI for this node
33127 this.ui = new uiClass(this);
33129 // finally support items[]
33130 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33135 Roo.each(this.attributes.items, function(c) {
33136 this.appendChild(Roo.factory(c,Roo.Tree));
33138 delete this.attributes.items;
33143 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33144 preventHScroll: true,
33146 * Returns true if this node is expanded
33147 * @return {Boolean}
33149 isExpanded : function(){
33150 return this.expanded;
33154 * Returns the UI object for this node
33155 * @return {TreeNodeUI}
33157 getUI : function(){
33161 // private override
33162 setFirstChild : function(node){
33163 var of = this.firstChild;
33164 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33165 if(this.childrenRendered && of && node != of){
33166 of.renderIndent(true, true);
33169 this.renderIndent(true, true);
33173 // private override
33174 setLastChild : function(node){
33175 var ol = this.lastChild;
33176 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33177 if(this.childrenRendered && ol && node != ol){
33178 ol.renderIndent(true, true);
33181 this.renderIndent(true, true);
33185 // these methods are overridden to provide lazy rendering support
33186 // private override
33187 appendChild : function()
33189 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33190 if(node && this.childrenRendered){
33193 this.ui.updateExpandIcon();
33197 // private override
33198 removeChild : function(node){
33199 this.ownerTree.getSelectionModel().unselect(node);
33200 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33201 // if it's been rendered remove dom node
33202 if(this.childrenRendered){
33205 if(this.childNodes.length < 1){
33206 this.collapse(false, false);
33208 this.ui.updateExpandIcon();
33210 if(!this.firstChild) {
33211 this.childrenRendered = false;
33216 // private override
33217 insertBefore : function(node, refNode){
33218 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33219 if(newNode && refNode && this.childrenRendered){
33222 this.ui.updateExpandIcon();
33227 * Sets the text for this node
33228 * @param {String} text
33230 setText : function(text){
33231 var oldText = this.text;
33233 this.attributes.text = text;
33234 if(this.rendered){ // event without subscribing
33235 this.ui.onTextChange(this, text, oldText);
33237 this.fireEvent("textchange", this, text, oldText);
33241 * Triggers selection of this node
33243 select : function(){
33244 this.getOwnerTree().getSelectionModel().select(this);
33248 * Triggers deselection of this node
33250 unselect : function(){
33251 this.getOwnerTree().getSelectionModel().unselect(this);
33255 * Returns true if this node is selected
33256 * @return {Boolean}
33258 isSelected : function(){
33259 return this.getOwnerTree().getSelectionModel().isSelected(this);
33263 * Expand this node.
33264 * @param {Boolean} deep (optional) True to expand all children as well
33265 * @param {Boolean} anim (optional) false to cancel the default animation
33266 * @param {Function} callback (optional) A callback to be called when
33267 * expanding this node completes (does not wait for deep expand to complete).
33268 * Called with 1 parameter, this node.
33270 expand : function(deep, anim, callback){
33271 if(!this.expanded){
33272 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33275 if(!this.childrenRendered){
33276 this.renderChildren();
33278 this.expanded = true;
33279 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33280 this.ui.animExpand(function(){
33281 this.fireEvent("expand", this);
33282 if(typeof callback == "function"){
33286 this.expandChildNodes(true);
33288 }.createDelegate(this));
33292 this.fireEvent("expand", this);
33293 if(typeof callback == "function"){
33298 if(typeof callback == "function"){
33303 this.expandChildNodes(true);
33307 isHiddenRoot : function(){
33308 return this.isRoot && !this.getOwnerTree().rootVisible;
33312 * Collapse this node.
33313 * @param {Boolean} deep (optional) True to collapse all children as well
33314 * @param {Boolean} anim (optional) false to cancel the default animation
33316 collapse : function(deep, anim){
33317 if(this.expanded && !this.isHiddenRoot()){
33318 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33321 this.expanded = false;
33322 if((this.getOwnerTree().animate && anim !== false) || anim){
33323 this.ui.animCollapse(function(){
33324 this.fireEvent("collapse", this);
33326 this.collapseChildNodes(true);
33328 }.createDelegate(this));
33331 this.ui.collapse();
33332 this.fireEvent("collapse", this);
33336 var cs = this.childNodes;
33337 for(var i = 0, len = cs.length; i < len; i++) {
33338 cs[i].collapse(true, false);
33344 delayedExpand : function(delay){
33345 if(!this.expandProcId){
33346 this.expandProcId = this.expand.defer(delay, this);
33351 cancelExpand : function(){
33352 if(this.expandProcId){
33353 clearTimeout(this.expandProcId);
33355 this.expandProcId = false;
33359 * Toggles expanded/collapsed state of the node
33361 toggle : function(){
33370 * Ensures all parent nodes are expanded
33372 ensureVisible : function(callback){
33373 var tree = this.getOwnerTree();
33374 tree.expandPath(this.parentNode.getPath(), false, function(){
33375 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33376 Roo.callback(callback);
33377 }.createDelegate(this));
33381 * Expand all child nodes
33382 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33384 expandChildNodes : function(deep){
33385 var cs = this.childNodes;
33386 for(var i = 0, len = cs.length; i < len; i++) {
33387 cs[i].expand(deep);
33392 * Collapse all child nodes
33393 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33395 collapseChildNodes : function(deep){
33396 var cs = this.childNodes;
33397 for(var i = 0, len = cs.length; i < len; i++) {
33398 cs[i].collapse(deep);
33403 * Disables this node
33405 disable : function(){
33406 this.disabled = true;
33408 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33409 this.ui.onDisableChange(this, true);
33411 this.fireEvent("disabledchange", this, true);
33415 * Enables this node
33417 enable : function(){
33418 this.disabled = false;
33419 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33420 this.ui.onDisableChange(this, false);
33422 this.fireEvent("disabledchange", this, false);
33426 renderChildren : function(suppressEvent){
33427 if(suppressEvent !== false){
33428 this.fireEvent("beforechildrenrendered", this);
33430 var cs = this.childNodes;
33431 for(var i = 0, len = cs.length; i < len; i++){
33432 cs[i].render(true);
33434 this.childrenRendered = true;
33438 sort : function(fn, scope){
33439 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33440 if(this.childrenRendered){
33441 var cs = this.childNodes;
33442 for(var i = 0, len = cs.length; i < len; i++){
33443 cs[i].render(true);
33449 render : function(bulkRender){
33450 this.ui.render(bulkRender);
33451 if(!this.rendered){
33452 this.rendered = true;
33454 this.expanded = false;
33455 this.expand(false, false);
33461 renderIndent : function(deep, refresh){
33463 this.ui.childIndent = null;
33465 this.ui.renderIndent();
33466 if(deep === true && this.childrenRendered){
33467 var cs = this.childNodes;
33468 for(var i = 0, len = cs.length; i < len; i++){
33469 cs[i].renderIndent(true, refresh);
33475 * Ext JS Library 1.1.1
33476 * Copyright(c) 2006-2007, Ext JS, LLC.
33478 * Originally Released Under LGPL - original licence link has changed is not relivant.
33481 * <script type="text/javascript">
33485 * @class Roo.tree.AsyncTreeNode
33486 * @extends Roo.tree.TreeNode
33487 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33489 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33491 Roo.tree.AsyncTreeNode = function(config){
33492 this.loaded = false;
33493 this.loading = false;
33494 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33496 * @event beforeload
33497 * Fires before this node is loaded, return false to cancel
33498 * @param {Node} this This node
33500 this.addEvents({'beforeload':true, 'load': true});
33503 * Fires when this node is loaded
33504 * @param {Node} this This node
33507 * The loader used by this node (defaults to using the tree's defined loader)
33512 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33513 expand : function(deep, anim, callback){
33514 if(this.loading){ // if an async load is already running, waiting til it's done
33516 var f = function(){
33517 if(!this.loading){ // done loading
33518 clearInterval(timer);
33519 this.expand(deep, anim, callback);
33521 }.createDelegate(this);
33522 timer = setInterval(f, 200);
33526 if(this.fireEvent("beforeload", this) === false){
33529 this.loading = true;
33530 this.ui.beforeLoad(this);
33531 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33533 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33537 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33541 * Returns true if this node is currently loading
33542 * @return {Boolean}
33544 isLoading : function(){
33545 return this.loading;
33548 loadComplete : function(deep, anim, callback){
33549 this.loading = false;
33550 this.loaded = true;
33551 this.ui.afterLoad(this);
33552 this.fireEvent("load", this);
33553 this.expand(deep, anim, callback);
33557 * Returns true if this node has been loaded
33558 * @return {Boolean}
33560 isLoaded : function(){
33561 return this.loaded;
33564 hasChildNodes : function(){
33565 if(!this.isLeaf() && !this.loaded){
33568 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33573 * Trigger a reload for this node
33574 * @param {Function} callback
33576 reload : function(callback){
33577 this.collapse(false, false);
33578 while(this.firstChild){
33579 this.removeChild(this.firstChild);
33581 this.childrenRendered = false;
33582 this.loaded = false;
33583 if(this.isHiddenRoot()){
33584 this.expanded = false;
33586 this.expand(false, false, callback);
33590 * Ext JS Library 1.1.1
33591 * Copyright(c) 2006-2007, Ext JS, LLC.
33593 * Originally Released Under LGPL - original licence link has changed is not relivant.
33596 * <script type="text/javascript">
33600 * @class Roo.tree.TreeNodeUI
33602 * @param {Object} node The node to render
33603 * The TreeNode UI implementation is separate from the
33604 * tree implementation. Unless you are customizing the tree UI,
33605 * you should never have to use this directly.
33607 Roo.tree.TreeNodeUI = function(node){
33609 this.rendered = false;
33610 this.animating = false;
33611 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33614 Roo.tree.TreeNodeUI.prototype = {
33615 removeChild : function(node){
33617 this.ctNode.removeChild(node.ui.getEl());
33621 beforeLoad : function(){
33622 this.addClass("x-tree-node-loading");
33625 afterLoad : function(){
33626 this.removeClass("x-tree-node-loading");
33629 onTextChange : function(node, text, oldText){
33631 this.textNode.innerHTML = text;
33635 onDisableChange : function(node, state){
33636 this.disabled = state;
33638 this.addClass("x-tree-node-disabled");
33640 this.removeClass("x-tree-node-disabled");
33644 onSelectedChange : function(state){
33647 this.addClass("x-tree-selected");
33650 this.removeClass("x-tree-selected");
33654 onMove : function(tree, node, oldParent, newParent, index, refNode){
33655 this.childIndent = null;
33657 var targetNode = newParent.ui.getContainer();
33658 if(!targetNode){//target not rendered
33659 this.holder = document.createElement("div");
33660 this.holder.appendChild(this.wrap);
33663 var insertBefore = refNode ? refNode.ui.getEl() : null;
33665 targetNode.insertBefore(this.wrap, insertBefore);
33667 targetNode.appendChild(this.wrap);
33669 this.node.renderIndent(true);
33673 addClass : function(cls){
33675 Roo.fly(this.elNode).addClass(cls);
33679 removeClass : function(cls){
33681 Roo.fly(this.elNode).removeClass(cls);
33685 remove : function(){
33687 this.holder = document.createElement("div");
33688 this.holder.appendChild(this.wrap);
33692 fireEvent : function(){
33693 return this.node.fireEvent.apply(this.node, arguments);
33696 initEvents : function(){
33697 this.node.on("move", this.onMove, this);
33698 var E = Roo.EventManager;
33699 var a = this.anchor;
33701 var el = Roo.fly(a, '_treeui');
33703 if(Roo.isOpera){ // opera render bug ignores the CSS
33704 el.setStyle("text-decoration", "none");
33707 el.on("click", this.onClick, this);
33708 el.on("dblclick", this.onDblClick, this);
33711 Roo.EventManager.on(this.checkbox,
33712 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33715 el.on("contextmenu", this.onContextMenu, this);
33717 var icon = Roo.fly(this.iconNode);
33718 icon.on("click", this.onClick, this);
33719 icon.on("dblclick", this.onDblClick, this);
33720 icon.on("contextmenu", this.onContextMenu, this);
33721 E.on(this.ecNode, "click", this.ecClick, this, true);
33723 if(this.node.disabled){
33724 this.addClass("x-tree-node-disabled");
33726 if(this.node.hidden){
33727 this.addClass("x-tree-node-disabled");
33729 var ot = this.node.getOwnerTree();
33730 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33731 if(dd && (!this.node.isRoot || ot.rootVisible)){
33732 Roo.dd.Registry.register(this.elNode, {
33734 handles: this.getDDHandles(),
33740 getDDHandles : function(){
33741 return [this.iconNode, this.textNode];
33746 this.wrap.style.display = "none";
33752 this.wrap.style.display = "";
33756 onContextMenu : function(e){
33757 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33758 e.preventDefault();
33760 this.fireEvent("contextmenu", this.node, e);
33764 onClick : function(e){
33769 if(this.fireEvent("beforeclick", this.node, e) !== false){
33770 if(!this.disabled && this.node.attributes.href){
33771 this.fireEvent("click", this.node, e);
33774 e.preventDefault();
33779 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33780 this.node.toggle();
33783 this.fireEvent("click", this.node, e);
33789 onDblClick : function(e){
33790 e.preventDefault();
33795 this.toggleCheck();
33797 if(!this.animating && this.node.hasChildNodes()){
33798 this.node.toggle();
33800 this.fireEvent("dblclick", this.node, e);
33803 onCheckChange : function(){
33804 var checked = this.checkbox.checked;
33805 this.node.attributes.checked = checked;
33806 this.fireEvent('checkchange', this.node, checked);
33809 ecClick : function(e){
33810 if(!this.animating && this.node.hasChildNodes()){
33811 this.node.toggle();
33815 startDrop : function(){
33816 this.dropping = true;
33819 // delayed drop so the click event doesn't get fired on a drop
33820 endDrop : function(){
33821 setTimeout(function(){
33822 this.dropping = false;
33823 }.createDelegate(this), 50);
33826 expand : function(){
33827 this.updateExpandIcon();
33828 this.ctNode.style.display = "";
33831 focus : function(){
33832 if(!this.node.preventHScroll){
33833 try{this.anchor.focus();
33835 }else if(!Roo.isIE){
33837 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33838 var l = noscroll.scrollLeft;
33839 this.anchor.focus();
33840 noscroll.scrollLeft = l;
33845 toggleCheck : function(value){
33846 var cb = this.checkbox;
33848 cb.checked = (value === undefined ? !cb.checked : value);
33854 this.anchor.blur();
33858 animExpand : function(callback){
33859 var ct = Roo.get(this.ctNode);
33861 if(!this.node.hasChildNodes()){
33862 this.updateExpandIcon();
33863 this.ctNode.style.display = "";
33864 Roo.callback(callback);
33867 this.animating = true;
33868 this.updateExpandIcon();
33871 callback : function(){
33872 this.animating = false;
33873 Roo.callback(callback);
33876 duration: this.node.ownerTree.duration || .25
33880 highlight : function(){
33881 var tree = this.node.getOwnerTree();
33882 Roo.fly(this.wrap).highlight(
33883 tree.hlColor || "C3DAF9",
33884 {endColor: tree.hlBaseColor}
33888 collapse : function(){
33889 this.updateExpandIcon();
33890 this.ctNode.style.display = "none";
33893 animCollapse : function(callback){
33894 var ct = Roo.get(this.ctNode);
33895 ct.enableDisplayMode('block');
33898 this.animating = true;
33899 this.updateExpandIcon();
33902 callback : function(){
33903 this.animating = false;
33904 Roo.callback(callback);
33907 duration: this.node.ownerTree.duration || .25
33911 getContainer : function(){
33912 return this.ctNode;
33915 getEl : function(){
33919 appendDDGhost : function(ghostNode){
33920 ghostNode.appendChild(this.elNode.cloneNode(true));
33923 getDDRepairXY : function(){
33924 return Roo.lib.Dom.getXY(this.iconNode);
33927 onRender : function(){
33931 render : function(bulkRender){
33932 var n = this.node, a = n.attributes;
33933 var targetNode = n.parentNode ?
33934 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33936 if(!this.rendered){
33937 this.rendered = true;
33939 this.renderElements(n, a, targetNode, bulkRender);
33942 if(this.textNode.setAttributeNS){
33943 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33945 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33948 this.textNode.setAttribute("ext:qtip", a.qtip);
33950 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33953 }else if(a.qtipCfg){
33954 a.qtipCfg.target = Roo.id(this.textNode);
33955 Roo.QuickTips.register(a.qtipCfg);
33958 if(!this.node.expanded){
33959 this.updateExpandIcon();
33962 if(bulkRender === true) {
33963 targetNode.appendChild(this.wrap);
33968 renderElements : function(n, a, targetNode, bulkRender)
33970 // add some indent caching, this helps performance when rendering a large tree
33971 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33972 var t = n.getOwnerTree();
33973 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33974 if (typeof(n.attributes.html) != 'undefined') {
33975 txt = n.attributes.html;
33977 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33978 var cb = typeof a.checked == 'boolean';
33979 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33980 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33981 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33982 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33983 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33984 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33985 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33986 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33987 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33988 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33991 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33992 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33993 n.nextSibling.ui.getEl(), buf.join(""));
33995 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33998 this.elNode = this.wrap.childNodes[0];
33999 this.ctNode = this.wrap.childNodes[1];
34000 var cs = this.elNode.childNodes;
34001 this.indentNode = cs[0];
34002 this.ecNode = cs[1];
34003 this.iconNode = cs[2];
34006 this.checkbox = cs[3];
34009 this.anchor = cs[index];
34010 this.textNode = cs[index].firstChild;
34013 getAnchor : function(){
34014 return this.anchor;
34017 getTextEl : function(){
34018 return this.textNode;
34021 getIconEl : function(){
34022 return this.iconNode;
34025 isChecked : function(){
34026 return this.checkbox ? this.checkbox.checked : false;
34029 updateExpandIcon : function(){
34031 var n = this.node, c1, c2;
34032 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34033 var hasChild = n.hasChildNodes();
34037 c1 = "x-tree-node-collapsed";
34038 c2 = "x-tree-node-expanded";
34041 c1 = "x-tree-node-expanded";
34042 c2 = "x-tree-node-collapsed";
34045 this.removeClass("x-tree-node-leaf");
34046 this.wasLeaf = false;
34048 if(this.c1 != c1 || this.c2 != c2){
34049 Roo.fly(this.elNode).replaceClass(c1, c2);
34050 this.c1 = c1; this.c2 = c2;
34053 // this changes non-leafs into leafs if they have no children.
34054 // it's not very rational behaviour..
34056 if(!this.wasLeaf && this.node.leaf){
34057 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34060 this.wasLeaf = true;
34063 var ecc = "x-tree-ec-icon "+cls;
34064 if(this.ecc != ecc){
34065 this.ecNode.className = ecc;
34071 getChildIndent : function(){
34072 if(!this.childIndent){
34076 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34078 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34080 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34085 this.childIndent = buf.join("");
34087 return this.childIndent;
34090 renderIndent : function(){
34093 var p = this.node.parentNode;
34095 indent = p.ui.getChildIndent();
34097 if(this.indentMarkup != indent){ // don't rerender if not required
34098 this.indentNode.innerHTML = indent;
34099 this.indentMarkup = indent;
34101 this.updateExpandIcon();
34106 Roo.tree.RootTreeNodeUI = function(){
34107 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34109 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34110 render : function(){
34111 if(!this.rendered){
34112 var targetNode = this.node.ownerTree.innerCt.dom;
34113 this.node.expanded = true;
34114 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34115 this.wrap = this.ctNode = targetNode.firstChild;
34118 collapse : function(){
34120 expand : function(){
34124 * Ext JS Library 1.1.1
34125 * Copyright(c) 2006-2007, Ext JS, LLC.
34127 * Originally Released Under LGPL - original licence link has changed is not relivant.
34130 * <script type="text/javascript">
34133 * @class Roo.tree.TreeLoader
34134 * @extends Roo.util.Observable
34135 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34136 * nodes from a specified URL. The response must be a javascript Array definition
34137 * who's elements are node definition objects. eg:
34142 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34143 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34150 * The old style respose with just an array is still supported, but not recommended.
34153 * A server request is sent, and child nodes are loaded only when a node is expanded.
34154 * The loading node's id is passed to the server under the parameter name "node" to
34155 * enable the server to produce the correct child nodes.
34157 * To pass extra parameters, an event handler may be attached to the "beforeload"
34158 * event, and the parameters specified in the TreeLoader's baseParams property:
34160 myTreeLoader.on("beforeload", function(treeLoader, node) {
34161 this.baseParams.category = node.attributes.category;
34164 * This would pass an HTTP parameter called "category" to the server containing
34165 * the value of the Node's "category" attribute.
34167 * Creates a new Treeloader.
34168 * @param {Object} config A config object containing config properties.
34170 Roo.tree.TreeLoader = function(config){
34171 this.baseParams = {};
34172 this.requestMethod = "POST";
34173 Roo.apply(this, config);
34178 * @event beforeload
34179 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34180 * @param {Object} This TreeLoader object.
34181 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34182 * @param {Object} callback The callback function specified in the {@link #load} call.
34187 * Fires when the node has been successfuly loaded.
34188 * @param {Object} This TreeLoader object.
34189 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34190 * @param {Object} response The response object containing the data from the server.
34194 * @event loadexception
34195 * Fires if the network request failed.
34196 * @param {Object} This TreeLoader object.
34197 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34198 * @param {Object} response The response object containing the data from the server.
34200 loadexception : true,
34203 * Fires before a node is created, enabling you to return custom Node types
34204 * @param {Object} This TreeLoader object.
34205 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34210 Roo.tree.TreeLoader.superclass.constructor.call(this);
34213 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34215 * @cfg {String} dataUrl The URL from which to request a Json string which
34216 * specifies an array of node definition object representing the child nodes
34220 * @cfg {String} requestMethod either GET or POST
34221 * defaults to POST (due to BC)
34225 * @cfg {Object} baseParams (optional) An object containing properties which
34226 * specify HTTP parameters to be passed to each request for child nodes.
34229 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34230 * created by this loader. If the attributes sent by the server have an attribute in this object,
34231 * they take priority.
34234 * @cfg {Object} uiProviders (optional) An object containing properties which
34236 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34237 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34238 * <i>uiProvider</i> attribute of a returned child node is a string rather
34239 * than a reference to a TreeNodeUI implementation, this that string value
34240 * is used as a property name in the uiProviders object. You can define the provider named
34241 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34246 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34247 * child nodes before loading.
34249 clearOnLoad : true,
34252 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34253 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34254 * Grid query { data : [ .....] }
34259 * @cfg {String} queryParam (optional)
34260 * Name of the query as it will be passed on the querystring (defaults to 'node')
34261 * eg. the request will be ?node=[id]
34268 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34269 * This is called automatically when a node is expanded, but may be used to reload
34270 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34271 * @param {Roo.tree.TreeNode} node
34272 * @param {Function} callback
34274 load : function(node, callback){
34275 if(this.clearOnLoad){
34276 while(node.firstChild){
34277 node.removeChild(node.firstChild);
34280 if(node.attributes.children){ // preloaded json children
34281 var cs = node.attributes.children;
34282 for(var i = 0, len = cs.length; i < len; i++){
34283 node.appendChild(this.createNode(cs[i]));
34285 if(typeof callback == "function"){
34288 }else if(this.dataUrl){
34289 this.requestData(node, callback);
34293 getParams: function(node){
34294 var buf = [], bp = this.baseParams;
34295 for(var key in bp){
34296 if(typeof bp[key] != "function"){
34297 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34300 var n = this.queryParam === false ? 'node' : this.queryParam;
34301 buf.push(n + "=", encodeURIComponent(node.id));
34302 return buf.join("");
34305 requestData : function(node, callback){
34306 if(this.fireEvent("beforeload", this, node, callback) !== false){
34307 this.transId = Roo.Ajax.request({
34308 method:this.requestMethod,
34309 url: this.dataUrl||this.url,
34310 success: this.handleResponse,
34311 failure: this.handleFailure,
34313 argument: {callback: callback, node: node},
34314 params: this.getParams(node)
34317 // if the load is cancelled, make sure we notify
34318 // the node that we are done
34319 if(typeof callback == "function"){
34325 isLoading : function(){
34326 return this.transId ? true : false;
34329 abort : function(){
34330 if(this.isLoading()){
34331 Roo.Ajax.abort(this.transId);
34336 createNode : function(attr)
34338 // apply baseAttrs, nice idea Corey!
34339 if(this.baseAttrs){
34340 Roo.applyIf(attr, this.baseAttrs);
34342 if(this.applyLoader !== false){
34343 attr.loader = this;
34345 // uiProvider = depreciated..
34347 if(typeof(attr.uiProvider) == 'string'){
34348 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34349 /** eval:var:attr */ eval(attr.uiProvider);
34351 if(typeof(this.uiProviders['default']) != 'undefined') {
34352 attr.uiProvider = this.uiProviders['default'];
34355 this.fireEvent('create', this, attr);
34357 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34359 new Roo.tree.TreeNode(attr) :
34360 new Roo.tree.AsyncTreeNode(attr));
34363 processResponse : function(response, node, callback)
34365 var json = response.responseText;
34368 var o = Roo.decode(json);
34370 if (this.root === false && typeof(o.success) != undefined) {
34371 this.root = 'data'; // the default behaviour for list like data..
34374 if (this.root !== false && !o.success) {
34375 // it's a failure condition.
34376 var a = response.argument;
34377 this.fireEvent("loadexception", this, a.node, response);
34378 Roo.log("Load failed - should have a handler really");
34384 if (this.root !== false) {
34388 for(var i = 0, len = o.length; i < len; i++){
34389 var n = this.createNode(o[i]);
34391 node.appendChild(n);
34394 if(typeof callback == "function"){
34395 callback(this, node);
34398 this.handleFailure(response);
34402 handleResponse : function(response){
34403 this.transId = false;
34404 var a = response.argument;
34405 this.processResponse(response, a.node, a.callback);
34406 this.fireEvent("load", this, a.node, response);
34409 handleFailure : function(response)
34411 // should handle failure better..
34412 this.transId = false;
34413 var a = response.argument;
34414 this.fireEvent("loadexception", this, a.node, response);
34415 if(typeof a.callback == "function"){
34416 a.callback(this, a.node);
34421 * Ext JS Library 1.1.1
34422 * Copyright(c) 2006-2007, Ext JS, LLC.
34424 * Originally Released Under LGPL - original licence link has changed is not relivant.
34427 * <script type="text/javascript">
34431 * @class Roo.tree.TreeFilter
34432 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34433 * @param {TreePanel} tree
34434 * @param {Object} config (optional)
34436 Roo.tree.TreeFilter = function(tree, config){
34438 this.filtered = {};
34439 Roo.apply(this, config);
34442 Roo.tree.TreeFilter.prototype = {
34449 * Filter the data by a specific attribute.
34450 * @param {String/RegExp} value Either string that the attribute value
34451 * should start with or a RegExp to test against the attribute
34452 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34453 * @param {TreeNode} startNode (optional) The node to start the filter at.
34455 filter : function(value, attr, startNode){
34456 attr = attr || "text";
34458 if(typeof value == "string"){
34459 var vlen = value.length;
34460 // auto clear empty filter
34461 if(vlen == 0 && this.clearBlank){
34465 value = value.toLowerCase();
34467 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34469 }else if(value.exec){ // regex?
34471 return value.test(n.attributes[attr]);
34474 throw 'Illegal filter type, must be string or regex';
34476 this.filterBy(f, null, startNode);
34480 * Filter by a function. The passed function will be called with each
34481 * node in the tree (or from the startNode). If the function returns true, the node is kept
34482 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34483 * @param {Function} fn The filter function
34484 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34486 filterBy : function(fn, scope, startNode){
34487 startNode = startNode || this.tree.root;
34488 if(this.autoClear){
34491 var af = this.filtered, rv = this.reverse;
34492 var f = function(n){
34493 if(n == startNode){
34499 var m = fn.call(scope || n, n);
34507 startNode.cascade(f);
34510 if(typeof id != "function"){
34512 if(n && n.parentNode){
34513 n.parentNode.removeChild(n);
34521 * Clears the current filter. Note: with the "remove" option
34522 * set a filter cannot be cleared.
34524 clear : function(){
34526 var af = this.filtered;
34528 if(typeof id != "function"){
34535 this.filtered = {};
34540 * Ext JS Library 1.1.1
34541 * Copyright(c) 2006-2007, Ext JS, LLC.
34543 * Originally Released Under LGPL - original licence link has changed is not relivant.
34546 * <script type="text/javascript">
34551 * @class Roo.tree.TreeSorter
34552 * Provides sorting of nodes in a TreePanel
34554 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34555 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34556 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34557 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34558 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34559 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34561 * @param {TreePanel} tree
34562 * @param {Object} config
34564 Roo.tree.TreeSorter = function(tree, config){
34565 Roo.apply(this, config);
34566 tree.on("beforechildrenrendered", this.doSort, this);
34567 tree.on("append", this.updateSort, this);
34568 tree.on("insert", this.updateSort, this);
34570 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34571 var p = this.property || "text";
34572 var sortType = this.sortType;
34573 var fs = this.folderSort;
34574 var cs = this.caseSensitive === true;
34575 var leafAttr = this.leafAttr || 'leaf';
34577 this.sortFn = function(n1, n2){
34579 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34582 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34586 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34587 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34589 return dsc ? +1 : -1;
34591 return dsc ? -1 : +1;
34598 Roo.tree.TreeSorter.prototype = {
34599 doSort : function(node){
34600 node.sort(this.sortFn);
34603 compareNodes : function(n1, n2){
34604 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34607 updateSort : function(tree, node){
34608 if(node.childrenRendered){
34609 this.doSort.defer(1, this, [node]);
34614 * Ext JS Library 1.1.1
34615 * Copyright(c) 2006-2007, Ext JS, LLC.
34617 * Originally Released Under LGPL - original licence link has changed is not relivant.
34620 * <script type="text/javascript">
34623 if(Roo.dd.DropZone){
34625 Roo.tree.TreeDropZone = function(tree, config){
34626 this.allowParentInsert = false;
34627 this.allowContainerDrop = false;
34628 this.appendOnly = false;
34629 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34631 this.lastInsertClass = "x-tree-no-status";
34632 this.dragOverData = {};
34635 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34636 ddGroup : "TreeDD",
34639 expandDelay : 1000,
34641 expandNode : function(node){
34642 if(node.hasChildNodes() && !node.isExpanded()){
34643 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34647 queueExpand : function(node){
34648 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34651 cancelExpand : function(){
34652 if(this.expandProcId){
34653 clearTimeout(this.expandProcId);
34654 this.expandProcId = false;
34658 isValidDropPoint : function(n, pt, dd, e, data){
34659 if(!n || !data){ return false; }
34660 var targetNode = n.node;
34661 var dropNode = data.node;
34662 // default drop rules
34663 if(!(targetNode && targetNode.isTarget && pt)){
34666 if(pt == "append" && targetNode.allowChildren === false){
34669 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34672 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34675 // reuse the object
34676 var overEvent = this.dragOverData;
34677 overEvent.tree = this.tree;
34678 overEvent.target = targetNode;
34679 overEvent.data = data;
34680 overEvent.point = pt;
34681 overEvent.source = dd;
34682 overEvent.rawEvent = e;
34683 overEvent.dropNode = dropNode;
34684 overEvent.cancel = false;
34685 var result = this.tree.fireEvent("nodedragover", overEvent);
34686 return overEvent.cancel === false && result !== false;
34689 getDropPoint : function(e, n, dd)
34693 return tn.allowChildren !== false ? "append" : false; // always append for root
34695 var dragEl = n.ddel;
34696 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34697 var y = Roo.lib.Event.getPageY(e);
34698 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34700 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34701 var noAppend = tn.allowChildren === false;
34702 if(this.appendOnly || tn.parentNode.allowChildren === false){
34703 return noAppend ? false : "append";
34705 var noBelow = false;
34706 if(!this.allowParentInsert){
34707 noBelow = tn.hasChildNodes() && tn.isExpanded();
34709 var q = (b - t) / (noAppend ? 2 : 3);
34710 if(y >= t && y < (t + q)){
34712 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34719 onNodeEnter : function(n, dd, e, data)
34721 this.cancelExpand();
34724 onNodeOver : function(n, dd, e, data)
34727 var pt = this.getDropPoint(e, n, dd);
34730 // auto node expand check
34731 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34732 this.queueExpand(node);
34733 }else if(pt != "append"){
34734 this.cancelExpand();
34737 // set the insert point style on the target node
34738 var returnCls = this.dropNotAllowed;
34739 if(this.isValidDropPoint(n, pt, dd, e, data)){
34744 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34745 cls = "x-tree-drag-insert-above";
34746 }else if(pt == "below"){
34747 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34748 cls = "x-tree-drag-insert-below";
34750 returnCls = "x-tree-drop-ok-append";
34751 cls = "x-tree-drag-append";
34753 if(this.lastInsertClass != cls){
34754 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34755 this.lastInsertClass = cls;
34762 onNodeOut : function(n, dd, e, data){
34764 this.cancelExpand();
34765 this.removeDropIndicators(n);
34768 onNodeDrop : function(n, dd, e, data){
34769 var point = this.getDropPoint(e, n, dd);
34770 var targetNode = n.node;
34771 targetNode.ui.startDrop();
34772 if(!this.isValidDropPoint(n, point, dd, e, data)){
34773 targetNode.ui.endDrop();
34776 // first try to find the drop node
34777 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34780 target: targetNode,
34785 dropNode: dropNode,
34788 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34789 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34790 targetNode.ui.endDrop();
34793 // allow target changing
34794 targetNode = dropEvent.target;
34795 if(point == "append" && !targetNode.isExpanded()){
34796 targetNode.expand(false, null, function(){
34797 this.completeDrop(dropEvent);
34798 }.createDelegate(this));
34800 this.completeDrop(dropEvent);
34805 completeDrop : function(de){
34806 var ns = de.dropNode, p = de.point, t = de.target;
34807 if(!(ns instanceof Array)){
34811 for(var i = 0, len = ns.length; i < len; i++){
34814 t.parentNode.insertBefore(n, t);
34815 }else if(p == "below"){
34816 t.parentNode.insertBefore(n, t.nextSibling);
34822 if(this.tree.hlDrop){
34826 this.tree.fireEvent("nodedrop", de);
34829 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34830 if(this.tree.hlDrop){
34831 dropNode.ui.focus();
34832 dropNode.ui.highlight();
34834 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34837 getTree : function(){
34841 removeDropIndicators : function(n){
34844 Roo.fly(el).removeClass([
34845 "x-tree-drag-insert-above",
34846 "x-tree-drag-insert-below",
34847 "x-tree-drag-append"]);
34848 this.lastInsertClass = "_noclass";
34852 beforeDragDrop : function(target, e, id){
34853 this.cancelExpand();
34857 afterRepair : function(data){
34858 if(data && Roo.enableFx){
34859 data.node.ui.highlight();
34869 * Ext JS Library 1.1.1
34870 * Copyright(c) 2006-2007, Ext JS, LLC.
34872 * Originally Released Under LGPL - original licence link has changed is not relivant.
34875 * <script type="text/javascript">
34879 if(Roo.dd.DragZone){
34880 Roo.tree.TreeDragZone = function(tree, config){
34881 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34885 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34886 ddGroup : "TreeDD",
34888 onBeforeDrag : function(data, e){
34890 return n && n.draggable && !n.disabled;
34894 onInitDrag : function(e){
34895 var data = this.dragData;
34896 this.tree.getSelectionModel().select(data.node);
34897 this.proxy.update("");
34898 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34899 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34902 getRepairXY : function(e, data){
34903 return data.node.ui.getDDRepairXY();
34906 onEndDrag : function(data, e){
34907 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34912 onValidDrop : function(dd, e, id){
34913 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34917 beforeInvalidDrop : function(e, id){
34918 // this scrolls the original position back into view
34919 var sm = this.tree.getSelectionModel();
34920 sm.clearSelections();
34921 sm.select(this.dragData.node);
34926 * Ext JS Library 1.1.1
34927 * Copyright(c) 2006-2007, Ext JS, LLC.
34929 * Originally Released Under LGPL - original licence link has changed is not relivant.
34932 * <script type="text/javascript">
34935 * @class Roo.tree.TreeEditor
34936 * @extends Roo.Editor
34937 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34938 * as the editor field.
34940 * @param {Object} config (used to be the tree panel.)
34941 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34943 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34944 * @cfg {Roo.form.TextField|Object} field The field configuration
34948 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34951 if (oldconfig) { // old style..
34952 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34955 tree = config.tree;
34956 config.field = config.field || {};
34957 config.field.xtype = 'TextField';
34958 field = Roo.factory(config.field, Roo.form);
34960 config = config || {};
34965 * @event beforenodeedit
34966 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34967 * false from the handler of this event.
34968 * @param {Editor} this
34969 * @param {Roo.tree.Node} node
34971 "beforenodeedit" : true
34975 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34979 tree.on('beforeclick', this.beforeNodeClick, this);
34980 tree.getTreeEl().on('mousedown', this.hide, this);
34981 this.on('complete', this.updateNode, this);
34982 this.on('beforestartedit', this.fitToTree, this);
34983 this.on('startedit', this.bindScroll, this, {delay:10});
34984 this.on('specialkey', this.onSpecialKey, this);
34987 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34989 * @cfg {String} alignment
34990 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34996 * @cfg {Boolean} hideEl
34997 * True to hide the bound element while the editor is displayed (defaults to false)
35001 * @cfg {String} cls
35002 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35004 cls: "x-small-editor x-tree-editor",
35006 * @cfg {Boolean} shim
35007 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35013 * @cfg {Number} maxWidth
35014 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35015 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35016 * scroll and client offsets into account prior to each edit.
35023 fitToTree : function(ed, el){
35024 var td = this.tree.getTreeEl().dom, nd = el.dom;
35025 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35026 td.scrollLeft = nd.offsetLeft;
35030 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35031 this.setSize(w, '');
35033 return this.fireEvent('beforenodeedit', this, this.editNode);
35038 triggerEdit : function(node){
35039 this.completeEdit();
35040 this.editNode = node;
35041 this.startEdit(node.ui.textNode, node.text);
35045 bindScroll : function(){
35046 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35050 beforeNodeClick : function(node, e){
35051 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35052 this.lastClick = new Date();
35053 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35055 this.triggerEdit(node);
35062 updateNode : function(ed, value){
35063 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35064 this.editNode.setText(value);
35068 onHide : function(){
35069 Roo.tree.TreeEditor.superclass.onHide.call(this);
35071 this.editNode.ui.focus();
35076 onSpecialKey : function(field, e){
35077 var k = e.getKey();
35081 }else if(k == e.ENTER && !e.hasModifier()){
35083 this.completeEdit();
35086 });//<Script type="text/javascript">
35089 * Ext JS Library 1.1.1
35090 * Copyright(c) 2006-2007, Ext JS, LLC.
35092 * Originally Released Under LGPL - original licence link has changed is not relivant.
35095 * <script type="text/javascript">
35099 * Not documented??? - probably should be...
35102 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35103 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35105 renderElements : function(n, a, targetNode, bulkRender){
35106 //consel.log("renderElements?");
35107 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35109 var t = n.getOwnerTree();
35110 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35112 var cols = t.columns;
35113 var bw = t.borderWidth;
35115 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35116 var cb = typeof a.checked == "boolean";
35117 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35118 var colcls = 'x-t-' + tid + '-c0';
35120 '<li class="x-tree-node">',
35123 '<div class="x-tree-node-el ', a.cls,'">',
35125 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35128 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35129 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35130 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35131 (a.icon ? ' x-tree-node-inline-icon' : ''),
35132 (a.iconCls ? ' '+a.iconCls : ''),
35133 '" unselectable="on" />',
35134 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35135 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35137 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35138 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35139 '<span unselectable="on" qtip="' + tx + '">',
35143 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35144 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35146 for(var i = 1, len = cols.length; i < len; i++){
35148 colcls = 'x-t-' + tid + '-c' +i;
35149 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35150 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35151 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35157 '<div class="x-clear"></div></div>',
35158 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35161 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35162 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35163 n.nextSibling.ui.getEl(), buf.join(""));
35165 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35167 var el = this.wrap.firstChild;
35169 this.elNode = el.firstChild;
35170 this.ranchor = el.childNodes[1];
35171 this.ctNode = this.wrap.childNodes[1];
35172 var cs = el.firstChild.childNodes;
35173 this.indentNode = cs[0];
35174 this.ecNode = cs[1];
35175 this.iconNode = cs[2];
35178 this.checkbox = cs[3];
35181 this.anchor = cs[index];
35183 this.textNode = cs[index].firstChild;
35185 //el.on("click", this.onClick, this);
35186 //el.on("dblclick", this.onDblClick, this);
35189 // console.log(this);
35191 initEvents : function(){
35192 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35195 var a = this.ranchor;
35197 var el = Roo.get(a);
35199 if(Roo.isOpera){ // opera render bug ignores the CSS
35200 el.setStyle("text-decoration", "none");
35203 el.on("click", this.onClick, this);
35204 el.on("dblclick", this.onDblClick, this);
35205 el.on("contextmenu", this.onContextMenu, this);
35209 /*onSelectedChange : function(state){
35212 this.addClass("x-tree-selected");
35215 this.removeClass("x-tree-selected");
35218 addClass : function(cls){
35220 Roo.fly(this.elRow).addClass(cls);
35226 removeClass : function(cls){
35228 Roo.fly(this.elRow).removeClass(cls);
35234 });//<Script type="text/javascript">
35238 * Ext JS Library 1.1.1
35239 * Copyright(c) 2006-2007, Ext JS, LLC.
35241 * Originally Released Under LGPL - original licence link has changed is not relivant.
35244 * <script type="text/javascript">
35249 * @class Roo.tree.ColumnTree
35250 * @extends Roo.data.TreePanel
35251 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35252 * @cfg {int} borderWidth compined right/left border allowance
35254 * @param {String/HTMLElement/Element} el The container element
35255 * @param {Object} config
35257 Roo.tree.ColumnTree = function(el, config)
35259 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35263 * Fire this event on a container when it resizes
35264 * @param {int} w Width
35265 * @param {int} h Height
35269 this.on('resize', this.onResize, this);
35272 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35276 borderWidth: Roo.isBorderBox ? 0 : 2,
35279 render : function(){
35280 // add the header.....
35282 Roo.tree.ColumnTree.superclass.render.apply(this);
35284 this.el.addClass('x-column-tree');
35286 this.headers = this.el.createChild(
35287 {cls:'x-tree-headers'},this.innerCt.dom);
35289 var cols = this.columns, c;
35290 var totalWidth = 0;
35292 var len = cols.length;
35293 for(var i = 0; i < len; i++){
35295 totalWidth += c.width;
35296 this.headEls.push(this.headers.createChild({
35297 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35299 cls:'x-tree-hd-text',
35302 style:'width:'+(c.width-this.borderWidth)+'px;'
35305 this.headers.createChild({cls:'x-clear'});
35306 // prevent floats from wrapping when clipped
35307 this.headers.setWidth(totalWidth);
35308 //this.innerCt.setWidth(totalWidth);
35309 this.innerCt.setStyle({ overflow: 'auto' });
35310 this.onResize(this.width, this.height);
35314 onResize : function(w,h)
35319 this.innerCt.setWidth(this.width);
35320 this.innerCt.setHeight(this.height-20);
35323 var cols = this.columns, c;
35324 var totalWidth = 0;
35326 var len = cols.length;
35327 for(var i = 0; i < len; i++){
35329 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35330 // it's the expander..
35331 expEl = this.headEls[i];
35334 totalWidth += c.width;
35338 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35340 this.headers.setWidth(w-20);
35349 * Ext JS Library 1.1.1
35350 * Copyright(c) 2006-2007, Ext JS, LLC.
35352 * Originally Released Under LGPL - original licence link has changed is not relivant.
35355 * <script type="text/javascript">
35359 * @class Roo.menu.Menu
35360 * @extends Roo.util.Observable
35361 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35362 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35364 * Creates a new Menu
35365 * @param {Object} config Configuration options
35367 Roo.menu.Menu = function(config){
35368 Roo.apply(this, config);
35369 this.id = this.id || Roo.id();
35372 * @event beforeshow
35373 * Fires before this menu is displayed
35374 * @param {Roo.menu.Menu} this
35378 * @event beforehide
35379 * Fires before this menu is hidden
35380 * @param {Roo.menu.Menu} this
35385 * Fires after this menu is displayed
35386 * @param {Roo.menu.Menu} this
35391 * Fires after this menu is hidden
35392 * @param {Roo.menu.Menu} this
35397 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35398 * @param {Roo.menu.Menu} this
35399 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35400 * @param {Roo.EventObject} e
35405 * Fires when the mouse is hovering over this menu
35406 * @param {Roo.menu.Menu} this
35407 * @param {Roo.EventObject} e
35408 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35413 * Fires when the mouse exits this menu
35414 * @param {Roo.menu.Menu} this
35415 * @param {Roo.EventObject} e
35416 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35421 * Fires when a menu item contained in this menu is clicked
35422 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35423 * @param {Roo.EventObject} e
35427 if (this.registerMenu) {
35428 Roo.menu.MenuMgr.register(this);
35431 var mis = this.items;
35432 this.items = new Roo.util.MixedCollection();
35434 this.add.apply(this, mis);
35438 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35440 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35444 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35445 * for bottom-right shadow (defaults to "sides")
35449 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35450 * this menu (defaults to "tl-tr?")
35452 subMenuAlign : "tl-tr?",
35454 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35455 * relative to its element of origin (defaults to "tl-bl?")
35457 defaultAlign : "tl-bl?",
35459 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35461 allowOtherMenus : false,
35463 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35465 registerMenu : true,
35470 render : function(){
35474 var el = this.el = new Roo.Layer({
35476 shadow:this.shadow,
35478 parentEl: this.parentEl || document.body,
35482 this.keyNav = new Roo.menu.MenuNav(this);
35485 el.addClass("x-menu-plain");
35488 el.addClass(this.cls);
35490 // generic focus element
35491 this.focusEl = el.createChild({
35492 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35494 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35495 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35497 ul.on("mouseover", this.onMouseOver, this);
35498 ul.on("mouseout", this.onMouseOut, this);
35499 this.items.each(function(item){
35504 var li = document.createElement("li");
35505 li.className = "x-menu-list-item";
35506 ul.dom.appendChild(li);
35507 item.render(li, this);
35514 autoWidth : function(){
35515 var el = this.el, ul = this.ul;
35519 var w = this.width;
35522 }else if(Roo.isIE){
35523 el.setWidth(this.minWidth);
35524 var t = el.dom.offsetWidth; // force recalc
35525 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35530 delayAutoWidth : function(){
35533 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35535 this.awTask.delay(20);
35540 findTargetItem : function(e){
35541 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35542 if(t && t.menuItemId){
35543 return this.items.get(t.menuItemId);
35548 onClick : function(e){
35549 Roo.log("menu.onClick");
35550 var t = this.findTargetItem(e);
35555 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35556 if(t == this.activeItem && t.shouldDeactivate(e)){
35557 this.activeItem.deactivate();
35558 delete this.activeItem;
35562 this.setActiveItem(t, true);
35570 this.fireEvent("click", this, t, e);
35574 setActiveItem : function(item, autoExpand){
35575 if(item != this.activeItem){
35576 if(this.activeItem){
35577 this.activeItem.deactivate();
35579 this.activeItem = item;
35580 item.activate(autoExpand);
35581 }else if(autoExpand){
35587 tryActivate : function(start, step){
35588 var items = this.items;
35589 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35590 var item = items.get(i);
35591 if(!item.disabled && item.canActivate){
35592 this.setActiveItem(item, false);
35600 onMouseOver : function(e){
35602 if(t = this.findTargetItem(e)){
35603 if(t.canActivate && !t.disabled){
35604 this.setActiveItem(t, true);
35607 this.fireEvent("mouseover", this, e, t);
35611 onMouseOut : function(e){
35613 if(t = this.findTargetItem(e)){
35614 if(t == this.activeItem && t.shouldDeactivate(e)){
35615 this.activeItem.deactivate();
35616 delete this.activeItem;
35619 this.fireEvent("mouseout", this, e, t);
35623 * Read-only. Returns true if the menu is currently displayed, else false.
35626 isVisible : function(){
35627 return this.el && !this.hidden;
35631 * Displays this menu relative to another element
35632 * @param {String/HTMLElement/Roo.Element} element The element to align to
35633 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35634 * the element (defaults to this.defaultAlign)
35635 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35637 show : function(el, pos, parentMenu){
35638 this.parentMenu = parentMenu;
35642 this.fireEvent("beforeshow", this);
35643 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35647 * Displays this menu at a specific xy position
35648 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35649 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35651 showAt : function(xy, parentMenu, /* private: */_e){
35652 this.parentMenu = parentMenu;
35657 this.fireEvent("beforeshow", this);
35658 xy = this.el.adjustForConstraints(xy);
35662 this.hidden = false;
35664 this.fireEvent("show", this);
35667 focus : function(){
35669 this.doFocus.defer(50, this);
35673 doFocus : function(){
35675 this.focusEl.focus();
35680 * Hides this menu and optionally all parent menus
35681 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35683 hide : function(deep){
35684 if(this.el && this.isVisible()){
35685 this.fireEvent("beforehide", this);
35686 if(this.activeItem){
35687 this.activeItem.deactivate();
35688 this.activeItem = null;
35691 this.hidden = true;
35692 this.fireEvent("hide", this);
35694 if(deep === true && this.parentMenu){
35695 this.parentMenu.hide(true);
35700 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35701 * Any of the following are valid:
35703 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35704 * <li>An HTMLElement object which will be converted to a menu item</li>
35705 * <li>A menu item config object that will be created as a new menu item</li>
35706 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35707 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35712 var menu = new Roo.menu.Menu();
35714 // Create a menu item to add by reference
35715 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35717 // Add a bunch of items at once using different methods.
35718 // Only the last item added will be returned.
35719 var item = menu.add(
35720 menuItem, // add existing item by ref
35721 'Dynamic Item', // new TextItem
35722 '-', // new separator
35723 { text: 'Config Item' } // new item by config
35726 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35727 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35730 var a = arguments, l = a.length, item;
35731 for(var i = 0; i < l; i++){
35733 if ((typeof(el) == "object") && el.xtype && el.xns) {
35734 el = Roo.factory(el, Roo.menu);
35737 if(el.render){ // some kind of Item
35738 item = this.addItem(el);
35739 }else if(typeof el == "string"){ // string
35740 if(el == "separator" || el == "-"){
35741 item = this.addSeparator();
35743 item = this.addText(el);
35745 }else if(el.tagName || el.el){ // element
35746 item = this.addElement(el);
35747 }else if(typeof el == "object"){ // must be menu item config?
35748 item = this.addMenuItem(el);
35755 * Returns this menu's underlying {@link Roo.Element} object
35756 * @return {Roo.Element} The element
35758 getEl : function(){
35766 * Adds a separator bar to the menu
35767 * @return {Roo.menu.Item} The menu item that was added
35769 addSeparator : function(){
35770 return this.addItem(new Roo.menu.Separator());
35774 * Adds an {@link Roo.Element} object to the menu
35775 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35776 * @return {Roo.menu.Item} The menu item that was added
35778 addElement : function(el){
35779 return this.addItem(new Roo.menu.BaseItem(el));
35783 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35784 * @param {Roo.menu.Item} item The menu item to add
35785 * @return {Roo.menu.Item} The menu item that was added
35787 addItem : function(item){
35788 this.items.add(item);
35790 var li = document.createElement("li");
35791 li.className = "x-menu-list-item";
35792 this.ul.dom.appendChild(li);
35793 item.render(li, this);
35794 this.delayAutoWidth();
35800 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35801 * @param {Object} config A MenuItem config object
35802 * @return {Roo.menu.Item} The menu item that was added
35804 addMenuItem : function(config){
35805 if(!(config instanceof Roo.menu.Item)){
35806 if(typeof config.checked == "boolean"){ // must be check menu item config?
35807 config = new Roo.menu.CheckItem(config);
35809 config = new Roo.menu.Item(config);
35812 return this.addItem(config);
35816 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35817 * @param {String} text The text to display in the menu item
35818 * @return {Roo.menu.Item} The menu item that was added
35820 addText : function(text){
35821 return this.addItem(new Roo.menu.TextItem({ text : text }));
35825 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35826 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35827 * @param {Roo.menu.Item} item The menu item to add
35828 * @return {Roo.menu.Item} The menu item that was added
35830 insert : function(index, item){
35831 this.items.insert(index, item);
35833 var li = document.createElement("li");
35834 li.className = "x-menu-list-item";
35835 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35836 item.render(li, this);
35837 this.delayAutoWidth();
35843 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35844 * @param {Roo.menu.Item} item The menu item to remove
35846 remove : function(item){
35847 this.items.removeKey(item.id);
35852 * Removes and destroys all items in the menu
35854 removeAll : function(){
35856 while(f = this.items.first()){
35862 // MenuNav is a private utility class used internally by the Menu
35863 Roo.menu.MenuNav = function(menu){
35864 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35865 this.scope = this.menu = menu;
35868 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35869 doRelay : function(e, h){
35870 var k = e.getKey();
35871 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35872 this.menu.tryActivate(0, 1);
35875 return h.call(this.scope || this, e, this.menu);
35878 up : function(e, m){
35879 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35880 m.tryActivate(m.items.length-1, -1);
35884 down : function(e, m){
35885 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35886 m.tryActivate(0, 1);
35890 right : function(e, m){
35892 m.activeItem.expandMenu(true);
35896 left : function(e, m){
35898 if(m.parentMenu && m.parentMenu.activeItem){
35899 m.parentMenu.activeItem.activate();
35903 enter : function(e, m){
35905 e.stopPropagation();
35906 m.activeItem.onClick(e);
35907 m.fireEvent("click", this, m.activeItem);
35913 * Ext JS Library 1.1.1
35914 * Copyright(c) 2006-2007, Ext JS, LLC.
35916 * Originally Released Under LGPL - original licence link has changed is not relivant.
35919 * <script type="text/javascript">
35923 * @class Roo.menu.MenuMgr
35924 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35927 Roo.menu.MenuMgr = function(){
35928 var menus, active, groups = {}, attached = false, lastShow = new Date();
35930 // private - called when first menu is created
35933 active = new Roo.util.MixedCollection();
35934 Roo.get(document).addKeyListener(27, function(){
35935 if(active.length > 0){
35942 function hideAll(){
35943 if(active && active.length > 0){
35944 var c = active.clone();
35945 c.each(function(m){
35952 function onHide(m){
35954 if(active.length < 1){
35955 Roo.get(document).un("mousedown", onMouseDown);
35961 function onShow(m){
35962 var last = active.last();
35963 lastShow = new Date();
35966 Roo.get(document).on("mousedown", onMouseDown);
35970 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35971 m.parentMenu.activeChild = m;
35972 }else if(last && last.isVisible()){
35973 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35978 function onBeforeHide(m){
35980 m.activeChild.hide();
35982 if(m.autoHideTimer){
35983 clearTimeout(m.autoHideTimer);
35984 delete m.autoHideTimer;
35989 function onBeforeShow(m){
35990 var pm = m.parentMenu;
35991 if(!pm && !m.allowOtherMenus){
35993 }else if(pm && pm.activeChild && active != m){
35994 pm.activeChild.hide();
35999 function onMouseDown(e){
36000 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36006 function onBeforeCheck(mi, state){
36008 var g = groups[mi.group];
36009 for(var i = 0, l = g.length; i < l; i++){
36011 g[i].setChecked(false);
36020 * Hides all menus that are currently visible
36022 hideAll : function(){
36027 register : function(menu){
36031 menus[menu.id] = menu;
36032 menu.on("beforehide", onBeforeHide);
36033 menu.on("hide", onHide);
36034 menu.on("beforeshow", onBeforeShow);
36035 menu.on("show", onShow);
36036 var g = menu.group;
36037 if(g && menu.events["checkchange"]){
36041 groups[g].push(menu);
36042 menu.on("checkchange", onCheck);
36047 * Returns a {@link Roo.menu.Menu} object
36048 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36049 * be used to generate and return a new Menu instance.
36051 get : function(menu){
36052 if(typeof menu == "string"){ // menu id
36053 return menus[menu];
36054 }else if(menu.events){ // menu instance
36056 }else if(typeof menu.length == 'number'){ // array of menu items?
36057 return new Roo.menu.Menu({items:menu});
36058 }else{ // otherwise, must be a config
36059 return new Roo.menu.Menu(menu);
36064 unregister : function(menu){
36065 delete menus[menu.id];
36066 menu.un("beforehide", onBeforeHide);
36067 menu.un("hide", onHide);
36068 menu.un("beforeshow", onBeforeShow);
36069 menu.un("show", onShow);
36070 var g = menu.group;
36071 if(g && menu.events["checkchange"]){
36072 groups[g].remove(menu);
36073 menu.un("checkchange", onCheck);
36078 registerCheckable : function(menuItem){
36079 var g = menuItem.group;
36084 groups[g].push(menuItem);
36085 menuItem.on("beforecheckchange", onBeforeCheck);
36090 unregisterCheckable : function(menuItem){
36091 var g = menuItem.group;
36093 groups[g].remove(menuItem);
36094 menuItem.un("beforecheckchange", onBeforeCheck);
36100 * Ext JS Library 1.1.1
36101 * Copyright(c) 2006-2007, Ext JS, LLC.
36103 * Originally Released Under LGPL - original licence link has changed is not relivant.
36106 * <script type="text/javascript">
36111 * @class Roo.menu.BaseItem
36112 * @extends Roo.Component
36113 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36114 * management and base configuration options shared by all menu components.
36116 * Creates a new BaseItem
36117 * @param {Object} config Configuration options
36119 Roo.menu.BaseItem = function(config){
36120 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36125 * Fires when this item is clicked
36126 * @param {Roo.menu.BaseItem} this
36127 * @param {Roo.EventObject} e
36132 * Fires when this item is activated
36133 * @param {Roo.menu.BaseItem} this
36137 * @event deactivate
36138 * Fires when this item is deactivated
36139 * @param {Roo.menu.BaseItem} this
36145 this.on("click", this.handler, this.scope, true);
36149 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36151 * @cfg {Function} handler
36152 * A function that will handle the click event of this menu item (defaults to undefined)
36155 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36157 canActivate : false,
36160 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36165 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36167 activeClass : "x-menu-item-active",
36169 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36171 hideOnClick : true,
36173 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36178 ctype: "Roo.menu.BaseItem",
36181 actionMode : "container",
36184 render : function(container, parentMenu){
36185 this.parentMenu = parentMenu;
36186 Roo.menu.BaseItem.superclass.render.call(this, container);
36187 this.container.menuItemId = this.id;
36191 onRender : function(container, position){
36192 this.el = Roo.get(this.el);
36193 container.dom.appendChild(this.el.dom);
36197 onClick : function(e){
36198 if(!this.disabled && this.fireEvent("click", this, e) !== false
36199 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36200 this.handleClick(e);
36207 activate : function(){
36211 var li = this.container;
36212 li.addClass(this.activeClass);
36213 this.region = li.getRegion().adjust(2, 2, -2, -2);
36214 this.fireEvent("activate", this);
36219 deactivate : function(){
36220 this.container.removeClass(this.activeClass);
36221 this.fireEvent("deactivate", this);
36225 shouldDeactivate : function(e){
36226 return !this.region || !this.region.contains(e.getPoint());
36230 handleClick : function(e){
36231 if(this.hideOnClick){
36232 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36237 expandMenu : function(autoActivate){
36242 hideMenu : function(){
36247 * Ext JS Library 1.1.1
36248 * Copyright(c) 2006-2007, Ext JS, LLC.
36250 * Originally Released Under LGPL - original licence link has changed is not relivant.
36253 * <script type="text/javascript">
36257 * @class Roo.menu.Adapter
36258 * @extends Roo.menu.BaseItem
36259 * 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.
36260 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36262 * Creates a new Adapter
36263 * @param {Object} config Configuration options
36265 Roo.menu.Adapter = function(component, config){
36266 Roo.menu.Adapter.superclass.constructor.call(this, config);
36267 this.component = component;
36269 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36271 canActivate : true,
36274 onRender : function(container, position){
36275 this.component.render(container);
36276 this.el = this.component.getEl();
36280 activate : function(){
36284 this.component.focus();
36285 this.fireEvent("activate", this);
36290 deactivate : function(){
36291 this.fireEvent("deactivate", this);
36295 disable : function(){
36296 this.component.disable();
36297 Roo.menu.Adapter.superclass.disable.call(this);
36301 enable : function(){
36302 this.component.enable();
36303 Roo.menu.Adapter.superclass.enable.call(this);
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.TextItem
36318 * @extends Roo.menu.BaseItem
36319 * Adds a static text string to a menu, usually used as either a heading or group separator.
36320 * Note: old style constructor with text is still supported.
36323 * Creates a new TextItem
36324 * @param {Object} cfg Configuration
36326 Roo.menu.TextItem = function(cfg){
36327 if (typeof(cfg) == 'string') {
36330 Roo.apply(this,cfg);
36333 Roo.menu.TextItem.superclass.constructor.call(this);
36336 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36338 * @cfg {Boolean} text Text to show on item.
36343 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36345 hideOnClick : false,
36347 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36349 itemCls : "x-menu-text",
36352 onRender : function(){
36353 var s = document.createElement("span");
36354 s.className = this.itemCls;
36355 s.innerHTML = this.text;
36357 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36361 * Ext JS Library 1.1.1
36362 * Copyright(c) 2006-2007, Ext JS, LLC.
36364 * Originally Released Under LGPL - original licence link has changed is not relivant.
36367 * <script type="text/javascript">
36371 * @class Roo.menu.Separator
36372 * @extends Roo.menu.BaseItem
36373 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36374 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36376 * @param {Object} config Configuration options
36378 Roo.menu.Separator = function(config){
36379 Roo.menu.Separator.superclass.constructor.call(this, config);
36382 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36384 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36386 itemCls : "x-menu-sep",
36388 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36390 hideOnClick : false,
36393 onRender : function(li){
36394 var s = document.createElement("span");
36395 s.className = this.itemCls;
36396 s.innerHTML = " ";
36398 li.addClass("x-menu-sep-li");
36399 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36403 * Ext JS Library 1.1.1
36404 * Copyright(c) 2006-2007, Ext JS, LLC.
36406 * Originally Released Under LGPL - original licence link has changed is not relivant.
36409 * <script type="text/javascript">
36412 * @class Roo.menu.Item
36413 * @extends Roo.menu.BaseItem
36414 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36415 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36416 * activation and click handling.
36418 * Creates a new Item
36419 * @param {Object} config Configuration options
36421 Roo.menu.Item = function(config){
36422 Roo.menu.Item.superclass.constructor.call(this, config);
36424 this.menu = Roo.menu.MenuMgr.get(this.menu);
36427 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36430 * @cfg {String} text
36431 * The text to show on the menu item.
36435 * @cfg {String} HTML to render in menu
36436 * The text to show on the menu item (HTML version).
36440 * @cfg {String} icon
36441 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36445 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36447 itemCls : "x-menu-item",
36449 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36451 canActivate : true,
36453 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36456 // doc'd in BaseItem
36460 ctype: "Roo.menu.Item",
36463 onRender : function(container, position){
36464 var el = document.createElement("a");
36465 el.hideFocus = true;
36466 el.unselectable = "on";
36467 el.href = this.href || "#";
36468 if(this.hrefTarget){
36469 el.target = this.hrefTarget;
36471 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36473 var html = this.html.length ? this.html : String.format('{0}',this.text);
36475 el.innerHTML = String.format(
36476 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36477 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36479 Roo.menu.Item.superclass.onRender.call(this, container, position);
36483 * Sets the text to display in this menu item
36484 * @param {String} text The text to display
36485 * @param {Boolean} isHTML true to indicate text is pure html.
36487 setText : function(text, isHTML){
36495 var html = this.html.length ? this.html : String.format('{0}',this.text);
36497 this.el.update(String.format(
36498 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36499 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36500 this.parentMenu.autoWidth();
36505 handleClick : function(e){
36506 if(!this.href){ // if no link defined, stop the event automatically
36509 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36513 activate : function(autoExpand){
36514 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36524 shouldDeactivate : function(e){
36525 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36526 if(this.menu && this.menu.isVisible()){
36527 return !this.menu.getEl().getRegion().contains(e.getPoint());
36535 deactivate : function(){
36536 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36541 expandMenu : function(autoActivate){
36542 if(!this.disabled && this.menu){
36543 clearTimeout(this.hideTimer);
36544 delete this.hideTimer;
36545 if(!this.menu.isVisible() && !this.showTimer){
36546 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36547 }else if (this.menu.isVisible() && autoActivate){
36548 this.menu.tryActivate(0, 1);
36554 deferExpand : function(autoActivate){
36555 delete this.showTimer;
36556 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36558 this.menu.tryActivate(0, 1);
36563 hideMenu : function(){
36564 clearTimeout(this.showTimer);
36565 delete this.showTimer;
36566 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36567 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36572 deferHide : function(){
36573 delete this.hideTimer;
36578 * Ext JS Library 1.1.1
36579 * Copyright(c) 2006-2007, Ext JS, LLC.
36581 * Originally Released Under LGPL - original licence link has changed is not relivant.
36584 * <script type="text/javascript">
36588 * @class Roo.menu.CheckItem
36589 * @extends Roo.menu.Item
36590 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36592 * Creates a new CheckItem
36593 * @param {Object} config Configuration options
36595 Roo.menu.CheckItem = function(config){
36596 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36599 * @event beforecheckchange
36600 * Fires before the checked value is set, providing an opportunity to cancel if needed
36601 * @param {Roo.menu.CheckItem} this
36602 * @param {Boolean} checked The new checked value that will be set
36604 "beforecheckchange" : true,
36606 * @event checkchange
36607 * Fires after the checked value has been set
36608 * @param {Roo.menu.CheckItem} this
36609 * @param {Boolean} checked The checked value that was set
36611 "checkchange" : true
36613 if(this.checkHandler){
36614 this.on('checkchange', this.checkHandler, this.scope);
36617 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36619 * @cfg {String} group
36620 * All check items with the same group name will automatically be grouped into a single-select
36621 * radio button group (defaults to '')
36624 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36626 itemCls : "x-menu-item x-menu-check-item",
36628 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36630 groupClass : "x-menu-group-item",
36633 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36634 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36635 * initialized with checked = true will be rendered as checked.
36640 ctype: "Roo.menu.CheckItem",
36643 onRender : function(c){
36644 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36646 this.el.addClass(this.groupClass);
36648 Roo.menu.MenuMgr.registerCheckable(this);
36650 this.checked = false;
36651 this.setChecked(true, true);
36656 destroy : function(){
36658 Roo.menu.MenuMgr.unregisterCheckable(this);
36660 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36664 * Set the checked state of this item
36665 * @param {Boolean} checked The new checked value
36666 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36668 setChecked : function(state, suppressEvent){
36669 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36670 if(this.container){
36671 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36673 this.checked = state;
36674 if(suppressEvent !== true){
36675 this.fireEvent("checkchange", this, state);
36681 handleClick : function(e){
36682 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36683 this.setChecked(!this.checked);
36685 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36689 * Ext JS Library 1.1.1
36690 * Copyright(c) 2006-2007, Ext JS, LLC.
36692 * Originally Released Under LGPL - original licence link has changed is not relivant.
36695 * <script type="text/javascript">
36699 * @class Roo.menu.DateItem
36700 * @extends Roo.menu.Adapter
36701 * A menu item that wraps the {@link Roo.DatPicker} component.
36703 * Creates a new DateItem
36704 * @param {Object} config Configuration options
36706 Roo.menu.DateItem = function(config){
36707 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36708 /** The Roo.DatePicker object @type Roo.DatePicker */
36709 this.picker = this.component;
36710 this.addEvents({select: true});
36712 this.picker.on("render", function(picker){
36713 picker.getEl().swallowEvent("click");
36714 picker.container.addClass("x-menu-date-item");
36717 this.picker.on("select", this.onSelect, this);
36720 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36722 onSelect : function(picker, date){
36723 this.fireEvent("select", this, date, picker);
36724 Roo.menu.DateItem.superclass.handleClick.call(this);
36728 * Ext JS Library 1.1.1
36729 * Copyright(c) 2006-2007, Ext JS, LLC.
36731 * Originally Released Under LGPL - original licence link has changed is not relivant.
36734 * <script type="text/javascript">
36738 * @class Roo.menu.ColorItem
36739 * @extends Roo.menu.Adapter
36740 * A menu item that wraps the {@link Roo.ColorPalette} component.
36742 * Creates a new ColorItem
36743 * @param {Object} config Configuration options
36745 Roo.menu.ColorItem = function(config){
36746 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36747 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36748 this.palette = this.component;
36749 this.relayEvents(this.palette, ["select"]);
36750 if(this.selectHandler){
36751 this.on('select', this.selectHandler, this.scope);
36754 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36756 * Ext JS Library 1.1.1
36757 * Copyright(c) 2006-2007, Ext JS, LLC.
36759 * Originally Released Under LGPL - original licence link has changed is not relivant.
36762 * <script type="text/javascript">
36767 * @class Roo.menu.DateMenu
36768 * @extends Roo.menu.Menu
36769 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36771 * Creates a new DateMenu
36772 * @param {Object} config Configuration options
36774 Roo.menu.DateMenu = function(config){
36775 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36777 var di = new Roo.menu.DateItem(config);
36780 * The {@link Roo.DatePicker} instance for this DateMenu
36783 this.picker = di.picker;
36786 * @param {DatePicker} picker
36787 * @param {Date} date
36789 this.relayEvents(di, ["select"]);
36790 this.on('beforeshow', function(){
36792 this.picker.hideMonthPicker(false);
36796 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36800 * Ext JS Library 1.1.1
36801 * Copyright(c) 2006-2007, Ext JS, LLC.
36803 * Originally Released Under LGPL - original licence link has changed is not relivant.
36806 * <script type="text/javascript">
36811 * @class Roo.menu.ColorMenu
36812 * @extends Roo.menu.Menu
36813 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36815 * Creates a new ColorMenu
36816 * @param {Object} config Configuration options
36818 Roo.menu.ColorMenu = function(config){
36819 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36821 var ci = new Roo.menu.ColorItem(config);
36824 * The {@link Roo.ColorPalette} instance for this ColorMenu
36825 * @type ColorPalette
36827 this.palette = ci.palette;
36830 * @param {ColorPalette} palette
36831 * @param {String} color
36833 this.relayEvents(ci, ["select"]);
36835 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36837 * Ext JS Library 1.1.1
36838 * Copyright(c) 2006-2007, Ext JS, LLC.
36840 * Originally Released Under LGPL - original licence link has changed is not relivant.
36843 * <script type="text/javascript">
36847 * @class Roo.form.Field
36848 * @extends Roo.BoxComponent
36849 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36851 * Creates a new Field
36852 * @param {Object} config Configuration options
36854 Roo.form.Field = function(config){
36855 Roo.form.Field.superclass.constructor.call(this, config);
36858 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36860 * @cfg {String} fieldLabel Label to use when rendering a form.
36863 * @cfg {String} qtip Mouse over tip
36867 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36869 invalidClass : "x-form-invalid",
36871 * @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")
36873 invalidText : "The value in this field is invalid",
36875 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36877 focusClass : "x-form-focus",
36879 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36880 automatic validation (defaults to "keyup").
36882 validationEvent : "keyup",
36884 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36886 validateOnBlur : true,
36888 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36890 validationDelay : 250,
36892 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36893 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36895 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36897 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36899 fieldClass : "x-form-field",
36901 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36904 ----------- ----------------------------------------------------------------------
36905 qtip Display a quick tip when the user hovers over the field
36906 title Display a default browser title attribute popup
36907 under Add a block div beneath the field containing the error text
36908 side Add an error icon to the right of the field with a popup on hover
36909 [element id] Add the error text directly to the innerHTML of the specified element
36912 msgTarget : 'qtip',
36914 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36919 * @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.
36924 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36929 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36931 inputType : undefined,
36934 * @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).
36936 tabIndex : undefined,
36939 isFormField : true,
36944 * @property {Roo.Element} fieldEl
36945 * Element Containing the rendered Field (with label etc.)
36948 * @cfg {Mixed} value A value to initialize this field with.
36953 * @cfg {String} name The field's HTML name attribute.
36956 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36960 initComponent : function(){
36961 Roo.form.Field.superclass.initComponent.call(this);
36965 * Fires when this field receives input focus.
36966 * @param {Roo.form.Field} this
36971 * Fires when this field loses input focus.
36972 * @param {Roo.form.Field} this
36976 * @event specialkey
36977 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36978 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36979 * @param {Roo.form.Field} this
36980 * @param {Roo.EventObject} e The event object
36985 * Fires just before the field blurs if the field value has changed.
36986 * @param {Roo.form.Field} this
36987 * @param {Mixed} newValue The new value
36988 * @param {Mixed} oldValue The original value
36993 * Fires after the field has been marked as invalid.
36994 * @param {Roo.form.Field} this
36995 * @param {String} msg The validation message
37000 * Fires after the field has been validated with no errors.
37001 * @param {Roo.form.Field} this
37006 * Fires after the key up
37007 * @param {Roo.form.Field} this
37008 * @param {Roo.EventObject} e The event Object
37015 * Returns the name attribute of the field if available
37016 * @return {String} name The field name
37018 getName: function(){
37019 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37023 onRender : function(ct, position){
37024 Roo.form.Field.superclass.onRender.call(this, ct, position);
37026 var cfg = this.getAutoCreate();
37028 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37030 if (!cfg.name.length) {
37033 if(this.inputType){
37034 cfg.type = this.inputType;
37036 this.el = ct.createChild(cfg, position);
37038 var type = this.el.dom.type;
37040 if(type == 'password'){
37043 this.el.addClass('x-form-'+type);
37046 this.el.dom.readOnly = true;
37048 if(this.tabIndex !== undefined){
37049 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37052 this.el.addClass([this.fieldClass, this.cls]);
37057 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37058 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37059 * @return {Roo.form.Field} this
37061 applyTo : function(target){
37062 this.allowDomMove = false;
37063 this.el = Roo.get(target);
37064 this.render(this.el.dom.parentNode);
37069 initValue : function(){
37070 if(this.value !== undefined){
37071 this.setValue(this.value);
37072 }else if(this.el.dom.value.length > 0){
37073 this.setValue(this.el.dom.value);
37078 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37080 isDirty : function() {
37081 if(this.disabled) {
37084 return String(this.getValue()) !== String(this.originalValue);
37088 afterRender : function(){
37089 Roo.form.Field.superclass.afterRender.call(this);
37094 fireKey : function(e){
37095 //Roo.log('field ' + e.getKey());
37096 if(e.isNavKeyPress()){
37097 this.fireEvent("specialkey", this, e);
37102 * Resets the current field value to the originally loaded value and clears any validation messages
37104 reset : function(){
37105 this.setValue(this.resetValue);
37106 this.clearInvalid();
37110 initEvents : function(){
37111 // safari killled keypress - so keydown is now used..
37112 this.el.on("keydown" , this.fireKey, this);
37113 this.el.on("focus", this.onFocus, this);
37114 this.el.on("blur", this.onBlur, this);
37115 this.el.relayEvent('keyup', this);
37117 // reference to original value for reset
37118 this.originalValue = this.getValue();
37119 this.resetValue = this.getValue();
37123 onFocus : function(){
37124 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37125 this.el.addClass(this.focusClass);
37127 if(!this.hasFocus){
37128 this.hasFocus = true;
37129 this.startValue = this.getValue();
37130 this.fireEvent("focus", this);
37134 beforeBlur : Roo.emptyFn,
37137 onBlur : function(){
37139 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37140 this.el.removeClass(this.focusClass);
37142 this.hasFocus = false;
37143 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37146 var v = this.getValue();
37147 if(String(v) !== String(this.startValue)){
37148 this.fireEvent('change', this, v, this.startValue);
37150 this.fireEvent("blur", this);
37154 * Returns whether or not the field value is currently valid
37155 * @param {Boolean} preventMark True to disable marking the field invalid
37156 * @return {Boolean} True if the value is valid, else false
37158 isValid : function(preventMark){
37162 var restore = this.preventMark;
37163 this.preventMark = preventMark === true;
37164 var v = this.validateValue(this.processValue(this.getRawValue()));
37165 this.preventMark = restore;
37170 * Validates the field value
37171 * @return {Boolean} True if the value is valid, else false
37173 validate : function(){
37174 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37175 this.clearInvalid();
37181 processValue : function(value){
37186 // Subclasses should provide the validation implementation by overriding this
37187 validateValue : function(value){
37192 * Mark this field as invalid
37193 * @param {String} msg The validation message
37195 markInvalid : function(msg){
37196 if(!this.rendered || this.preventMark){ // not rendered
37200 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37202 obj.el.addClass(this.invalidClass);
37203 msg = msg || this.invalidText;
37204 switch(this.msgTarget){
37206 obj.el.dom.qtip = msg;
37207 obj.el.dom.qclass = 'x-form-invalid-tip';
37208 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37209 Roo.QuickTips.enable();
37213 this.el.dom.title = msg;
37217 var elp = this.el.findParent('.x-form-element', 5, true);
37218 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37219 this.errorEl.setWidth(elp.getWidth(true)-20);
37221 this.errorEl.update(msg);
37222 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37225 if(!this.errorIcon){
37226 var elp = this.el.findParent('.x-form-element', 5, true);
37227 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37229 this.alignErrorIcon();
37230 this.errorIcon.dom.qtip = msg;
37231 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37232 this.errorIcon.show();
37233 this.on('resize', this.alignErrorIcon, this);
37236 var t = Roo.getDom(this.msgTarget);
37238 t.style.display = this.msgDisplay;
37241 this.fireEvent('invalid', this, msg);
37245 alignErrorIcon : function(){
37246 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37250 * Clear any invalid styles/messages for this field
37252 clearInvalid : function(){
37253 if(!this.rendered || this.preventMark){ // not rendered
37256 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37258 obj.el.removeClass(this.invalidClass);
37259 switch(this.msgTarget){
37261 obj.el.dom.qtip = '';
37264 this.el.dom.title = '';
37268 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37272 if(this.errorIcon){
37273 this.errorIcon.dom.qtip = '';
37274 this.errorIcon.hide();
37275 this.un('resize', this.alignErrorIcon, this);
37279 var t = Roo.getDom(this.msgTarget);
37281 t.style.display = 'none';
37284 this.fireEvent('valid', this);
37288 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37289 * @return {Mixed} value The field value
37291 getRawValue : function(){
37292 var v = this.el.getValue();
37298 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37299 * @return {Mixed} value The field value
37301 getValue : function(){
37302 var v = this.el.getValue();
37308 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37309 * @param {Mixed} value The value to set
37311 setRawValue : function(v){
37312 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37316 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37317 * @param {Mixed} value The value to set
37319 setValue : function(v){
37322 this.el.dom.value = (v === null || v === undefined ? '' : v);
37327 adjustSize : function(w, h){
37328 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37329 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37333 adjustWidth : function(tag, w){
37334 tag = tag.toLowerCase();
37335 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37336 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37337 if(tag == 'input'){
37340 if(tag == 'textarea'){
37343 }else if(Roo.isOpera){
37344 if(tag == 'input'){
37347 if(tag == 'textarea'){
37357 // anything other than normal should be considered experimental
37358 Roo.form.Field.msgFx = {
37360 show: function(msgEl, f){
37361 msgEl.setDisplayed('block');
37364 hide : function(msgEl, f){
37365 msgEl.setDisplayed(false).update('');
37370 show: function(msgEl, f){
37371 msgEl.slideIn('t', {stopFx:true});
37374 hide : function(msgEl, f){
37375 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37380 show: function(msgEl, f){
37381 msgEl.fixDisplay();
37382 msgEl.alignTo(f.el, 'tl-tr');
37383 msgEl.slideIn('l', {stopFx:true});
37386 hide : function(msgEl, f){
37387 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37392 * Ext JS Library 1.1.1
37393 * Copyright(c) 2006-2007, Ext JS, LLC.
37395 * Originally Released Under LGPL - original licence link has changed is not relivant.
37398 * <script type="text/javascript">
37403 * @class Roo.form.TextField
37404 * @extends Roo.form.Field
37405 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37406 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37408 * Creates a new TextField
37409 * @param {Object} config Configuration options
37411 Roo.form.TextField = function(config){
37412 Roo.form.TextField.superclass.constructor.call(this, config);
37416 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37417 * according to the default logic, but this event provides a hook for the developer to apply additional
37418 * logic at runtime to resize the field if needed.
37419 * @param {Roo.form.Field} this This text field
37420 * @param {Number} width The new field width
37426 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37428 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37432 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37436 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37440 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37444 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37448 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37450 disableKeyFilter : false,
37452 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37456 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37460 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37462 maxLength : Number.MAX_VALUE,
37464 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37466 minLengthText : "The minimum length for this field is {0}",
37468 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37470 maxLengthText : "The maximum length for this field is {0}",
37472 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37474 selectOnFocus : false,
37476 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37478 blankText : "This field is required",
37480 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37481 * If available, this function will be called only after the basic validators all return true, and will be passed the
37482 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37486 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37487 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37488 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37492 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37496 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37502 initEvents : function()
37504 if (this.emptyText) {
37505 this.el.attr('placeholder', this.emptyText);
37508 Roo.form.TextField.superclass.initEvents.call(this);
37509 if(this.validationEvent == 'keyup'){
37510 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37511 this.el.on('keyup', this.filterValidation, this);
37513 else if(this.validationEvent !== false){
37514 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37517 if(this.selectOnFocus){
37518 this.on("focus", this.preFocus, this);
37521 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37522 this.el.on("keypress", this.filterKeys, this);
37525 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37526 this.el.on("click", this.autoSize, this);
37528 if(this.el.is('input[type=password]') && Roo.isSafari){
37529 this.el.on('keydown', this.SafariOnKeyDown, this);
37533 processValue : function(value){
37534 if(this.stripCharsRe){
37535 var newValue = value.replace(this.stripCharsRe, '');
37536 if(newValue !== value){
37537 this.setRawValue(newValue);
37544 filterValidation : function(e){
37545 if(!e.isNavKeyPress()){
37546 this.validationTask.delay(this.validationDelay);
37551 onKeyUp : function(e){
37552 if(!e.isNavKeyPress()){
37558 * Resets the current field value to the originally-loaded value and clears any validation messages.
37561 reset : function(){
37562 Roo.form.TextField.superclass.reset.call(this);
37568 preFocus : function(){
37570 if(this.selectOnFocus){
37571 this.el.dom.select();
37577 filterKeys : function(e){
37578 var k = e.getKey();
37579 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37582 var c = e.getCharCode(), cc = String.fromCharCode(c);
37583 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37586 if(!this.maskRe.test(cc)){
37591 setValue : function(v){
37593 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37599 * Validates a value according to the field's validation rules and marks the field as invalid
37600 * if the validation fails
37601 * @param {Mixed} value The value to validate
37602 * @return {Boolean} True if the value is valid, else false
37604 validateValue : function(value){
37605 if(value.length < 1) { // if it's blank
37606 if(this.allowBlank){
37607 this.clearInvalid();
37610 this.markInvalid(this.blankText);
37614 if(value.length < this.minLength){
37615 this.markInvalid(String.format(this.minLengthText, this.minLength));
37618 if(value.length > this.maxLength){
37619 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37623 var vt = Roo.form.VTypes;
37624 if(!vt[this.vtype](value, this)){
37625 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37629 if(typeof this.validator == "function"){
37630 var msg = this.validator(value);
37632 this.markInvalid(msg);
37636 if(this.regex && !this.regex.test(value)){
37637 this.markInvalid(this.regexText);
37644 * Selects text in this field
37645 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37646 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37648 selectText : function(start, end){
37649 var v = this.getRawValue();
37651 start = start === undefined ? 0 : start;
37652 end = end === undefined ? v.length : end;
37653 var d = this.el.dom;
37654 if(d.setSelectionRange){
37655 d.setSelectionRange(start, end);
37656 }else if(d.createTextRange){
37657 var range = d.createTextRange();
37658 range.moveStart("character", start);
37659 range.moveEnd("character", v.length-end);
37666 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37667 * This only takes effect if grow = true, and fires the autosize event.
37669 autoSize : function(){
37670 if(!this.grow || !this.rendered){
37674 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37677 var v = el.dom.value;
37678 var d = document.createElement('div');
37679 d.appendChild(document.createTextNode(v));
37683 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37684 this.el.setWidth(w);
37685 this.fireEvent("autosize", this, w);
37689 SafariOnKeyDown : function(event)
37691 // this is a workaround for a password hang bug on chrome/ webkit.
37693 var isSelectAll = false;
37695 if(this.el.dom.selectionEnd > 0){
37696 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37698 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37699 event.preventDefault();
37704 if(isSelectAll){ // backspace and delete key
37706 event.preventDefault();
37707 // this is very hacky as keydown always get's upper case.
37709 var cc = String.fromCharCode(event.getCharCode());
37710 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37718 * Ext JS Library 1.1.1
37719 * Copyright(c) 2006-2007, Ext JS, LLC.
37721 * Originally Released Under LGPL - original licence link has changed is not relivant.
37724 * <script type="text/javascript">
37728 * @class Roo.form.Hidden
37729 * @extends Roo.form.TextField
37730 * Simple Hidden element used on forms
37732 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37735 * Creates a new Hidden form element.
37736 * @param {Object} config Configuration options
37741 // easy hidden field...
37742 Roo.form.Hidden = function(config){
37743 Roo.form.Hidden.superclass.constructor.call(this, config);
37746 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37748 inputType: 'hidden',
37751 labelSeparator: '',
37753 itemCls : 'x-form-item-display-none'
37761 * Ext JS Library 1.1.1
37762 * Copyright(c) 2006-2007, Ext JS, LLC.
37764 * Originally Released Under LGPL - original licence link has changed is not relivant.
37767 * <script type="text/javascript">
37771 * @class Roo.form.TriggerField
37772 * @extends Roo.form.TextField
37773 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37774 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37775 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37776 * for which you can provide a custom implementation. For example:
37778 var trigger = new Roo.form.TriggerField();
37779 trigger.onTriggerClick = myTriggerFn;
37780 trigger.applyTo('my-field');
37783 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37784 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37785 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37786 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37788 * Create a new TriggerField.
37789 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37790 * to the base TextField)
37792 Roo.form.TriggerField = function(config){
37793 this.mimicing = false;
37794 Roo.form.TriggerField.superclass.constructor.call(this, config);
37797 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37799 * @cfg {String} triggerClass A CSS class to apply to the trigger
37802 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37803 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37805 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37807 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37811 /** @cfg {Boolean} grow @hide */
37812 /** @cfg {Number} growMin @hide */
37813 /** @cfg {Number} growMax @hide */
37819 autoSize: Roo.emptyFn,
37823 deferHeight : true,
37826 actionMode : 'wrap',
37828 onResize : function(w, h){
37829 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37830 if(typeof w == 'number'){
37831 var x = w - this.trigger.getWidth();
37832 this.el.setWidth(this.adjustWidth('input', x));
37833 this.trigger.setStyle('left', x+'px');
37838 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37841 getResizeEl : function(){
37846 getPositionEl : function(){
37851 alignErrorIcon : function(){
37852 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37856 onRender : function(ct, position){
37857 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37858 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37859 this.trigger = this.wrap.createChild(this.triggerConfig ||
37860 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37861 if(this.hideTrigger){
37862 this.trigger.setDisplayed(false);
37864 this.initTrigger();
37866 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37871 initTrigger : function(){
37872 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37873 this.trigger.addClassOnOver('x-form-trigger-over');
37874 this.trigger.addClassOnClick('x-form-trigger-click');
37878 onDestroy : function(){
37880 this.trigger.removeAllListeners();
37881 this.trigger.remove();
37884 this.wrap.remove();
37886 Roo.form.TriggerField.superclass.onDestroy.call(this);
37890 onFocus : function(){
37891 Roo.form.TriggerField.superclass.onFocus.call(this);
37892 if(!this.mimicing){
37893 this.wrap.addClass('x-trigger-wrap-focus');
37894 this.mimicing = true;
37895 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37896 if(this.monitorTab){
37897 this.el.on("keydown", this.checkTab, this);
37903 checkTab : function(e){
37904 if(e.getKey() == e.TAB){
37905 this.triggerBlur();
37910 onBlur : function(){
37915 mimicBlur : function(e, t){
37916 if(!this.wrap.contains(t) && this.validateBlur()){
37917 this.triggerBlur();
37922 triggerBlur : function(){
37923 this.mimicing = false;
37924 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37925 if(this.monitorTab){
37926 this.el.un("keydown", this.checkTab, this);
37928 this.wrap.removeClass('x-trigger-wrap-focus');
37929 Roo.form.TriggerField.superclass.onBlur.call(this);
37933 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37934 validateBlur : function(e, t){
37939 onDisable : function(){
37940 Roo.form.TriggerField.superclass.onDisable.call(this);
37942 this.wrap.addClass('x-item-disabled');
37947 onEnable : function(){
37948 Roo.form.TriggerField.superclass.onEnable.call(this);
37950 this.wrap.removeClass('x-item-disabled');
37955 onShow : function(){
37956 var ae = this.getActionEl();
37959 ae.dom.style.display = '';
37960 ae.dom.style.visibility = 'visible';
37966 onHide : function(){
37967 var ae = this.getActionEl();
37968 ae.dom.style.display = 'none';
37972 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37973 * by an implementing function.
37975 * @param {EventObject} e
37977 onTriggerClick : Roo.emptyFn
37980 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37981 // to be extended by an implementing class. For an example of implementing this class, see the custom
37982 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37983 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37984 initComponent : function(){
37985 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37987 this.triggerConfig = {
37988 tag:'span', cls:'x-form-twin-triggers', cn:[
37989 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37990 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37994 getTrigger : function(index){
37995 return this.triggers[index];
37998 initTrigger : function(){
37999 var ts = this.trigger.select('.x-form-trigger', true);
38000 this.wrap.setStyle('overflow', 'hidden');
38001 var triggerField = this;
38002 ts.each(function(t, all, index){
38003 t.hide = function(){
38004 var w = triggerField.wrap.getWidth();
38005 this.dom.style.display = 'none';
38006 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38008 t.show = function(){
38009 var w = triggerField.wrap.getWidth();
38010 this.dom.style.display = '';
38011 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38013 var triggerIndex = 'Trigger'+(index+1);
38015 if(this['hide'+triggerIndex]){
38016 t.dom.style.display = 'none';
38018 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38019 t.addClassOnOver('x-form-trigger-over');
38020 t.addClassOnClick('x-form-trigger-click');
38022 this.triggers = ts.elements;
38025 onTrigger1Click : Roo.emptyFn,
38026 onTrigger2Click : Roo.emptyFn
38029 * Ext JS Library 1.1.1
38030 * Copyright(c) 2006-2007, Ext JS, LLC.
38032 * Originally Released Under LGPL - original licence link has changed is not relivant.
38035 * <script type="text/javascript">
38039 * @class Roo.form.TextArea
38040 * @extends Roo.form.TextField
38041 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38042 * support for auto-sizing.
38044 * Creates a new TextArea
38045 * @param {Object} config Configuration options
38047 Roo.form.TextArea = function(config){
38048 Roo.form.TextArea.superclass.constructor.call(this, config);
38049 // these are provided exchanges for backwards compat
38050 // minHeight/maxHeight were replaced by growMin/growMax to be
38051 // compatible with TextField growing config values
38052 if(this.minHeight !== undefined){
38053 this.growMin = this.minHeight;
38055 if(this.maxHeight !== undefined){
38056 this.growMax = this.maxHeight;
38060 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38062 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38066 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38070 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38071 * in the field (equivalent to setting overflow: hidden, defaults to false)
38073 preventScrollbars: false,
38075 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38076 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38080 onRender : function(ct, position){
38082 this.defaultAutoCreate = {
38084 style:"width:300px;height:60px;",
38085 autocomplete: "off"
38088 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38090 this.textSizeEl = Roo.DomHelper.append(document.body, {
38091 tag: "pre", cls: "x-form-grow-sizer"
38093 if(this.preventScrollbars){
38094 this.el.setStyle("overflow", "hidden");
38096 this.el.setHeight(this.growMin);
38100 onDestroy : function(){
38101 if(this.textSizeEl){
38102 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38104 Roo.form.TextArea.superclass.onDestroy.call(this);
38108 onKeyUp : function(e){
38109 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38115 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38116 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38118 autoSize : function(){
38119 if(!this.grow || !this.textSizeEl){
38123 var v = el.dom.value;
38124 var ts = this.textSizeEl;
38127 ts.appendChild(document.createTextNode(v));
38130 Roo.fly(ts).setWidth(this.el.getWidth());
38132 v = "  ";
38135 v = v.replace(/\n/g, '<p> </p>');
38137 v += " \n ";
38140 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38141 if(h != this.lastHeight){
38142 this.lastHeight = h;
38143 this.el.setHeight(h);
38144 this.fireEvent("autosize", this, h);
38149 * Ext JS Library 1.1.1
38150 * Copyright(c) 2006-2007, Ext JS, LLC.
38152 * Originally Released Under LGPL - original licence link has changed is not relivant.
38155 * <script type="text/javascript">
38160 * @class Roo.form.NumberField
38161 * @extends Roo.form.TextField
38162 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38164 * Creates a new NumberField
38165 * @param {Object} config Configuration options
38167 Roo.form.NumberField = function(config){
38168 Roo.form.NumberField.superclass.constructor.call(this, config);
38171 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38173 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38175 fieldClass: "x-form-field x-form-num-field",
38177 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38179 allowDecimals : true,
38181 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38183 decimalSeparator : ".",
38185 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38187 decimalPrecision : 2,
38189 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38191 allowNegative : true,
38193 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38195 minValue : Number.NEGATIVE_INFINITY,
38197 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38199 maxValue : Number.MAX_VALUE,
38201 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38203 minText : "The minimum value for this field is {0}",
38205 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38207 maxText : "The maximum value for this field is {0}",
38209 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38210 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38212 nanText : "{0} is not a valid number",
38215 initEvents : function(){
38216 Roo.form.NumberField.superclass.initEvents.call(this);
38217 var allowed = "0123456789";
38218 if(this.allowDecimals){
38219 allowed += this.decimalSeparator;
38221 if(this.allowNegative){
38224 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38225 var keyPress = function(e){
38226 var k = e.getKey();
38227 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38230 var c = e.getCharCode();
38231 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38235 this.el.on("keypress", keyPress, this);
38239 validateValue : function(value){
38240 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38243 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38246 var num = this.parseValue(value);
38248 this.markInvalid(String.format(this.nanText, value));
38251 if(num < this.minValue){
38252 this.markInvalid(String.format(this.minText, this.minValue));
38255 if(num > this.maxValue){
38256 this.markInvalid(String.format(this.maxText, this.maxValue));
38262 getValue : function(){
38263 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38267 parseValue : function(value){
38268 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38269 return isNaN(value) ? '' : value;
38273 fixPrecision : function(value){
38274 var nan = isNaN(value);
38275 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38276 return nan ? '' : value;
38278 return parseFloat(value).toFixed(this.decimalPrecision);
38281 setValue : function(v){
38282 v = this.fixPrecision(v);
38283 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38287 decimalPrecisionFcn : function(v){
38288 return Math.floor(v);
38291 beforeBlur : function(){
38292 var v = this.parseValue(this.getRawValue());
38299 * Ext JS Library 1.1.1
38300 * Copyright(c) 2006-2007, Ext JS, LLC.
38302 * Originally Released Under LGPL - original licence link has changed is not relivant.
38305 * <script type="text/javascript">
38309 * @class Roo.form.DateField
38310 * @extends Roo.form.TriggerField
38311 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38313 * Create a new DateField
38314 * @param {Object} config
38316 Roo.form.DateField = function(config){
38317 Roo.form.DateField.superclass.constructor.call(this, config);
38323 * Fires when a date is selected
38324 * @param {Roo.form.DateField} combo This combo box
38325 * @param {Date} date The date selected
38332 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38333 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38334 this.ddMatch = null;
38335 if(this.disabledDates){
38336 var dd = this.disabledDates;
38338 for(var i = 0; i < dd.length; i++){
38340 if(i != dd.length-1) re += "|";
38342 this.ddMatch = new RegExp(re + ")");
38346 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38348 * @cfg {String} format
38349 * The default date format string which can be overriden for localization support. The format must be
38350 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38354 * @cfg {String} altFormats
38355 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38356 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38358 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38360 * @cfg {Array} disabledDays
38361 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38363 disabledDays : null,
38365 * @cfg {String} disabledDaysText
38366 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38368 disabledDaysText : "Disabled",
38370 * @cfg {Array} disabledDates
38371 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38372 * expression so they are very powerful. Some examples:
38374 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38375 * <li>["03/08", "09/16"] would disable those days for every year</li>
38376 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38377 * <li>["03/../2006"] would disable every day in March 2006</li>
38378 * <li>["^03"] would disable every day in every March</li>
38380 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38381 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38383 disabledDates : null,
38385 * @cfg {String} disabledDatesText
38386 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38388 disabledDatesText : "Disabled",
38390 * @cfg {Date/String} minValue
38391 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38392 * valid format (defaults to null).
38396 * @cfg {Date/String} maxValue
38397 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38398 * valid format (defaults to null).
38402 * @cfg {String} minText
38403 * The error text to display when the date in the cell is before minValue (defaults to
38404 * 'The date in this field must be after {minValue}').
38406 minText : "The date in this field must be equal to or after {0}",
38408 * @cfg {String} maxText
38409 * The error text to display when the date in the cell is after maxValue (defaults to
38410 * 'The date in this field must be before {maxValue}').
38412 maxText : "The date in this field must be equal to or before {0}",
38414 * @cfg {String} invalidText
38415 * The error text to display when the date in the field is invalid (defaults to
38416 * '{value} is not a valid date - it must be in the format {format}').
38418 invalidText : "{0} is not a valid date - it must be in the format {1}",
38420 * @cfg {String} triggerClass
38421 * An additional CSS class used to style the trigger button. The trigger will always get the
38422 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38423 * which displays a calendar icon).
38425 triggerClass : 'x-form-date-trigger',
38429 * @cfg {Boolean} useIso
38430 * if enabled, then the date field will use a hidden field to store the
38431 * real value as iso formated date. default (false)
38435 * @cfg {String/Object} autoCreate
38436 * A DomHelper element spec, or true for a default element spec (defaults to
38437 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38440 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38443 hiddenField: false,
38445 onRender : function(ct, position)
38447 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38449 //this.el.dom.removeAttribute('name');
38450 Roo.log("Changing name?");
38451 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38452 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38454 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38455 // prevent input submission
38456 this.hiddenName = this.name;
38463 validateValue : function(value)
38465 value = this.formatDate(value);
38466 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38467 Roo.log('super failed');
38470 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38473 var svalue = value;
38474 value = this.parseDate(value);
38476 Roo.log('parse date failed' + svalue);
38477 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38480 var time = value.getTime();
38481 if(this.minValue && time < this.minValue.getTime()){
38482 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38485 if(this.maxValue && time > this.maxValue.getTime()){
38486 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38489 if(this.disabledDays){
38490 var day = value.getDay();
38491 for(var i = 0; i < this.disabledDays.length; i++) {
38492 if(day === this.disabledDays[i]){
38493 this.markInvalid(this.disabledDaysText);
38498 var fvalue = this.formatDate(value);
38499 if(this.ddMatch && this.ddMatch.test(fvalue)){
38500 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38507 // Provides logic to override the default TriggerField.validateBlur which just returns true
38508 validateBlur : function(){
38509 return !this.menu || !this.menu.isVisible();
38512 getName: function()
38514 // returns hidden if it's set..
38515 if (!this.rendered) {return ''};
38516 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38521 * Returns the current date value of the date field.
38522 * @return {Date} The date value
38524 getValue : function(){
38526 return this.hiddenField ?
38527 this.hiddenField.value :
38528 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38532 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38533 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38534 * (the default format used is "m/d/y").
38537 //All of these calls set the same date value (May 4, 2006)
38539 //Pass a date object:
38540 var dt = new Date('5/4/06');
38541 dateField.setValue(dt);
38543 //Pass a date string (default format):
38544 dateField.setValue('5/4/06');
38546 //Pass a date string (custom format):
38547 dateField.format = 'Y-m-d';
38548 dateField.setValue('2006-5-4');
38550 * @param {String/Date} date The date or valid date string
38552 setValue : function(date){
38553 if (this.hiddenField) {
38554 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38556 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38557 // make sure the value field is always stored as a date..
38558 this.value = this.parseDate(date);
38564 parseDate : function(value){
38565 if(!value || value instanceof Date){
38568 var v = Date.parseDate(value, this.format);
38569 if (!v && this.useIso) {
38570 v = Date.parseDate(value, 'Y-m-d');
38572 if(!v && this.altFormats){
38573 if(!this.altFormatsArray){
38574 this.altFormatsArray = this.altFormats.split("|");
38576 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38577 v = Date.parseDate(value, this.altFormatsArray[i]);
38584 formatDate : function(date, fmt){
38585 return (!date || !(date instanceof Date)) ?
38586 date : date.dateFormat(fmt || this.format);
38591 select: function(m, d){
38594 this.fireEvent('select', this, d);
38596 show : function(){ // retain focus styling
38600 this.focus.defer(10, this);
38601 var ml = this.menuListeners;
38602 this.menu.un("select", ml.select, this);
38603 this.menu.un("show", ml.show, this);
38604 this.menu.un("hide", ml.hide, this);
38609 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38610 onTriggerClick : function(){
38614 if(this.menu == null){
38615 this.menu = new Roo.menu.DateMenu();
38617 Roo.apply(this.menu.picker, {
38618 showClear: this.allowBlank,
38619 minDate : this.minValue,
38620 maxDate : this.maxValue,
38621 disabledDatesRE : this.ddMatch,
38622 disabledDatesText : this.disabledDatesText,
38623 disabledDays : this.disabledDays,
38624 disabledDaysText : this.disabledDaysText,
38625 format : this.useIso ? 'Y-m-d' : this.format,
38626 minText : String.format(this.minText, this.formatDate(this.minValue)),
38627 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38629 this.menu.on(Roo.apply({}, this.menuListeners, {
38632 this.menu.picker.setValue(this.getValue() || new Date());
38633 this.menu.show(this.el, "tl-bl?");
38636 beforeBlur : function(){
38637 var v = this.parseDate(this.getRawValue());
38647 isDirty : function() {
38648 if(this.disabled) {
38652 if(typeof(this.startValue) === 'undefined'){
38656 return String(this.getValue()) !== String(this.startValue);
38661 * Ext JS Library 1.1.1
38662 * Copyright(c) 2006-2007, Ext JS, LLC.
38664 * Originally Released Under LGPL - original licence link has changed is not relivant.
38667 * <script type="text/javascript">
38671 * @class Roo.form.MonthField
38672 * @extends Roo.form.TriggerField
38673 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38675 * Create a new MonthField
38676 * @param {Object} config
38678 Roo.form.MonthField = function(config){
38680 Roo.form.MonthField.superclass.constructor.call(this, config);
38686 * Fires when a date is selected
38687 * @param {Roo.form.MonthFieeld} combo This combo box
38688 * @param {Date} date The date selected
38695 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38696 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38697 this.ddMatch = null;
38698 if(this.disabledDates){
38699 var dd = this.disabledDates;
38701 for(var i = 0; i < dd.length; i++){
38703 if(i != dd.length-1) re += "|";
38705 this.ddMatch = new RegExp(re + ")");
38709 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38711 * @cfg {String} format
38712 * The default date format string which can be overriden for localization support. The format must be
38713 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38717 * @cfg {String} altFormats
38718 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38719 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38721 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38723 * @cfg {Array} disabledDays
38724 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38726 disabledDays : [0,1,2,3,4,5,6],
38728 * @cfg {String} disabledDaysText
38729 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38731 disabledDaysText : "Disabled",
38733 * @cfg {Array} disabledDates
38734 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38735 * expression so they are very powerful. Some examples:
38737 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38738 * <li>["03/08", "09/16"] would disable those days for every year</li>
38739 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38740 * <li>["03/../2006"] would disable every day in March 2006</li>
38741 * <li>["^03"] would disable every day in every March</li>
38743 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38744 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38746 disabledDates : null,
38748 * @cfg {String} disabledDatesText
38749 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38751 disabledDatesText : "Disabled",
38753 * @cfg {Date/String} minValue
38754 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38755 * valid format (defaults to null).
38759 * @cfg {Date/String} maxValue
38760 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38761 * valid format (defaults to null).
38765 * @cfg {String} minText
38766 * The error text to display when the date in the cell is before minValue (defaults to
38767 * 'The date in this field must be after {minValue}').
38769 minText : "The date in this field must be equal to or after {0}",
38771 * @cfg {String} maxTextf
38772 * The error text to display when the date in the cell is after maxValue (defaults to
38773 * 'The date in this field must be before {maxValue}').
38775 maxText : "The date in this field must be equal to or before {0}",
38777 * @cfg {String} invalidText
38778 * The error text to display when the date in the field is invalid (defaults to
38779 * '{value} is not a valid date - it must be in the format {format}').
38781 invalidText : "{0} is not a valid date - it must be in the format {1}",
38783 * @cfg {String} triggerClass
38784 * An additional CSS class used to style the trigger button. The trigger will always get the
38785 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38786 * which displays a calendar icon).
38788 triggerClass : 'x-form-date-trigger',
38792 * @cfg {Boolean} useIso
38793 * if enabled, then the date field will use a hidden field to store the
38794 * real value as iso formated date. default (true)
38798 * @cfg {String/Object} autoCreate
38799 * A DomHelper element spec, or true for a default element spec (defaults to
38800 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38803 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38806 hiddenField: false,
38808 hideMonthPicker : false,
38810 onRender : function(ct, position)
38812 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38814 this.el.dom.removeAttribute('name');
38815 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38817 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38818 // prevent input submission
38819 this.hiddenName = this.name;
38826 validateValue : function(value)
38828 value = this.formatDate(value);
38829 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38832 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38835 var svalue = value;
38836 value = this.parseDate(value);
38838 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38841 var time = value.getTime();
38842 if(this.minValue && time < this.minValue.getTime()){
38843 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38846 if(this.maxValue && time > this.maxValue.getTime()){
38847 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38850 /*if(this.disabledDays){
38851 var day = value.getDay();
38852 for(var i = 0; i < this.disabledDays.length; i++) {
38853 if(day === this.disabledDays[i]){
38854 this.markInvalid(this.disabledDaysText);
38860 var fvalue = this.formatDate(value);
38861 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38862 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38870 // Provides logic to override the default TriggerField.validateBlur which just returns true
38871 validateBlur : function(){
38872 return !this.menu || !this.menu.isVisible();
38876 * Returns the current date value of the date field.
38877 * @return {Date} The date value
38879 getValue : function(){
38883 return this.hiddenField ?
38884 this.hiddenField.value :
38885 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38889 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38890 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38891 * (the default format used is "m/d/y").
38894 //All of these calls set the same date value (May 4, 2006)
38896 //Pass a date object:
38897 var dt = new Date('5/4/06');
38898 monthField.setValue(dt);
38900 //Pass a date string (default format):
38901 monthField.setValue('5/4/06');
38903 //Pass a date string (custom format):
38904 monthField.format = 'Y-m-d';
38905 monthField.setValue('2006-5-4');
38907 * @param {String/Date} date The date or valid date string
38909 setValue : function(date){
38910 Roo.log('month setValue' + date);
38911 // can only be first of month..
38913 var val = this.parseDate(date);
38915 if (this.hiddenField) {
38916 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38918 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38919 this.value = this.parseDate(date);
38923 parseDate : function(value){
38924 if(!value || value instanceof Date){
38925 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38928 var v = Date.parseDate(value, this.format);
38929 if (!v && this.useIso) {
38930 v = Date.parseDate(value, 'Y-m-d');
38934 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38938 if(!v && this.altFormats){
38939 if(!this.altFormatsArray){
38940 this.altFormatsArray = this.altFormats.split("|");
38942 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38943 v = Date.parseDate(value, this.altFormatsArray[i]);
38950 formatDate : function(date, fmt){
38951 return (!date || !(date instanceof Date)) ?
38952 date : date.dateFormat(fmt || this.format);
38957 select: function(m, d){
38959 this.fireEvent('select', this, d);
38961 show : function(){ // retain focus styling
38965 this.focus.defer(10, this);
38966 var ml = this.menuListeners;
38967 this.menu.un("select", ml.select, this);
38968 this.menu.un("show", ml.show, this);
38969 this.menu.un("hide", ml.hide, this);
38973 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38974 onTriggerClick : function(){
38978 if(this.menu == null){
38979 this.menu = new Roo.menu.DateMenu();
38983 Roo.apply(this.menu.picker, {
38985 showClear: this.allowBlank,
38986 minDate : this.minValue,
38987 maxDate : this.maxValue,
38988 disabledDatesRE : this.ddMatch,
38989 disabledDatesText : this.disabledDatesText,
38991 format : this.useIso ? 'Y-m-d' : this.format,
38992 minText : String.format(this.minText, this.formatDate(this.minValue)),
38993 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38996 this.menu.on(Roo.apply({}, this.menuListeners, {
39004 // hide month picker get's called when we called by 'before hide';
39006 var ignorehide = true;
39007 p.hideMonthPicker = function(disableAnim){
39011 if(this.monthPicker){
39012 Roo.log("hideMonthPicker called");
39013 if(disableAnim === true){
39014 this.monthPicker.hide();
39016 this.monthPicker.slideOut('t', {duration:.2});
39017 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39018 p.fireEvent("select", this, this.value);
39024 Roo.log('picker set value');
39025 Roo.log(this.getValue());
39026 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39027 m.show(this.el, 'tl-bl?');
39028 ignorehide = false;
39029 // this will trigger hideMonthPicker..
39032 // hidden the day picker
39033 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39039 p.showMonthPicker.defer(100, p);
39045 beforeBlur : function(){
39046 var v = this.parseDate(this.getRawValue());
39052 /** @cfg {Boolean} grow @hide */
39053 /** @cfg {Number} growMin @hide */
39054 /** @cfg {Number} growMax @hide */
39061 * Ext JS Library 1.1.1
39062 * Copyright(c) 2006-2007, Ext JS, LLC.
39064 * Originally Released Under LGPL - original licence link has changed is not relivant.
39067 * <script type="text/javascript">
39072 * @class Roo.form.ComboBox
39073 * @extends Roo.form.TriggerField
39074 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39076 * Create a new ComboBox.
39077 * @param {Object} config Configuration options
39079 Roo.form.ComboBox = function(config){
39080 Roo.form.ComboBox.superclass.constructor.call(this, config);
39084 * Fires when the dropdown list is expanded
39085 * @param {Roo.form.ComboBox} combo This combo box
39090 * Fires when the dropdown list is collapsed
39091 * @param {Roo.form.ComboBox} combo This combo box
39095 * @event beforeselect
39096 * Fires before a list item is selected. Return false to cancel the selection.
39097 * @param {Roo.form.ComboBox} combo This combo box
39098 * @param {Roo.data.Record} record The data record returned from the underlying store
39099 * @param {Number} index The index of the selected item in the dropdown list
39101 'beforeselect' : true,
39104 * Fires when a list item is selected
39105 * @param {Roo.form.ComboBox} combo This combo box
39106 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39107 * @param {Number} index The index of the selected item in the dropdown list
39111 * @event beforequery
39112 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39113 * The event object passed has these properties:
39114 * @param {Roo.form.ComboBox} combo This combo box
39115 * @param {String} query The query
39116 * @param {Boolean} forceAll true to force "all" query
39117 * @param {Boolean} cancel true to cancel the query
39118 * @param {Object} e The query event object
39120 'beforequery': true,
39123 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39124 * @param {Roo.form.ComboBox} combo This combo box
39129 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39130 * @param {Roo.form.ComboBox} combo This combo box
39131 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39137 if(this.transform){
39138 this.allowDomMove = false;
39139 var s = Roo.getDom(this.transform);
39140 if(!this.hiddenName){
39141 this.hiddenName = s.name;
39144 this.mode = 'local';
39145 var d = [], opts = s.options;
39146 for(var i = 0, len = opts.length;i < len; i++){
39148 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39150 this.value = value;
39152 d.push([value, o.text]);
39154 this.store = new Roo.data.SimpleStore({
39156 fields: ['value', 'text'],
39159 this.valueField = 'value';
39160 this.displayField = 'text';
39162 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39163 if(!this.lazyRender){
39164 this.target = true;
39165 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39166 s.parentNode.removeChild(s); // remove it
39167 this.render(this.el.parentNode);
39169 s.parentNode.removeChild(s); // remove it
39174 this.store = Roo.factory(this.store, Roo.data);
39177 this.selectedIndex = -1;
39178 if(this.mode == 'local'){
39179 if(config.queryDelay === undefined){
39180 this.queryDelay = 10;
39182 if(config.minChars === undefined){
39188 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39190 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39193 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39194 * rendering into an Roo.Editor, defaults to false)
39197 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39198 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39201 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39204 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39205 * the dropdown list (defaults to undefined, with no header element)
39209 * @cfg {String/Roo.Template} tpl The template to use to render the output
39213 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39215 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39217 listWidth: undefined,
39219 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39220 * mode = 'remote' or 'text' if mode = 'local')
39222 displayField: undefined,
39224 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39225 * mode = 'remote' or 'value' if mode = 'local').
39226 * Note: use of a valueField requires the user make a selection
39227 * in order for a value to be mapped.
39229 valueField: undefined,
39233 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39234 * field's data value (defaults to the underlying DOM element's name)
39236 hiddenName: undefined,
39238 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39242 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39244 selectedClass: 'x-combo-selected',
39246 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39247 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39248 * which displays a downward arrow icon).
39250 triggerClass : 'x-form-arrow-trigger',
39252 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39256 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39257 * anchor positions (defaults to 'tl-bl')
39259 listAlign: 'tl-bl?',
39261 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39265 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39266 * query specified by the allQuery config option (defaults to 'query')
39268 triggerAction: 'query',
39270 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39271 * (defaults to 4, does not apply if editable = false)
39275 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39276 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39280 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39281 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39285 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39286 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39290 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39291 * when editable = true (defaults to false)
39293 selectOnFocus:false,
39295 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39297 queryParam: 'query',
39299 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39300 * when mode = 'remote' (defaults to 'Loading...')
39302 loadingText: 'Loading...',
39304 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39308 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39312 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39313 * traditional select (defaults to true)
39317 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39321 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39325 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39326 * listWidth has a higher value)
39330 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39331 * allow the user to set arbitrary text into the field (defaults to false)
39333 forceSelection:false,
39335 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39336 * if typeAhead = true (defaults to 250)
39338 typeAheadDelay : 250,
39340 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39341 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39343 valueNotFoundText : undefined,
39345 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39347 blockFocus : false,
39350 * @cfg {Boolean} disableClear Disable showing of clear button.
39352 disableClear : false,
39354 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39356 alwaysQuery : false,
39362 // element that contains real text value.. (when hidden is used..)
39365 onRender : function(ct, position){
39366 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39367 if(this.hiddenName){
39368 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39370 this.hiddenField.value =
39371 this.hiddenValue !== undefined ? this.hiddenValue :
39372 this.value !== undefined ? this.value : '';
39374 // prevent input submission
39375 this.el.dom.removeAttribute('name');
39380 this.el.dom.setAttribute('autocomplete', 'off');
39383 var cls = 'x-combo-list';
39385 this.list = new Roo.Layer({
39386 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39389 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39390 this.list.setWidth(lw);
39391 this.list.swallowEvent('mousewheel');
39392 this.assetHeight = 0;
39395 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39396 this.assetHeight += this.header.getHeight();
39399 this.innerList = this.list.createChild({cls:cls+'-inner'});
39400 this.innerList.on('mouseover', this.onViewOver, this);
39401 this.innerList.on('mousemove', this.onViewMove, this);
39402 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39404 if(this.allowBlank && !this.pageSize && !this.disableClear){
39405 this.footer = this.list.createChild({cls:cls+'-ft'});
39406 this.pageTb = new Roo.Toolbar(this.footer);
39410 this.footer = this.list.createChild({cls:cls+'-ft'});
39411 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39412 {pageSize: this.pageSize});
39416 if (this.pageTb && this.allowBlank && !this.disableClear) {
39418 this.pageTb.add(new Roo.Toolbar.Fill(), {
39419 cls: 'x-btn-icon x-btn-clear',
39421 handler: function()
39424 _this.clearValue();
39425 _this.onSelect(false, -1);
39430 this.assetHeight += this.footer.getHeight();
39435 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39438 this.view = new Roo.View(this.innerList, this.tpl, {
39439 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39442 this.view.on('click', this.onViewClick, this);
39444 this.store.on('beforeload', this.onBeforeLoad, this);
39445 this.store.on('load', this.onLoad, this);
39446 this.store.on('loadexception', this.onLoadException, this);
39448 if(this.resizable){
39449 this.resizer = new Roo.Resizable(this.list, {
39450 pinned:true, handles:'se'
39452 this.resizer.on('resize', function(r, w, h){
39453 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39454 this.listWidth = w;
39455 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39456 this.restrictHeight();
39458 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39460 if(!this.editable){
39461 this.editable = true;
39462 this.setEditable(false);
39466 if (typeof(this.events.add.listeners) != 'undefined') {
39468 this.addicon = this.wrap.createChild(
39469 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39471 this.addicon.on('click', function(e) {
39472 this.fireEvent('add', this);
39475 if (typeof(this.events.edit.listeners) != 'undefined') {
39477 this.editicon = this.wrap.createChild(
39478 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39479 if (this.addicon) {
39480 this.editicon.setStyle('margin-left', '40px');
39482 this.editicon.on('click', function(e) {
39484 // we fire even if inothing is selected..
39485 this.fireEvent('edit', this, this.lastData );
39495 initEvents : function(){
39496 Roo.form.ComboBox.superclass.initEvents.call(this);
39498 this.keyNav = new Roo.KeyNav(this.el, {
39499 "up" : function(e){
39500 this.inKeyMode = true;
39504 "down" : function(e){
39505 if(!this.isExpanded()){
39506 this.onTriggerClick();
39508 this.inKeyMode = true;
39513 "enter" : function(e){
39514 this.onViewClick();
39518 "esc" : function(e){
39522 "tab" : function(e){
39523 this.onViewClick(false);
39524 this.fireEvent("specialkey", this, e);
39530 doRelay : function(foo, bar, hname){
39531 if(hname == 'down' || this.scope.isExpanded()){
39532 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39539 this.queryDelay = Math.max(this.queryDelay || 10,
39540 this.mode == 'local' ? 10 : 250);
39541 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39542 if(this.typeAhead){
39543 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39545 if(this.editable !== false){
39546 this.el.on("keyup", this.onKeyUp, this);
39548 if(this.forceSelection){
39549 this.on('blur', this.doForce, this);
39553 onDestroy : function(){
39555 this.view.setStore(null);
39556 this.view.el.removeAllListeners();
39557 this.view.el.remove();
39558 this.view.purgeListeners();
39561 this.list.destroy();
39564 this.store.un('beforeload', this.onBeforeLoad, this);
39565 this.store.un('load', this.onLoad, this);
39566 this.store.un('loadexception', this.onLoadException, this);
39568 Roo.form.ComboBox.superclass.onDestroy.call(this);
39572 fireKey : function(e){
39573 if(e.isNavKeyPress() && !this.list.isVisible()){
39574 this.fireEvent("specialkey", this, e);
39579 onResize: function(w, h){
39580 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39582 if(typeof w != 'number'){
39583 // we do not handle it!?!?
39586 var tw = this.trigger.getWidth();
39587 tw += this.addicon ? this.addicon.getWidth() : 0;
39588 tw += this.editicon ? this.editicon.getWidth() : 0;
39590 this.el.setWidth( this.adjustWidth('input', x));
39592 this.trigger.setStyle('left', x+'px');
39594 if(this.list && this.listWidth === undefined){
39595 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39596 this.list.setWidth(lw);
39597 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39605 * Allow or prevent the user from directly editing the field text. If false is passed,
39606 * the user will only be able to select from the items defined in the dropdown list. This method
39607 * is the runtime equivalent of setting the 'editable' config option at config time.
39608 * @param {Boolean} value True to allow the user to directly edit the field text
39610 setEditable : function(value){
39611 if(value == this.editable){
39614 this.editable = value;
39616 this.el.dom.setAttribute('readOnly', true);
39617 this.el.on('mousedown', this.onTriggerClick, this);
39618 this.el.addClass('x-combo-noedit');
39620 this.el.dom.setAttribute('readOnly', false);
39621 this.el.un('mousedown', this.onTriggerClick, this);
39622 this.el.removeClass('x-combo-noedit');
39627 onBeforeLoad : function(){
39628 if(!this.hasFocus){
39631 this.innerList.update(this.loadingText ?
39632 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39633 this.restrictHeight();
39634 this.selectedIndex = -1;
39638 onLoad : function(){
39639 if(!this.hasFocus){
39642 if(this.store.getCount() > 0){
39644 this.restrictHeight();
39645 if(this.lastQuery == this.allQuery){
39647 this.el.dom.select();
39649 if(!this.selectByValue(this.value, true)){
39650 this.select(0, true);
39654 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39655 this.taTask.delay(this.typeAheadDelay);
39659 this.onEmptyResults();
39664 onLoadException : function()
39667 Roo.log(this.store.reader.jsonData);
39668 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39669 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39675 onTypeAhead : function(){
39676 if(this.store.getCount() > 0){
39677 var r = this.store.getAt(0);
39678 var newValue = r.data[this.displayField];
39679 var len = newValue.length;
39680 var selStart = this.getRawValue().length;
39681 if(selStart != len){
39682 this.setRawValue(newValue);
39683 this.selectText(selStart, newValue.length);
39689 onSelect : function(record, index){
39690 if(this.fireEvent('beforeselect', this, record, index) !== false){
39691 this.setFromData(index > -1 ? record.data : false);
39693 this.fireEvent('select', this, record, index);
39698 * Returns the currently selected field value or empty string if no value is set.
39699 * @return {String} value The selected value
39701 getValue : function(){
39702 if(this.valueField){
39703 return typeof this.value != 'undefined' ? this.value : '';
39705 return Roo.form.ComboBox.superclass.getValue.call(this);
39710 * Clears any text/value currently set in the field
39712 clearValue : function(){
39713 if(this.hiddenField){
39714 this.hiddenField.value = '';
39717 this.setRawValue('');
39718 this.lastSelectionText = '';
39723 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39724 * will be displayed in the field. If the value does not match the data value of an existing item,
39725 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39726 * Otherwise the field will be blank (although the value will still be set).
39727 * @param {String} value The value to match
39729 setValue : function(v){
39731 if(this.valueField){
39732 var r = this.findRecord(this.valueField, v);
39734 text = r.data[this.displayField];
39735 }else if(this.valueNotFoundText !== undefined){
39736 text = this.valueNotFoundText;
39739 this.lastSelectionText = text;
39740 if(this.hiddenField){
39741 this.hiddenField.value = v;
39743 Roo.form.ComboBox.superclass.setValue.call(this, text);
39747 * @property {Object} the last set data for the element
39752 * Sets the value of the field based on a object which is related to the record format for the store.
39753 * @param {Object} value the value to set as. or false on reset?
39755 setFromData : function(o){
39756 var dv = ''; // display value
39757 var vv = ''; // value value..
39759 if (this.displayField) {
39760 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39762 // this is an error condition!!!
39763 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39766 if(this.valueField){
39767 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39769 if(this.hiddenField){
39770 this.hiddenField.value = vv;
39772 this.lastSelectionText = dv;
39773 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39777 // no hidden field.. - we store the value in 'value', but still display
39778 // display field!!!!
39779 this.lastSelectionText = dv;
39780 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39786 reset : function(){
39787 // overridden so that last data is reset..
39788 this.setValue(this.resetValue);
39789 this.clearInvalid();
39790 this.lastData = false;
39792 this.view.clearSelections();
39796 findRecord : function(prop, value){
39798 if(this.store.getCount() > 0){
39799 this.store.each(function(r){
39800 if(r.data[prop] == value){
39810 getName: function()
39812 // returns hidden if it's set..
39813 if (!this.rendered) {return ''};
39814 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39818 onViewMove : function(e, t){
39819 this.inKeyMode = false;
39823 onViewOver : function(e, t){
39824 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39827 var item = this.view.findItemFromChild(t);
39829 var index = this.view.indexOf(item);
39830 this.select(index, false);
39835 onViewClick : function(doFocus)
39837 var index = this.view.getSelectedIndexes()[0];
39838 var r = this.store.getAt(index);
39840 this.onSelect(r, index);
39842 if(doFocus !== false && !this.blockFocus){
39848 restrictHeight : function(){
39849 this.innerList.dom.style.height = '';
39850 var inner = this.innerList.dom;
39851 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39852 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39853 this.list.beginUpdate();
39854 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39855 this.list.alignTo(this.el, this.listAlign);
39856 this.list.endUpdate();
39860 onEmptyResults : function(){
39865 * Returns true if the dropdown list is expanded, else false.
39867 isExpanded : function(){
39868 return this.list.isVisible();
39872 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39873 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39874 * @param {String} value The data value of the item to select
39875 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39876 * selected item if it is not currently in view (defaults to true)
39877 * @return {Boolean} True if the value matched an item in the list, else false
39879 selectByValue : function(v, scrollIntoView){
39880 if(v !== undefined && v !== null){
39881 var r = this.findRecord(this.valueField || this.displayField, v);
39883 this.select(this.store.indexOf(r), scrollIntoView);
39891 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39892 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39893 * @param {Number} index The zero-based index of the list item to select
39894 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39895 * selected item if it is not currently in view (defaults to true)
39897 select : function(index, scrollIntoView){
39898 this.selectedIndex = index;
39899 this.view.select(index);
39900 if(scrollIntoView !== false){
39901 var el = this.view.getNode(index);
39903 this.innerList.scrollChildIntoView(el, false);
39909 selectNext : function(){
39910 var ct = this.store.getCount();
39912 if(this.selectedIndex == -1){
39914 }else if(this.selectedIndex < ct-1){
39915 this.select(this.selectedIndex+1);
39921 selectPrev : function(){
39922 var ct = this.store.getCount();
39924 if(this.selectedIndex == -1){
39926 }else if(this.selectedIndex != 0){
39927 this.select(this.selectedIndex-1);
39933 onKeyUp : function(e){
39934 if(this.editable !== false && !e.isSpecialKey()){
39935 this.lastKey = e.getKey();
39936 this.dqTask.delay(this.queryDelay);
39941 validateBlur : function(){
39942 return !this.list || !this.list.isVisible();
39946 initQuery : function(){
39947 this.doQuery(this.getRawValue());
39951 doForce : function(){
39952 if(this.el.dom.value.length > 0){
39953 this.el.dom.value =
39954 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39960 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39961 * query allowing the query action to be canceled if needed.
39962 * @param {String} query The SQL query to execute
39963 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39964 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39965 * saved in the current store (defaults to false)
39967 doQuery : function(q, forceAll){
39968 if(q === undefined || q === null){
39973 forceAll: forceAll,
39977 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39981 forceAll = qe.forceAll;
39982 if(forceAll === true || (q.length >= this.minChars)){
39983 if(this.lastQuery != q || this.alwaysQuery){
39984 this.lastQuery = q;
39985 if(this.mode == 'local'){
39986 this.selectedIndex = -1;
39988 this.store.clearFilter();
39990 this.store.filter(this.displayField, q);
39994 this.store.baseParams[this.queryParam] = q;
39996 params: this.getParams(q)
40001 this.selectedIndex = -1;
40008 getParams : function(q){
40010 //p[this.queryParam] = q;
40013 p.limit = this.pageSize;
40019 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40021 collapse : function(){
40022 if(!this.isExpanded()){
40026 Roo.get(document).un('mousedown', this.collapseIf, this);
40027 Roo.get(document).un('mousewheel', this.collapseIf, this);
40028 if (!this.editable) {
40029 Roo.get(document).un('keydown', this.listKeyPress, this);
40031 this.fireEvent('collapse', this);
40035 collapseIf : function(e){
40036 if(!e.within(this.wrap) && !e.within(this.list)){
40042 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40044 expand : function(){
40045 if(this.isExpanded() || !this.hasFocus){
40048 this.list.alignTo(this.el, this.listAlign);
40050 Roo.get(document).on('mousedown', this.collapseIf, this);
40051 Roo.get(document).on('mousewheel', this.collapseIf, this);
40052 if (!this.editable) {
40053 Roo.get(document).on('keydown', this.listKeyPress, this);
40056 this.fireEvent('expand', this);
40060 // Implements the default empty TriggerField.onTriggerClick function
40061 onTriggerClick : function(){
40065 if(this.isExpanded()){
40067 if (!this.blockFocus) {
40072 this.hasFocus = true;
40073 if(this.triggerAction == 'all') {
40074 this.doQuery(this.allQuery, true);
40076 this.doQuery(this.getRawValue());
40078 if (!this.blockFocus) {
40083 listKeyPress : function(e)
40085 //Roo.log('listkeypress');
40086 // scroll to first matching element based on key pres..
40087 if (e.isSpecialKey()) {
40090 var k = String.fromCharCode(e.getKey()).toUpperCase();
40093 var csel = this.view.getSelectedNodes();
40094 var cselitem = false;
40096 var ix = this.view.indexOf(csel[0]);
40097 cselitem = this.store.getAt(ix);
40098 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40104 this.store.each(function(v) {
40106 // start at existing selection.
40107 if (cselitem.id == v.id) {
40113 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40114 match = this.store.indexOf(v);
40119 if (match === false) {
40120 return true; // no more action?
40123 this.view.select(match);
40124 var sn = Roo.get(this.view.getSelectedNodes()[0])
40125 sn.scrollIntoView(sn.dom.parentNode, false);
40129 * @cfg {Boolean} grow
40133 * @cfg {Number} growMin
40137 * @cfg {Number} growMax
40145 * Copyright(c) 2010-2012, Roo J Solutions Limited
40152 * @class Roo.form.ComboBoxArray
40153 * @extends Roo.form.TextField
40154 * A facebook style adder... for lists of email / people / countries etc...
40155 * pick multiple items from a combo box, and shows each one.
40157 * Fred [x] Brian [x] [Pick another |v]
40160 * For this to work: it needs various extra information
40161 * - normal combo problay has
40163 * + displayField, valueField
40165 * For our purpose...
40168 * If we change from 'extends' to wrapping...
40175 * Create a new ComboBoxArray.
40176 * @param {Object} config Configuration options
40180 Roo.form.ComboBoxArray = function(config)
40185 * Fires when remove the value from the list
40186 * @param {Roo.form.ComboBoxArray} _self This combo box array
40187 * @param {Roo.form.ComboBoxArray.Item} item removed item
40194 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40196 this.items = new Roo.util.MixedCollection(false);
40198 // construct the child combo...
40208 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40211 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40216 // behavies liek a hiddne field
40217 inputType: 'hidden',
40219 * @cfg {Number} width The width of the box that displays the selected element
40226 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40230 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40232 hiddenName : false,
40235 // private the array of items that are displayed..
40237 // private - the hidden field el.
40239 // private - the filed el..
40242 //validateValue : function() { return true; }, // all values are ok!
40243 //onAddClick: function() { },
40245 onRender : function(ct, position)
40248 // create the standard hidden element
40249 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40252 // give fake names to child combo;
40253 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40254 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40256 this.combo = Roo.factory(this.combo, Roo.form);
40257 this.combo.onRender(ct, position);
40258 if (typeof(this.combo.width) != 'undefined') {
40259 this.combo.onResize(this.combo.width,0);
40262 this.combo.initEvents();
40264 // assigned so form know we need to do this..
40265 this.store = this.combo.store;
40266 this.valueField = this.combo.valueField;
40267 this.displayField = this.combo.displayField ;
40270 this.combo.wrap.addClass('x-cbarray-grp');
40272 var cbwrap = this.combo.wrap.createChild(
40273 {tag: 'div', cls: 'x-cbarray-cb'},
40278 this.hiddenEl = this.combo.wrap.createChild({
40279 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40281 this.el = this.combo.wrap.createChild({
40282 tag: 'input', type:'hidden' , name: this.name, value : ''
40284 // this.el.dom.removeAttribute("name");
40287 this.outerWrap = this.combo.wrap;
40288 this.wrap = cbwrap;
40290 this.outerWrap.setWidth(this.width);
40291 this.outerWrap.dom.removeChild(this.el.dom);
40293 this.wrap.dom.appendChild(this.el.dom);
40294 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40295 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40297 this.combo.trigger.setStyle('position','relative');
40298 this.combo.trigger.setStyle('left', '0px');
40299 this.combo.trigger.setStyle('top', '2px');
40301 this.combo.el.setStyle('vertical-align', 'text-bottom');
40303 //this.trigger.setStyle('vertical-align', 'top');
40305 // this should use the code from combo really... on('add' ....)
40309 this.adder = this.outerWrap.createChild(
40310 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40312 this.adder.on('click', function(e) {
40313 _t.fireEvent('adderclick', this, e);
40317 //this.adder.on('click', this.onAddClick, _t);
40320 this.combo.on('select', function(cb, rec, ix) {
40321 this.addItem(rec.data);
40324 cb.el.dom.value = '';
40325 //cb.lastData = rec.data;
40334 getName: function()
40336 // returns hidden if it's set..
40337 if (!this.rendered) {return ''};
40338 return this.hiddenName ? this.hiddenName : this.name;
40343 onResize: function(w, h){
40346 // not sure if this is needed..
40347 //this.combo.onResize(w,h);
40349 if(typeof w != 'number'){
40350 // we do not handle it!?!?
40353 var tw = this.combo.trigger.getWidth();
40354 tw += this.addicon ? this.addicon.getWidth() : 0;
40355 tw += this.editicon ? this.editicon.getWidth() : 0;
40357 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40359 this.combo.trigger.setStyle('left', '0px');
40361 if(this.list && this.listWidth === undefined){
40362 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40363 this.list.setWidth(lw);
40364 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40371 addItem: function(rec)
40373 var valueField = this.combo.valueField;
40374 var displayField = this.combo.displayField;
40375 if (this.items.indexOfKey(rec[valueField]) > -1) {
40376 //console.log("GOT " + rec.data.id);
40380 var x = new Roo.form.ComboBoxArray.Item({
40381 //id : rec[this.idField],
40383 displayField : displayField ,
40384 tipField : displayField ,
40388 this.items.add(rec[valueField],x);
40389 // add it before the element..
40390 this.updateHiddenEl();
40391 x.render(this.outerWrap, this.wrap.dom);
40392 // add the image handler..
40395 updateHiddenEl : function()
40398 if (!this.hiddenEl) {
40402 var idField = this.combo.valueField;
40404 this.items.each(function(f) {
40405 ar.push(f.data[idField]);
40408 this.hiddenEl.dom.value = ar.join(',');
40414 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40415 this.items.each(function(f) {
40418 this.el.dom.value = '';
40419 if (this.hiddenEl) {
40420 this.hiddenEl.dom.value = '';
40424 getValue: function()
40426 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40428 setValue: function(v) // not a valid action - must use addItems..
40435 if (this.store.isLocal && (typeof(v) == 'string')) {
40436 // then we can use the store to find the values..
40437 // comma seperated at present.. this needs to allow JSON based encoding..
40438 this.hiddenEl.value = v;
40440 Roo.each(v.split(','), function(k) {
40441 Roo.log("CHECK " + this.valueField + ',' + k);
40442 var li = this.store.query(this.valueField, k);
40447 add[this.valueField] = k;
40448 add[this.displayField] = li.item(0).data[this.displayField];
40454 if (typeof(v) == 'object') {
40455 // then let's assume it's an array of objects..
40456 Roo.each(v, function(l) {
40464 setFromData: function(v)
40466 // this recieves an object, if setValues is called.
40468 this.el.dom.value = v[this.displayField];
40469 this.hiddenEl.dom.value = v[this.valueField];
40470 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40473 var kv = v[this.valueField];
40474 var dv = v[this.displayField];
40475 kv = typeof(kv) != 'string' ? '' : kv;
40476 dv = typeof(dv) != 'string' ? '' : dv;
40479 var keys = kv.split(',');
40480 var display = dv.split(',');
40481 for (var i = 0 ; i < keys.length; i++) {
40484 add[this.valueField] = keys[i];
40485 add[this.displayField] = display[i];
40493 * Validates the combox array value
40494 * @return {Boolean} True if the value is valid, else false
40496 validate : function(){
40497 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40498 this.clearInvalid();
40504 validateValue : function(value){
40505 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40513 isDirty : function() {
40514 if(this.disabled) {
40519 var d = Roo.decode(String(this.originalValue));
40521 return String(this.getValue()) !== String(this.originalValue);
40524 var originalValue = [];
40526 for (var i = 0; i < d.length; i++){
40527 originalValue.push(d[i][this.valueField]);
40530 return String(this.getValue()) !== String(originalValue.join(','));
40539 * @class Roo.form.ComboBoxArray.Item
40540 * @extends Roo.BoxComponent
40541 * A selected item in the list
40542 * Fred [x] Brian [x] [Pick another |v]
40545 * Create a new item.
40546 * @param {Object} config Configuration options
40549 Roo.form.ComboBoxArray.Item = function(config) {
40550 config.id = Roo.id();
40551 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40554 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40557 displayField : false,
40561 defaultAutoCreate : {
40563 cls: 'x-cbarray-item',
40570 src : Roo.BLANK_IMAGE_URL ,
40578 onRender : function(ct, position)
40580 Roo.form.Field.superclass.onRender.call(this, ct, position);
40583 var cfg = this.getAutoCreate();
40584 this.el = ct.createChild(cfg, position);
40587 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40589 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40590 this.cb.renderer(this.data) :
40591 String.format('{0}',this.data[this.displayField]);
40594 this.el.child('div').dom.setAttribute('qtip',
40595 String.format('{0}',this.data[this.tipField])
40598 this.el.child('img').on('click', this.remove, this);
40602 remove : function()
40604 this.cb.items.remove(this);
40605 this.el.child('img').un('click', this.remove, this);
40607 this.cb.updateHiddenEl();
40609 this.cb.fireEvent('remove', this.cb, this);
40613 * Ext JS Library 1.1.1
40614 * Copyright(c) 2006-2007, Ext JS, LLC.
40616 * Originally Released Under LGPL - original licence link has changed is not relivant.
40619 * <script type="text/javascript">
40622 * @class Roo.form.Checkbox
40623 * @extends Roo.form.Field
40624 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40626 * Creates a new Checkbox
40627 * @param {Object} config Configuration options
40629 Roo.form.Checkbox = function(config){
40630 Roo.form.Checkbox.superclass.constructor.call(this, config);
40634 * Fires when the checkbox is checked or unchecked.
40635 * @param {Roo.form.Checkbox} this This checkbox
40636 * @param {Boolean} checked The new checked value
40642 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40644 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40646 focusClass : undefined,
40648 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40650 fieldClass: "x-form-field",
40652 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40656 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40657 * {tag: "input", type: "checkbox", autocomplete: "off"})
40659 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40661 * @cfg {String} boxLabel The text that appears beside the checkbox
40665 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40669 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40671 valueOff: '0', // value when not checked..
40673 actionMode : 'viewEl',
40676 itemCls : 'x-menu-check-item x-form-item',
40677 groupClass : 'x-menu-group-item',
40678 inputType : 'hidden',
40681 inSetChecked: false, // check that we are not calling self...
40683 inputElement: false, // real input element?
40684 basedOn: false, // ????
40686 isFormField: true, // not sure where this is needed!!!!
40688 onResize : function(){
40689 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40690 if(!this.boxLabel){
40691 this.el.alignTo(this.wrap, 'c-c');
40695 initEvents : function(){
40696 Roo.form.Checkbox.superclass.initEvents.call(this);
40697 this.el.on("click", this.onClick, this);
40698 this.el.on("change", this.onClick, this);
40702 getResizeEl : function(){
40706 getPositionEl : function(){
40711 onRender : function(ct, position){
40712 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40714 if(this.inputValue !== undefined){
40715 this.el.dom.value = this.inputValue;
40718 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40719 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40720 var viewEl = this.wrap.createChild({
40721 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40722 this.viewEl = viewEl;
40723 this.wrap.on('click', this.onClick, this);
40725 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40726 this.el.on('propertychange', this.setFromHidden, this); //ie
40731 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40732 // viewEl.on('click', this.onClick, this);
40734 //if(this.checked){
40735 this.setChecked(this.checked);
40737 //this.checked = this.el.dom;
40743 initValue : Roo.emptyFn,
40746 * Returns the checked state of the checkbox.
40747 * @return {Boolean} True if checked, else false
40749 getValue : function(){
40751 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40753 return this.valueOff;
40758 onClick : function(){
40759 this.setChecked(!this.checked);
40761 //if(this.el.dom.checked != this.checked){
40762 // this.setValue(this.el.dom.checked);
40767 * Sets the checked state of the checkbox.
40768 * On is always based on a string comparison between inputValue and the param.
40769 * @param {Boolean/String} value - the value to set
40770 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40772 setValue : function(v,suppressEvent){
40775 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40776 //if(this.el && this.el.dom){
40777 // this.el.dom.checked = this.checked;
40778 // this.el.dom.defaultChecked = this.checked;
40780 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40781 //this.fireEvent("check", this, this.checked);
40784 setChecked : function(state,suppressEvent)
40786 if (this.inSetChecked) {
40787 this.checked = state;
40793 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40795 this.checked = state;
40796 if(suppressEvent !== true){
40797 this.fireEvent('check', this, state);
40799 this.inSetChecked = true;
40800 this.el.dom.value = state ? this.inputValue : this.valueOff;
40801 this.inSetChecked = false;
40804 // handle setting of hidden value by some other method!!?!?
40805 setFromHidden: function()
40810 //console.log("SET FROM HIDDEN");
40811 //alert('setFrom hidden');
40812 this.setValue(this.el.dom.value);
40815 onDestroy : function()
40818 Roo.get(this.viewEl).remove();
40821 Roo.form.Checkbox.superclass.onDestroy.call(this);
40826 * Ext JS Library 1.1.1
40827 * Copyright(c) 2006-2007, Ext JS, LLC.
40829 * Originally Released Under LGPL - original licence link has changed is not relivant.
40832 * <script type="text/javascript">
40836 * @class Roo.form.Radio
40837 * @extends Roo.form.Checkbox
40838 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40839 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40841 * Creates a new Radio
40842 * @param {Object} config Configuration options
40844 Roo.form.Radio = function(){
40845 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40847 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40848 inputType: 'radio',
40851 * If this radio is part of a group, it will return the selected value
40854 getGroupValue : function(){
40855 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40859 onRender : function(ct, position){
40860 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40862 if(this.inputValue !== undefined){
40863 this.el.dom.value = this.inputValue;
40866 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40867 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40868 //var viewEl = this.wrap.createChild({
40869 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40870 //this.viewEl = viewEl;
40871 //this.wrap.on('click', this.onClick, this);
40873 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40874 //this.el.on('propertychange', this.setFromHidden, this); //ie
40879 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40880 // viewEl.on('click', this.onClick, this);
40883 this.el.dom.checked = 'checked' ;
40889 });//<script type="text/javascript">
40892 * Based Ext JS Library 1.1.1
40893 * Copyright(c) 2006-2007, Ext JS, LLC.
40899 * @class Roo.HtmlEditorCore
40900 * @extends Roo.Component
40901 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
40903 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40906 Roo.HtmlEditorCore = function(config){
40909 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
40912 * @event initialize
40913 * Fires when the editor is fully initialized (including the iframe)
40914 * @param {Roo.HtmlEditorCore} this
40919 * Fires when the editor is first receives the focus. Any insertion must wait
40920 * until after this event.
40921 * @param {Roo.HtmlEditorCore} this
40925 * @event beforesync
40926 * Fires before the textarea is updated with content from the editor iframe. Return false
40927 * to cancel the sync.
40928 * @param {Roo.HtmlEditorCore} this
40929 * @param {String} html
40933 * @event beforepush
40934 * Fires before the iframe editor is updated with content from the textarea. Return false
40935 * to cancel the push.
40936 * @param {Roo.HtmlEditorCore} this
40937 * @param {String} html
40942 * Fires when the textarea is updated with content from the editor iframe.
40943 * @param {Roo.HtmlEditorCore} this
40944 * @param {String} html
40949 * Fires when the iframe editor is updated with content from the textarea.
40950 * @param {Roo.HtmlEditorCore} this
40951 * @param {String} html
40956 * @event editorevent
40957 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40958 * @param {Roo.HtmlEditorCore} this
40966 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
40970 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
40976 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40981 * @cfg {Number} height (in pixels)
40985 * @cfg {Number} width (in pixels)
40990 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40993 stylesheets: false,
40998 // private properties
40999 validationEvent : false,
41001 initialized : false,
41003 sourceEditMode : false,
41004 onFocus : Roo.emptyFn,
41006 hideMode:'offsets',
41014 * Protected method that will not generally be called directly. It
41015 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41016 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41018 getDocMarkup : function(){
41021 Roo.log(this.stylesheets);
41023 // inherit styels from page...??
41024 if (this.stylesheets === false) {
41026 Roo.get(document.head).select('style').each(function(node) {
41027 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41030 Roo.get(document.head).select('link').each(function(node) {
41031 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41034 } else if (!this.stylesheets.length) {
41036 st = '<style type="text/css">' +
41037 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41040 Roo.each(this.stylesheets, function(s) {
41041 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41046 st += '<style type="text/css">' +
41047 'IMG { cursor: pointer } ' +
41051 return '<html><head>' + st +
41052 //<style type="text/css">' +
41053 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41055 ' </head><body class="roo-htmleditor-body"></body></html>';
41059 onRender : function(ct, position)
41062 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41063 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41066 this.el.dom.style.border = '0 none';
41067 this.el.dom.setAttribute('tabIndex', -1);
41068 this.el.addClass('x-hidden hide');
41072 if(Roo.isIE){ // fix IE 1px bogus margin
41073 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41077 this.frameId = Roo.id();
41081 var iframe = this.owner.wrap.createChild({
41083 cls: 'form-control', // bootstrap..
41085 name: this.frameId,
41086 frameBorder : 'no',
41087 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41092 this.iframe = iframe.dom;
41094 this.assignDocWin();
41096 this.doc.designMode = 'on';
41099 this.doc.write(this.getDocMarkup());
41103 var task = { // must defer to wait for browser to be ready
41105 //console.log("run task?" + this.doc.readyState);
41106 this.assignDocWin();
41107 if(this.doc.body || this.doc.readyState == 'complete'){
41109 this.doc.designMode="on";
41113 Roo.TaskMgr.stop(task);
41114 this.initEditor.defer(10, this);
41121 Roo.TaskMgr.start(task);
41128 onResize : function(w, h)
41130 Roo.log('resize: ' +w + ',' + h );
41131 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41135 if(typeof w == 'number'){
41137 this.iframe.style.width = w + 'px';
41139 if(typeof h == 'number'){
41141 this.iframe.style.height = h + 'px';
41143 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41150 * Toggles the editor between standard and source edit mode.
41151 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41153 toggleSourceEdit : function(sourceEditMode){
41155 this.sourceEditMode = sourceEditMode === true;
41157 if(this.sourceEditMode){
41159 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41162 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41163 //this.iframe.className = '';
41166 //this.setSize(this.owner.wrap.getSize());
41167 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41174 * Protected method that will not generally be called directly. If you need/want
41175 * custom HTML cleanup, this is the method you should override.
41176 * @param {String} html The HTML to be cleaned
41177 * return {String} The cleaned HTML
41179 cleanHtml : function(html){
41180 html = String(html);
41181 if(html.length > 5){
41182 if(Roo.isSafari){ // strip safari nonsense
41183 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41186 if(html == ' '){
41193 * HTML Editor -> Textarea
41194 * Protected method that will not generally be called directly. Syncs the contents
41195 * of the editor iframe with the textarea.
41197 syncValue : function(){
41198 if(this.initialized){
41199 var bd = (this.doc.body || this.doc.documentElement);
41200 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41201 var html = bd.innerHTML;
41203 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41204 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41206 html = '<div style="'+m[0]+'">' + html + '</div>';
41209 html = this.cleanHtml(html);
41210 // fix up the special chars.. normaly like back quotes in word...
41211 // however we do not want to do this with chinese..
41212 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41213 var cc = b.charCodeAt();
41215 (cc >= 0x4E00 && cc < 0xA000 ) ||
41216 (cc >= 0x3400 && cc < 0x4E00 ) ||
41217 (cc >= 0xf900 && cc < 0xfb00 )
41223 if(this.owner.fireEvent('beforesync', this, html) !== false){
41224 this.el.dom.value = html;
41225 this.owner.fireEvent('sync', this, html);
41231 * Protected method that will not generally be called directly. Pushes the value of the textarea
41232 * into the iframe editor.
41234 pushValue : function(){
41235 if(this.initialized){
41236 var v = this.el.dom.value.trim();
41238 // if(v.length < 1){
41242 if(this.owner.fireEvent('beforepush', this, v) !== false){
41243 var d = (this.doc.body || this.doc.documentElement);
41245 this.cleanUpPaste();
41246 this.el.dom.value = d.innerHTML;
41247 this.owner.fireEvent('push', this, v);
41253 deferFocus : function(){
41254 this.focus.defer(10, this);
41258 focus : function(){
41259 if(this.win && !this.sourceEditMode){
41266 assignDocWin: function()
41268 var iframe = this.iframe;
41271 this.doc = iframe.contentWindow.document;
41272 this.win = iframe.contentWindow;
41274 if (!Roo.get(this.frameId)) {
41277 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41278 this.win = Roo.get(this.frameId).dom.contentWindow;
41283 initEditor : function(){
41284 //console.log("INIT EDITOR");
41285 this.assignDocWin();
41289 this.doc.designMode="on";
41291 this.doc.write(this.getDocMarkup());
41294 var dbody = (this.doc.body || this.doc.documentElement);
41295 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41296 // this copies styles from the containing element into thsi one..
41297 // not sure why we need all of this..
41298 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41299 ss['background-attachment'] = 'fixed'; // w3c
41300 dbody.bgProperties = 'fixed'; // ie
41301 Roo.DomHelper.applyStyles(dbody, ss);
41302 Roo.EventManager.on(this.doc, {
41303 //'mousedown': this.onEditorEvent,
41304 'mouseup': this.onEditorEvent,
41305 'dblclick': this.onEditorEvent,
41306 'click': this.onEditorEvent,
41307 'keyup': this.onEditorEvent,
41312 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41314 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41315 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41317 this.initialized = true;
41319 this.owner.fireEvent('initialize', this);
41324 onDestroy : function(){
41330 //for (var i =0; i < this.toolbars.length;i++) {
41331 // // fixme - ask toolbars for heights?
41332 // this.toolbars[i].onDestroy();
41335 //this.wrap.dom.innerHTML = '';
41336 //this.wrap.remove();
41341 onFirstFocus : function(){
41343 this.assignDocWin();
41346 this.activated = true;
41349 if(Roo.isGecko){ // prevent silly gecko errors
41351 var s = this.win.getSelection();
41352 if(!s.focusNode || s.focusNode.nodeType != 3){
41353 var r = s.getRangeAt(0);
41354 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41359 this.execCmd('useCSS', true);
41360 this.execCmd('styleWithCSS', false);
41363 this.owner.fireEvent('activate', this);
41367 adjustFont: function(btn){
41368 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41369 //if(Roo.isSafari){ // safari
41372 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41373 if(Roo.isSafari){ // safari
41374 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41375 v = (v < 10) ? 10 : v;
41376 v = (v > 48) ? 48 : v;
41377 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41382 v = Math.max(1, v+adjust);
41384 this.execCmd('FontSize', v );
41387 onEditorEvent : function(e){
41388 this.owner.fireEvent('editorevent', this, e);
41389 // this.updateToolbar();
41390 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41393 insertTag : function(tg)
41395 // could be a bit smarter... -> wrap the current selected tRoo..
41396 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41398 range = this.createRange(this.getSelection());
41399 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41400 wrappingNode.appendChild(range.extractContents());
41401 range.insertNode(wrappingNode);
41408 this.execCmd("formatblock", tg);
41412 insertText : function(txt)
41416 var range = this.createRange();
41417 range.deleteContents();
41418 //alert(Sender.getAttribute('label'));
41420 range.insertNode(this.doc.createTextNode(txt));
41426 * Executes a Midas editor command on the editor document and performs necessary focus and
41427 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41428 * @param {String} cmd The Midas command
41429 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41431 relayCmd : function(cmd, value){
41433 this.execCmd(cmd, value);
41434 this.owner.fireEvent('editorevent', this);
41435 //this.updateToolbar();
41436 this.owner.deferFocus();
41440 * Executes a Midas editor command directly on the editor document.
41441 * For visual commands, you should use {@link #relayCmd} instead.
41442 * <b>This should only be called after the editor is initialized.</b>
41443 * @param {String} cmd The Midas command
41444 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41446 execCmd : function(cmd, value){
41447 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41454 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41456 * @param {String} text | dom node..
41458 insertAtCursor : function(text)
41463 if(!this.activated){
41469 var r = this.doc.selection.createRange();
41480 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41484 // from jquery ui (MIT licenced)
41486 var win = this.win;
41488 if (win.getSelection && win.getSelection().getRangeAt) {
41489 range = win.getSelection().getRangeAt(0);
41490 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41491 range.insertNode(node);
41492 } else if (win.document.selection && win.document.selection.createRange) {
41493 // no firefox support
41494 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41495 win.document.selection.createRange().pasteHTML(txt);
41497 // no firefox support
41498 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41499 this.execCmd('InsertHTML', txt);
41508 mozKeyPress : function(e){
41510 var c = e.getCharCode(), cmd;
41513 c = String.fromCharCode(c).toLowerCase();
41527 this.cleanUpPaste.defer(100, this);
41535 e.preventDefault();
41543 fixKeys : function(){ // load time branching for fastest keydown performance
41545 return function(e){
41546 var k = e.getKey(), r;
41549 r = this.doc.selection.createRange();
41552 r.pasteHTML('    ');
41559 r = this.doc.selection.createRange();
41561 var target = r.parentElement();
41562 if(!target || target.tagName.toLowerCase() != 'li'){
41564 r.pasteHTML('<br />');
41570 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41571 this.cleanUpPaste.defer(100, this);
41577 }else if(Roo.isOpera){
41578 return function(e){
41579 var k = e.getKey();
41583 this.execCmd('InsertHTML','    ');
41586 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41587 this.cleanUpPaste.defer(100, this);
41592 }else if(Roo.isSafari){
41593 return function(e){
41594 var k = e.getKey();
41598 this.execCmd('InsertText','\t');
41602 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41603 this.cleanUpPaste.defer(100, this);
41611 getAllAncestors: function()
41613 var p = this.getSelectedNode();
41616 a.push(p); // push blank onto stack..
41617 p = this.getParentElement();
41621 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41625 a.push(this.doc.body);
41629 lastSelNode : false,
41632 getSelection : function()
41634 this.assignDocWin();
41635 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41638 getSelectedNode: function()
41640 // this may only work on Gecko!!!
41642 // should we cache this!!!!
41647 var range = this.createRange(this.getSelection()).cloneRange();
41650 var parent = range.parentElement();
41652 var testRange = range.duplicate();
41653 testRange.moveToElementText(parent);
41654 if (testRange.inRange(range)) {
41657 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41660 parent = parent.parentElement;
41665 // is ancestor a text element.
41666 var ac = range.commonAncestorContainer;
41667 if (ac.nodeType == 3) {
41668 ac = ac.parentNode;
41671 var ar = ac.childNodes;
41674 var other_nodes = [];
41675 var has_other_nodes = false;
41676 for (var i=0;i<ar.length;i++) {
41677 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41680 // fullly contained node.
41682 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41687 // probably selected..
41688 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41689 other_nodes.push(ar[i]);
41693 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41698 has_other_nodes = true;
41700 if (!nodes.length && other_nodes.length) {
41701 nodes= other_nodes;
41703 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41709 createRange: function(sel)
41711 // this has strange effects when using with
41712 // top toolbar - not sure if it's a great idea.
41713 //this.editor.contentWindow.focus();
41714 if (typeof sel != "undefined") {
41716 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41718 return this.doc.createRange();
41721 return this.doc.createRange();
41724 getParentElement: function()
41727 this.assignDocWin();
41728 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41730 var range = this.createRange(sel);
41733 var p = range.commonAncestorContainer;
41734 while (p.nodeType == 3) { // text node
41745 * Range intersection.. the hard stuff...
41749 * [ -- selected range --- ]
41753 * if end is before start or hits it. fail.
41754 * if start is after end or hits it fail.
41756 * if either hits (but other is outside. - then it's not
41762 // @see http://www.thismuchiknow.co.uk/?p=64.
41763 rangeIntersectsNode : function(range, node)
41765 var nodeRange = node.ownerDocument.createRange();
41767 nodeRange.selectNode(node);
41769 nodeRange.selectNodeContents(node);
41772 var rangeStartRange = range.cloneRange();
41773 rangeStartRange.collapse(true);
41775 var rangeEndRange = range.cloneRange();
41776 rangeEndRange.collapse(false);
41778 var nodeStartRange = nodeRange.cloneRange();
41779 nodeStartRange.collapse(true);
41781 var nodeEndRange = nodeRange.cloneRange();
41782 nodeEndRange.collapse(false);
41784 return rangeStartRange.compareBoundaryPoints(
41785 Range.START_TO_START, nodeEndRange) == -1 &&
41786 rangeEndRange.compareBoundaryPoints(
41787 Range.START_TO_START, nodeStartRange) == 1;
41791 rangeCompareNode : function(range, node)
41793 var nodeRange = node.ownerDocument.createRange();
41795 nodeRange.selectNode(node);
41797 nodeRange.selectNodeContents(node);
41801 range.collapse(true);
41803 nodeRange.collapse(true);
41805 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41806 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41808 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41810 var nodeIsBefore = ss == 1;
41811 var nodeIsAfter = ee == -1;
41813 if (nodeIsBefore && nodeIsAfter)
41815 if (!nodeIsBefore && nodeIsAfter)
41816 return 1; //right trailed.
41818 if (nodeIsBefore && !nodeIsAfter)
41819 return 2; // left trailed.
41824 // private? - in a new class?
41825 cleanUpPaste : function()
41827 // cleans up the whole document..
41828 Roo.log('cleanuppaste');
41830 this.cleanUpChildren(this.doc.body);
41831 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41832 if (clean != this.doc.body.innerHTML) {
41833 this.doc.body.innerHTML = clean;
41838 cleanWordChars : function(input) {// change the chars to hex code
41839 var he = Roo.HtmlEditorCore;
41841 var output = input;
41842 Roo.each(he.swapCodes, function(sw) {
41843 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41845 output = output.replace(swapper, sw[1]);
41852 cleanUpChildren : function (n)
41854 if (!n.childNodes.length) {
41857 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41858 this.cleanUpChild(n.childNodes[i]);
41865 cleanUpChild : function (node)
41868 //console.log(node);
41869 if (node.nodeName == "#text") {
41870 // clean up silly Windows -- stuff?
41873 if (node.nodeName == "#comment") {
41874 node.parentNode.removeChild(node);
41875 // clean up silly Windows -- stuff?
41879 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
41881 node.parentNode.removeChild(node);
41886 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
41888 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41889 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41891 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41892 // remove_keep_children = true;
41895 if (remove_keep_children) {
41896 this.cleanUpChildren(node);
41897 // inserts everything just before this node...
41898 while (node.childNodes.length) {
41899 var cn = node.childNodes[0];
41900 node.removeChild(cn);
41901 node.parentNode.insertBefore(cn, node);
41903 node.parentNode.removeChild(node);
41907 if (!node.attributes || !node.attributes.length) {
41908 this.cleanUpChildren(node);
41912 function cleanAttr(n,v)
41915 if (v.match(/^\./) || v.match(/^\//)) {
41918 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41921 if (v.match(/^#/)) {
41924 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41925 node.removeAttribute(n);
41929 function cleanStyle(n,v)
41931 if (v.match(/expression/)) { //XSS?? should we even bother..
41932 node.removeAttribute(n);
41935 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
41936 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
41939 var parts = v.split(/;/);
41942 Roo.each(parts, function(p) {
41943 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41947 var l = p.split(':').shift().replace(/\s+/g,'');
41948 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41950 if ( cblack.indexOf(l) > -1) {
41951 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41952 //node.removeAttribute(n);
41956 // only allow 'c whitelisted system attributes'
41957 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41958 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41959 //node.removeAttribute(n);
41969 if (clean.length) {
41970 node.setAttribute(n, clean.join(';'));
41972 node.removeAttribute(n);
41978 for (var i = node.attributes.length-1; i > -1 ; i--) {
41979 var a = node.attributes[i];
41982 if (a.name.toLowerCase().substr(0,2)=='on') {
41983 node.removeAttribute(a.name);
41986 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
41987 node.removeAttribute(a.name);
41990 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
41991 cleanAttr(a.name,a.value); // fixme..
41994 if (a.name == 'style') {
41995 cleanStyle(a.name,a.value);
41998 /// clean up MS crap..
41999 // tecnically this should be a list of valid class'es..
42002 if (a.name == 'class') {
42003 if (a.value.match(/^Mso/)) {
42004 node.className = '';
42007 if (a.value.match(/body/)) {
42008 node.className = '';
42019 this.cleanUpChildren(node);
42024 * Clean up MS wordisms...
42026 cleanWord : function(node)
42029 var cleanWordChildren = function()
42031 if (!node.childNodes.length) {
42034 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42035 _t.cleanWord(node.childNodes[i]);
42041 this.cleanWord(this.doc.body);
42044 if (node.nodeName == "#text") {
42045 // clean up silly Windows -- stuff?
42048 if (node.nodeName == "#comment") {
42049 node.parentNode.removeChild(node);
42050 // clean up silly Windows -- stuff?
42054 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42055 node.parentNode.removeChild(node);
42059 // remove - but keep children..
42060 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42061 while (node.childNodes.length) {
42062 var cn = node.childNodes[0];
42063 node.removeChild(cn);
42064 node.parentNode.insertBefore(cn, node);
42066 node.parentNode.removeChild(node);
42067 cleanWordChildren();
42071 if (node.className.length) {
42073 var cn = node.className.split(/\W+/);
42075 Roo.each(cn, function(cls) {
42076 if (cls.match(/Mso[a-zA-Z]+/)) {
42081 node.className = cna.length ? cna.join(' ') : '';
42083 node.removeAttribute("class");
42087 if (node.hasAttribute("lang")) {
42088 node.removeAttribute("lang");
42091 if (node.hasAttribute("style")) {
42093 var styles = node.getAttribute("style").split(";");
42095 Roo.each(styles, function(s) {
42096 if (!s.match(/:/)) {
42099 var kv = s.split(":");
42100 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42103 // what ever is left... we allow.
42106 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42107 if (!nstyle.length) {
42108 node.removeAttribute('style');
42112 cleanWordChildren();
42116 domToHTML : function(currentElement, depth, nopadtext) {
42118 depth = depth || 0;
42119 nopadtext = nopadtext || false;
42121 if (!currentElement) {
42122 return this.domToHTML(this.doc.body);
42125 //Roo.log(currentElement);
42127 var allText = false;
42128 var nodeName = currentElement.nodeName;
42129 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42131 if (nodeName == '#text') {
42132 return currentElement.nodeValue;
42137 if (nodeName != 'BODY') {
42140 // Prints the node tagName, such as <A>, <IMG>, etc
42143 for(i = 0; i < currentElement.attributes.length;i++) {
42145 var aname = currentElement.attributes.item(i).name;
42146 if (!currentElement.attributes.item(i).value.length) {
42149 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42152 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42161 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42164 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42169 // Traverse the tree
42171 var currentElementChild = currentElement.childNodes.item(i);
42172 var allText = true;
42173 var innerHTML = '';
42175 while (currentElementChild) {
42176 // Formatting code (indent the tree so it looks nice on the screen)
42177 var nopad = nopadtext;
42178 if (lastnode == 'SPAN') {
42182 if (currentElementChild.nodeName == '#text') {
42183 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42184 if (!nopad && toadd.length > 80) {
42185 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42187 innerHTML += toadd;
42190 currentElementChild = currentElement.childNodes.item(i);
42196 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42198 // Recursively traverse the tree structure of the child node
42199 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42200 lastnode = currentElementChild.nodeName;
42202 currentElementChild=currentElement.childNodes.item(i);
42208 // The remaining code is mostly for formatting the tree
42209 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42214 ret+= "</"+tagName+">";
42220 // hide stuff that is not compatible
42234 * @event specialkey
42238 * @cfg {String} fieldClass @hide
42241 * @cfg {String} focusClass @hide
42244 * @cfg {String} autoCreate @hide
42247 * @cfg {String} inputType @hide
42250 * @cfg {String} invalidClass @hide
42253 * @cfg {String} invalidText @hide
42256 * @cfg {String} msgFx @hide
42259 * @cfg {String} validateOnBlur @hide
42263 Roo.HtmlEditorCore.white = [
42264 'area', 'br', 'img', 'input', 'hr', 'wbr',
42266 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42267 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42268 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42269 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42270 'table', 'ul', 'xmp',
42272 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42275 'dir', 'menu', 'ol', 'ul', 'dl',
42281 Roo.HtmlEditorCore.black = [
42282 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42284 'base', 'basefont', 'bgsound', 'blink', 'body',
42285 'frame', 'frameset', 'head', 'html', 'ilayer',
42286 'iframe', 'layer', 'link', 'meta', 'object',
42287 'script', 'style' ,'title', 'xml' // clean later..
42289 Roo.HtmlEditorCore.clean = [
42290 'script', 'style', 'title', 'xml'
42292 Roo.HtmlEditorCore.remove = [
42297 Roo.HtmlEditorCore.ablack = [
42301 Roo.HtmlEditorCore.aclean = [
42302 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42306 Roo.HtmlEditorCore.pwhite= [
42307 'http', 'https', 'mailto'
42310 // white listed style attributes.
42311 Roo.HtmlEditorCore.cwhite= [
42312 // 'text-align', /// default is to allow most things..
42318 // black listed style attributes.
42319 Roo.HtmlEditorCore.cblack= [
42320 // 'font-size' -- this can be set by the project
42324 Roo.HtmlEditorCore.swapCodes =[
42335 //<script type="text/javascript">
42338 * Ext JS Library 1.1.1
42339 * Copyright(c) 2006-2007, Ext JS, LLC.
42345 Roo.form.HtmlEditor = function(config){
42349 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42351 if (!this.toolbars) {
42352 this.toolbars = [];
42354 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42360 * @class Roo.form.HtmlEditor
42361 * @extends Roo.form.Field
42362 * Provides a lightweight HTML Editor component.
42364 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42366 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42367 * supported by this editor.</b><br/><br/>
42368 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42369 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42371 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42373 * @cfg {Boolean} clearUp
42377 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42382 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42387 * @cfg {Number} height (in pixels)
42391 * @cfg {Number} width (in pixels)
42396 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42399 stylesheets: false,
42404 // private properties
42405 validationEvent : false,
42407 initialized : false,
42410 onFocus : Roo.emptyFn,
42412 hideMode:'offsets',
42414 defaultAutoCreate : { // modified by initCompnoent..
42416 style:"width:500px;height:300px;",
42417 autocomplete: "off"
42421 initComponent : function(){
42424 * @event initialize
42425 * Fires when the editor is fully initialized (including the iframe)
42426 * @param {HtmlEditor} this
42431 * Fires when the editor is first receives the focus. Any insertion must wait
42432 * until after this event.
42433 * @param {HtmlEditor} this
42437 * @event beforesync
42438 * Fires before the textarea is updated with content from the editor iframe. Return false
42439 * to cancel the sync.
42440 * @param {HtmlEditor} this
42441 * @param {String} html
42445 * @event beforepush
42446 * Fires before the iframe editor is updated with content from the textarea. Return false
42447 * to cancel the push.
42448 * @param {HtmlEditor} this
42449 * @param {String} html
42454 * Fires when the textarea is updated with content from the editor iframe.
42455 * @param {HtmlEditor} this
42456 * @param {String} html
42461 * Fires when the iframe editor is updated with content from the textarea.
42462 * @param {HtmlEditor} this
42463 * @param {String} html
42467 * @event editmodechange
42468 * Fires when the editor switches edit modes
42469 * @param {HtmlEditor} this
42470 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42472 editmodechange: true,
42474 * @event editorevent
42475 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42476 * @param {HtmlEditor} this
42480 * @event firstfocus
42481 * Fires when on first focus - needed by toolbars..
42482 * @param {HtmlEditor} this
42487 * Auto save the htmlEditor value as a file into Events
42488 * @param {HtmlEditor} this
42492 * @event savedpreview
42493 * preview the saved version of htmlEditor
42494 * @param {HtmlEditor} this
42498 this.defaultAutoCreate = {
42500 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42501 autocomplete: "off"
42506 * Protected method that will not generally be called directly. It
42507 * is called when the editor creates its toolbar. Override this method if you need to
42508 * add custom toolbar buttons.
42509 * @param {HtmlEditor} editor
42511 createToolbar : function(editor){
42512 Roo.log("create toolbars");
42513 if (!editor.toolbars || !editor.toolbars.length) {
42514 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42517 for (var i =0 ; i < editor.toolbars.length;i++) {
42518 editor.toolbars[i] = Roo.factory(
42519 typeof(editor.toolbars[i]) == 'string' ?
42520 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42521 Roo.form.HtmlEditor);
42522 editor.toolbars[i].init(editor);
42530 onRender : function(ct, position)
42533 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42535 this.wrap = this.el.wrap({
42536 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42539 this.editorcore.onRender(ct, position);
42541 if (this.resizable) {
42542 this.resizeEl = new Roo.Resizable(this.wrap, {
42546 minHeight : this.height,
42547 height: this.height,
42548 handles : this.resizable,
42551 resize : function(r, w, h) {
42552 _t.onResize(w,h); // -something
42558 this.createToolbar(this);
42562 this.setSize(this.wrap.getSize());
42564 if (this.resizeEl) {
42565 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42566 // should trigger onReize..
42569 // if(this.autosave && this.w){
42570 // this.autoSaveFn = setInterval(this.autosave, 1000);
42575 onResize : function(w, h)
42577 //Roo.log('resize: ' +w + ',' + h );
42578 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42583 if(typeof w == 'number'){
42584 var aw = w - this.wrap.getFrameWidth('lr');
42585 this.el.setWidth(this.adjustWidth('textarea', aw));
42588 if(typeof h == 'number'){
42590 for (var i =0; i < this.toolbars.length;i++) {
42591 // fixme - ask toolbars for heights?
42592 tbh += this.toolbars[i].tb.el.getHeight();
42593 if (this.toolbars[i].footer) {
42594 tbh += this.toolbars[i].footer.el.getHeight();
42601 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42602 ah -= 5; // knock a few pixes off for look..
42603 this.el.setHeight(this.adjustWidth('textarea', ah));
42607 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42608 this.editorcore.onResize(ew,eh);
42613 * Toggles the editor between standard and source edit mode.
42614 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42616 toggleSourceEdit : function(sourceEditMode)
42618 this.editorcore.toggleSourceEdit(sourceEditMode);
42620 if(this.editorcore.sourceEditMode){
42621 Roo.log('editor - showing textarea');
42624 // Roo.log(this.syncValue());
42625 this.editorcore.syncValue();
42626 this.el.removeClass('x-hidden');
42627 this.el.dom.removeAttribute('tabIndex');
42630 Roo.log('editor - hiding textarea');
42632 // Roo.log(this.pushValue());
42633 this.editorcore.pushValue();
42635 this.el.addClass('x-hidden');
42636 this.el.dom.setAttribute('tabIndex', -1);
42637 //this.deferFocus();
42640 this.setSize(this.wrap.getSize());
42641 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42644 // private (for BoxComponent)
42645 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42647 // private (for BoxComponent)
42648 getResizeEl : function(){
42652 // private (for BoxComponent)
42653 getPositionEl : function(){
42658 initEvents : function(){
42659 this.originalValue = this.getValue();
42663 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42666 markInvalid : Roo.emptyFn,
42668 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42671 clearInvalid : Roo.emptyFn,
42673 setValue : function(v){
42674 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42675 this.editorcore.pushValue();
42680 deferFocus : function(){
42681 this.focus.defer(10, this);
42685 focus : function(){
42686 this.editorcore.focus();
42692 onDestroy : function(){
42698 for (var i =0; i < this.toolbars.length;i++) {
42699 // fixme - ask toolbars for heights?
42700 this.toolbars[i].onDestroy();
42703 this.wrap.dom.innerHTML = '';
42704 this.wrap.remove();
42709 onFirstFocus : function(){
42710 //Roo.log("onFirstFocus");
42711 this.editorcore.onFirstFocus();
42712 for (var i =0; i < this.toolbars.length;i++) {
42713 this.toolbars[i].onFirstFocus();
42719 syncValue : function()
42721 this.editorcore.syncValue();
42724 pushValue : function()
42726 this.editorcore.pushValue();
42730 // hide stuff that is not compatible
42744 * @event specialkey
42748 * @cfg {String} fieldClass @hide
42751 * @cfg {String} focusClass @hide
42754 * @cfg {String} autoCreate @hide
42757 * @cfg {String} inputType @hide
42760 * @cfg {String} invalidClass @hide
42763 * @cfg {String} invalidText @hide
42766 * @cfg {String} msgFx @hide
42769 * @cfg {String} validateOnBlur @hide
42773 // <script type="text/javascript">
42776 * Ext JS Library 1.1.1
42777 * Copyright(c) 2006-2007, Ext JS, LLC.
42783 * @class Roo.form.HtmlEditorToolbar1
42788 new Roo.form.HtmlEditor({
42791 new Roo.form.HtmlEditorToolbar1({
42792 disable : { fonts: 1 , format: 1, ..., ... , ...],
42798 * @cfg {Object} disable List of elements to disable..
42799 * @cfg {Array} btns List of additional buttons.
42803 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42806 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42809 Roo.apply(this, config);
42811 // default disabled, based on 'good practice'..
42812 this.disable = this.disable || {};
42813 Roo.applyIf(this.disable, {
42816 specialElements : true
42820 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42821 // dont call parent... till later.
42824 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42831 editorcore : false,
42833 * @cfg {Object} disable List of toolbar elements to disable
42840 * @cfg {String} createLinkText The default text for the create link prompt
42842 createLinkText : 'Please enter the URL for the link:',
42844 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
42846 defaultLinkValue : 'http:/'+'/',
42850 * @cfg {Array} fontFamilies An array of available font families
42868 // "á" , ?? a acute?
42873 "°" // , // degrees
42875 // "é" , // e ecute
42876 // "ú" , // u ecute?
42879 specialElements : [
42881 text: "Insert Table",
42884 ihtml : '<table><tr><td>Cell</td></tr></table>'
42888 text: "Insert Image",
42891 ihtml : '<img src="about:blank"/>'
42900 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42901 "input:submit", "input:button", "select", "textarea", "label" ],
42904 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42906 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42914 * @cfg {String} defaultFont default font to use.
42916 defaultFont: 'tahoma',
42918 fontSelect : false,
42921 formatCombo : false,
42923 init : function(editor)
42925 this.editor = editor;
42926 this.editorcore = editor.editorcore ? editor.editorcore : editor;
42927 var editorcore = this.editorcore;
42931 var fid = editorcore.frameId;
42933 function btn(id, toggle, handler){
42934 var xid = fid + '-'+ id ;
42938 cls : 'x-btn-icon x-edit-'+id,
42939 enableToggle:toggle !== false,
42940 scope: _t, // was editor...
42941 handler:handler||_t.relayBtnCmd,
42942 clickEvent:'mousedown',
42943 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42950 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
42952 // stop form submits
42953 tb.el.on('click', function(e){
42954 e.preventDefault(); // what does this do?
42957 if(!this.disable.font) { // && !Roo.isSafari){
42958 /* why no safari for fonts
42959 editor.fontSelect = tb.el.createChild({
42962 cls:'x-font-select',
42963 html: this.createFontOptions()
42966 editor.fontSelect.on('change', function(){
42967 var font = editor.fontSelect.dom.value;
42968 editor.relayCmd('fontname', font);
42969 editor.deferFocus();
42973 editor.fontSelect.dom,
42979 if(!this.disable.formats){
42980 this.formatCombo = new Roo.form.ComboBox({
42981 store: new Roo.data.SimpleStore({
42984 data : this.formats // from states.js
42988 //autoCreate : {tag: "div", size: "20"},
42989 displayField:'tag',
42993 triggerAction: 'all',
42994 emptyText:'Add tag',
42995 selectOnFocus:true,
42998 'select': function(c, r, i) {
42999 editorcore.insertTag(r.get('tag'));
43005 tb.addField(this.formatCombo);
43009 if(!this.disable.format){
43016 if(!this.disable.fontSize){
43021 btn('increasefontsize', false, editorcore.adjustFont),
43022 btn('decreasefontsize', false, editorcore.adjustFont)
43027 if(!this.disable.colors){
43030 id:editorcore.frameId +'-forecolor',
43031 cls:'x-btn-icon x-edit-forecolor',
43032 clickEvent:'mousedown',
43033 tooltip: this.buttonTips['forecolor'] || undefined,
43035 menu : new Roo.menu.ColorMenu({
43036 allowReselect: true,
43037 focus: Roo.emptyFn,
43040 selectHandler: function(cp, color){
43041 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43042 editor.deferFocus();
43045 clickEvent:'mousedown'
43048 id:editorcore.frameId +'backcolor',
43049 cls:'x-btn-icon x-edit-backcolor',
43050 clickEvent:'mousedown',
43051 tooltip: this.buttonTips['backcolor'] || undefined,
43053 menu : new Roo.menu.ColorMenu({
43054 focus: Roo.emptyFn,
43057 allowReselect: true,
43058 selectHandler: function(cp, color){
43060 editorcore.execCmd('useCSS', false);
43061 editorcore.execCmd('hilitecolor', color);
43062 editorcore.execCmd('useCSS', true);
43063 editor.deferFocus();
43065 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43066 Roo.isSafari || Roo.isIE ? '#'+color : color);
43067 editor.deferFocus();
43071 clickEvent:'mousedown'
43076 // now add all the items...
43079 if(!this.disable.alignments){
43082 btn('justifyleft'),
43083 btn('justifycenter'),
43084 btn('justifyright')
43088 //if(!Roo.isSafari){
43089 if(!this.disable.links){
43092 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43096 if(!this.disable.lists){
43099 btn('insertorderedlist'),
43100 btn('insertunorderedlist')
43103 if(!this.disable.sourceEdit){
43106 btn('sourceedit', true, function(btn){
43108 this.toggleSourceEdit(btn.pressed);
43115 // special menu.. - needs to be tidied up..
43116 if (!this.disable.special) {
43119 cls: 'x-edit-none',
43125 for (var i =0; i < this.specialChars.length; i++) {
43126 smenu.menu.items.push({
43128 html: this.specialChars[i],
43129 handler: function(a,b) {
43130 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43131 //editor.insertAtCursor(a.html);
43145 if (!this.disable.cleanStyles) {
43147 cls: 'x-btn-icon x-btn-clear',
43153 for (var i =0; i < this.cleanStyles.length; i++) {
43154 cmenu.menu.items.push({
43155 actiontype : this.cleanStyles[i],
43156 html: 'Remove ' + this.cleanStyles[i],
43157 handler: function(a,b) {
43160 var c = Roo.get(editorcore.doc.body);
43161 c.select('[style]').each(function(s) {
43162 s.dom.style.removeProperty(a.actiontype);
43164 editorcore.syncValue();
43169 cmenu.menu.items.push({
43170 actiontype : 'word',
43171 html: 'Remove MS Word Formating',
43172 handler: function(a,b) {
43173 editorcore.cleanWord();
43174 editorcore.syncValue();
43179 cmenu.menu.items.push({
43180 actiontype : 'all',
43181 html: 'Remove All Styles',
43182 handler: function(a,b) {
43184 var c = Roo.get(editorcore.doc.body);
43185 c.select('[style]').each(function(s) {
43186 s.dom.removeAttribute('style');
43188 editorcore.syncValue();
43192 cmenu.menu.items.push({
43193 actiontype : 'word',
43194 html: 'Tidy HTML Source',
43195 handler: function(a,b) {
43196 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43197 editorcore.syncValue();
43206 if (!this.disable.specialElements) {
43209 cls: 'x-edit-none',
43214 for (var i =0; i < this.specialElements.length; i++) {
43215 semenu.menu.items.push(
43217 handler: function(a,b) {
43218 editor.insertAtCursor(this.ihtml);
43220 }, this.specialElements[i])
43232 for(var i =0; i< this.btns.length;i++) {
43233 var b = Roo.factory(this.btns[i],Roo.form);
43234 b.cls = 'x-edit-none';
43235 b.scope = editorcore;
43243 // disable everything...
43245 this.tb.items.each(function(item){
43246 if(item.id != editorcore.frameId+ '-sourceedit'){
43250 this.rendered = true;
43252 // the all the btns;
43253 editor.on('editorevent', this.updateToolbar, this);
43254 // other toolbars need to implement this..
43255 //editor.on('editmodechange', this.updateToolbar, this);
43259 relayBtnCmd : function(btn) {
43260 this.editorcore.relayCmd(btn.cmd);
43262 // private used internally
43263 createLink : function(){
43264 Roo.log("create link?");
43265 var url = prompt(this.createLinkText, this.defaultLinkValue);
43266 if(url && url != 'http:/'+'/'){
43267 this.editorcore.relayCmd('createlink', url);
43273 * Protected method that will not generally be called directly. It triggers
43274 * a toolbar update by reading the markup state of the current selection in the editor.
43276 updateToolbar: function(){
43278 if(!this.editorcore.activated){
43279 this.editor.onFirstFocus();
43283 var btns = this.tb.items.map,
43284 doc = this.editorcore.doc,
43285 frameId = this.editorcore.frameId;
43287 if(!this.disable.font && !Roo.isSafari){
43289 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43290 if(name != this.fontSelect.dom.value){
43291 this.fontSelect.dom.value = name;
43295 if(!this.disable.format){
43296 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43297 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43298 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43300 if(!this.disable.alignments){
43301 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43302 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43303 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43305 if(!Roo.isSafari && !this.disable.lists){
43306 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43307 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43310 var ans = this.editorcore.getAllAncestors();
43311 if (this.formatCombo) {
43314 var store = this.formatCombo.store;
43315 this.formatCombo.setValue("");
43316 for (var i =0; i < ans.length;i++) {
43317 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43319 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43327 // hides menus... - so this cant be on a menu...
43328 Roo.menu.MenuMgr.hideAll();
43330 //this.editorsyncValue();
43334 createFontOptions : function(){
43335 var buf = [], fs = this.fontFamilies, ff, lc;
43339 for(var i = 0, len = fs.length; i< len; i++){
43341 lc = ff.toLowerCase();
43343 '<option value="',lc,'" style="font-family:',ff,';"',
43344 (this.defaultFont == lc ? ' selected="true">' : '>'),
43349 return buf.join('');
43352 toggleSourceEdit : function(sourceEditMode){
43354 Roo.log("toolbar toogle");
43355 if(sourceEditMode === undefined){
43356 sourceEditMode = !this.sourceEditMode;
43358 this.sourceEditMode = sourceEditMode === true;
43359 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43360 // just toggle the button?
43361 if(btn.pressed !== this.sourceEditMode){
43362 btn.toggle(this.sourceEditMode);
43366 if(sourceEditMode){
43367 Roo.log("disabling buttons");
43368 this.tb.items.each(function(item){
43369 if(item.cmd != 'sourceedit'){
43375 Roo.log("enabling buttons");
43376 if(this.editorcore.initialized){
43377 this.tb.items.each(function(item){
43383 Roo.log("calling toggole on editor");
43384 // tell the editor that it's been pressed..
43385 this.editor.toggleSourceEdit(sourceEditMode);
43389 * Object collection of toolbar tooltips for the buttons in the editor. The key
43390 * is the command id associated with that button and the value is a valid QuickTips object.
43395 title: 'Bold (Ctrl+B)',
43396 text: 'Make the selected text bold.',
43397 cls: 'x-html-editor-tip'
43400 title: 'Italic (Ctrl+I)',
43401 text: 'Make the selected text italic.',
43402 cls: 'x-html-editor-tip'
43410 title: 'Bold (Ctrl+B)',
43411 text: 'Make the selected text bold.',
43412 cls: 'x-html-editor-tip'
43415 title: 'Italic (Ctrl+I)',
43416 text: 'Make the selected text italic.',
43417 cls: 'x-html-editor-tip'
43420 title: 'Underline (Ctrl+U)',
43421 text: 'Underline the selected text.',
43422 cls: 'x-html-editor-tip'
43424 increasefontsize : {
43425 title: 'Grow Text',
43426 text: 'Increase the font size.',
43427 cls: 'x-html-editor-tip'
43429 decreasefontsize : {
43430 title: 'Shrink Text',
43431 text: 'Decrease the font size.',
43432 cls: 'x-html-editor-tip'
43435 title: 'Text Highlight Color',
43436 text: 'Change the background color of the selected text.',
43437 cls: 'x-html-editor-tip'
43440 title: 'Font Color',
43441 text: 'Change the color of the selected text.',
43442 cls: 'x-html-editor-tip'
43445 title: 'Align Text Left',
43446 text: 'Align text to the left.',
43447 cls: 'x-html-editor-tip'
43450 title: 'Center Text',
43451 text: 'Center text in the editor.',
43452 cls: 'x-html-editor-tip'
43455 title: 'Align Text Right',
43456 text: 'Align text to the right.',
43457 cls: 'x-html-editor-tip'
43459 insertunorderedlist : {
43460 title: 'Bullet List',
43461 text: 'Start a bulleted list.',
43462 cls: 'x-html-editor-tip'
43464 insertorderedlist : {
43465 title: 'Numbered List',
43466 text: 'Start a numbered list.',
43467 cls: 'x-html-editor-tip'
43470 title: 'Hyperlink',
43471 text: 'Make the selected text a hyperlink.',
43472 cls: 'x-html-editor-tip'
43475 title: 'Source Edit',
43476 text: 'Switch to source editing mode.',
43477 cls: 'x-html-editor-tip'
43481 onDestroy : function(){
43484 this.tb.items.each(function(item){
43486 item.menu.removeAll();
43488 item.menu.el.destroy();
43496 onFirstFocus: function() {
43497 this.tb.items.each(function(item){
43506 // <script type="text/javascript">
43509 * Ext JS Library 1.1.1
43510 * Copyright(c) 2006-2007, Ext JS, LLC.
43517 * @class Roo.form.HtmlEditor.ToolbarContext
43522 new Roo.form.HtmlEditor({
43525 { xtype: 'ToolbarStandard', styles : {} }
43526 { xtype: 'ToolbarContext', disable : {} }
43532 * @config : {Object} disable List of elements to disable.. (not done yet.)
43533 * @config : {Object} styles Map of styles available.
43537 Roo.form.HtmlEditor.ToolbarContext = function(config)
43540 Roo.apply(this, config);
43541 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43542 // dont call parent... till later.
43543 this.styles = this.styles || {};
43548 Roo.form.HtmlEditor.ToolbarContext.types = {
43560 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43626 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43631 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43641 style : 'fontFamily',
43642 displayField: 'display',
43643 optname : 'font-family',
43692 // should we really allow this??
43693 // should this just be
43704 style : 'fontFamily',
43705 displayField: 'display',
43706 optname : 'font-family',
43713 style : 'fontFamily',
43714 displayField: 'display',
43715 optname : 'font-family',
43722 style : 'fontFamily',
43723 displayField: 'display',
43724 optname : 'font-family',
43735 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43736 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43738 Roo.form.HtmlEditor.ToolbarContext.options = {
43740 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43741 [ 'Courier New', 'Courier New'],
43742 [ 'Tahoma', 'Tahoma'],
43743 [ 'Times New Roman,serif', 'Times'],
43744 [ 'Verdana','Verdana' ]
43748 // fixme - these need to be configurable..
43751 Roo.form.HtmlEditor.ToolbarContext.types
43754 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43761 editorcore : false,
43763 * @cfg {Object} disable List of toolbar elements to disable
43768 * @cfg {Object} styles List of styles
43769 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43771 * These must be defined in the page, so they get rendered correctly..
43782 init : function(editor)
43784 this.editor = editor;
43785 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43786 var editorcore = this.editorcore;
43788 var fid = editorcore.frameId;
43790 function btn(id, toggle, handler){
43791 var xid = fid + '-'+ id ;
43795 cls : 'x-btn-icon x-edit-'+id,
43796 enableToggle:toggle !== false,
43797 scope: editorcore, // was editor...
43798 handler:handler||editorcore.relayBtnCmd,
43799 clickEvent:'mousedown',
43800 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43804 // create a new element.
43805 var wdiv = editor.wrap.createChild({
43807 }, editor.wrap.dom.firstChild.nextSibling, true);
43809 // can we do this more than once??
43811 // stop form submits
43814 // disable everything...
43815 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43816 this.toolbars = {};
43818 for (var i in ty) {
43820 this.toolbars[i] = this.buildToolbar(ty[i],i);
43822 this.tb = this.toolbars.BODY;
43824 this.buildFooter();
43825 this.footer.show();
43826 editor.on('hide', function( ) { this.footer.hide() }, this);
43827 editor.on('show', function( ) { this.footer.show() }, this);
43830 this.rendered = true;
43832 // the all the btns;
43833 editor.on('editorevent', this.updateToolbar, this);
43834 // other toolbars need to implement this..
43835 //editor.on('editmodechange', this.updateToolbar, this);
43841 * Protected method that will not generally be called directly. It triggers
43842 * a toolbar update by reading the markup state of the current selection in the editor.
43844 updateToolbar: function(editor,ev,sel){
43847 // capture mouse up - this is handy for selecting images..
43848 // perhaps should go somewhere else...
43849 if(!this.editorcore.activated){
43850 this.editor.onFirstFocus();
43854 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43855 // selectNode - might want to handle IE?
43857 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43858 ev.target && ev.target.tagName == 'IMG') {
43859 // they have click on an image...
43860 // let's see if we can change the selection...
43863 var nodeRange = sel.ownerDocument.createRange();
43865 nodeRange.selectNode(sel);
43867 nodeRange.selectNodeContents(sel);
43869 //nodeRange.collapse(true);
43870 var s = this.editorcore.win.getSelection();
43871 s.removeAllRanges();
43872 s.addRange(nodeRange);
43876 var updateFooter = sel ? false : true;
43879 var ans = this.editorcore.getAllAncestors();
43882 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43885 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
43886 sel = sel ? sel : this.editorcore.doc.body;
43887 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
43890 // pick a menu that exists..
43891 var tn = sel.tagName.toUpperCase();
43892 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43894 tn = sel.tagName.toUpperCase();
43896 var lastSel = this.tb.selectedNode
43898 this.tb.selectedNode = sel;
43900 // if current menu does not match..
43901 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43904 ///console.log("show: " + tn);
43905 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43908 this.tb.items.first().el.innerHTML = tn + ': ';
43911 // update attributes
43912 if (this.tb.fields) {
43913 this.tb.fields.each(function(e) {
43915 e.setValue(sel.style[e.stylename]);
43918 e.setValue(sel.getAttribute(e.attrname));
43922 var hasStyles = false;
43923 for(var i in this.styles) {
43930 var st = this.tb.fields.item(0);
43932 st.store.removeAll();
43935 var cn = sel.className.split(/\s+/);
43938 if (this.styles['*']) {
43940 Roo.each(this.styles['*'], function(v) {
43941 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43944 if (this.styles[tn]) {
43945 Roo.each(this.styles[tn], function(v) {
43946 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43950 st.store.loadData(avs);
43954 // flag our selected Node.
43955 this.tb.selectedNode = sel;
43958 Roo.menu.MenuMgr.hideAll();
43962 if (!updateFooter) {
43963 //this.footDisp.dom.innerHTML = '';
43966 // update the footer
43970 this.footerEls = ans.reverse();
43971 Roo.each(this.footerEls, function(a,i) {
43972 if (!a) { return; }
43973 html += html.length ? ' > ' : '';
43975 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
43980 var sz = this.footDisp.up('td').getSize();
43981 this.footDisp.dom.style.width = (sz.width -10) + 'px';
43982 this.footDisp.dom.style.marginLeft = '5px';
43984 this.footDisp.dom.style.overflow = 'hidden';
43986 this.footDisp.dom.innerHTML = html;
43988 //this.editorsyncValue();
43995 onDestroy : function(){
43998 this.tb.items.each(function(item){
44000 item.menu.removeAll();
44002 item.menu.el.destroy();
44010 onFirstFocus: function() {
44011 // need to do this for all the toolbars..
44012 this.tb.items.each(function(item){
44016 buildToolbar: function(tlist, nm)
44018 var editor = this.editor;
44019 var editorcore = this.editorcore;
44020 // create a new element.
44021 var wdiv = editor.wrap.createChild({
44023 }, editor.wrap.dom.firstChild.nextSibling, true);
44026 var tb = new Roo.Toolbar(wdiv);
44029 tb.add(nm+ ": ");
44032 for(var i in this.styles) {
44037 if (styles && styles.length) {
44039 // this needs a multi-select checkbox...
44040 tb.addField( new Roo.form.ComboBox({
44041 store: new Roo.data.SimpleStore({
44043 fields: ['val', 'selected'],
44046 name : '-roo-edit-className',
44047 attrname : 'className',
44048 displayField: 'val',
44052 triggerAction: 'all',
44053 emptyText:'Select Style',
44054 selectOnFocus:true,
44057 'select': function(c, r, i) {
44058 // initial support only for on class per el..
44059 tb.selectedNode.className = r ? r.get('val') : '';
44060 editorcore.syncValue();
44067 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44068 var tbops = tbc.options;
44070 for (var i in tlist) {
44072 var item = tlist[i];
44073 tb.add(item.title + ": ");
44076 //optname == used so you can configure the options available..
44077 var opts = item.opts ? item.opts : false;
44078 if (item.optname) {
44079 opts = tbops[item.optname];
44084 // opts == pulldown..
44085 tb.addField( new Roo.form.ComboBox({
44086 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44088 fields: ['val', 'display'],
44091 name : '-roo-edit-' + i,
44093 stylename : item.style ? item.style : false,
44094 displayField: item.displayField ? item.displayField : 'val',
44095 valueField : 'val',
44097 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44099 triggerAction: 'all',
44100 emptyText:'Select',
44101 selectOnFocus:true,
44102 width: item.width ? item.width : 130,
44104 'select': function(c, r, i) {
44106 tb.selectedNode.style[c.stylename] = r.get('val');
44109 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44118 tb.addField( new Roo.form.TextField({
44121 //allowBlank:false,
44126 tb.addField( new Roo.form.TextField({
44127 name: '-roo-edit-' + i,
44134 'change' : function(f, nv, ov) {
44135 tb.selectedNode.setAttribute(f.attrname, nv);
44144 text: 'Remove Tag',
44147 click : function ()
44150 // undo does not work.
44152 var sn = tb.selectedNode;
44154 var pn = sn.parentNode;
44156 var stn = sn.childNodes[0];
44157 var en = sn.childNodes[sn.childNodes.length - 1 ];
44158 while (sn.childNodes.length) {
44159 var node = sn.childNodes[0];
44160 sn.removeChild(node);
44162 pn.insertBefore(node, sn);
44165 pn.removeChild(sn);
44166 var range = editorcore.createRange();
44168 range.setStart(stn,0);
44169 range.setEnd(en,0); //????
44170 //range.selectNode(sel);
44173 var selection = editorcore.getSelection();
44174 selection.removeAllRanges();
44175 selection.addRange(range);
44179 //_this.updateToolbar(null, null, pn);
44180 _this.updateToolbar(null, null, null);
44181 _this.footDisp.dom.innerHTML = '';
44191 tb.el.on('click', function(e){
44192 e.preventDefault(); // what does this do?
44194 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44197 // dont need to disable them... as they will get hidden
44202 buildFooter : function()
44205 var fel = this.editor.wrap.createChild();
44206 this.footer = new Roo.Toolbar(fel);
44207 // toolbar has scrolly on left / right?
44208 var footDisp= new Roo.Toolbar.Fill();
44214 handler : function() {
44215 _t.footDisp.scrollTo('left',0,true)
44219 this.footer.add( footDisp );
44224 handler : function() {
44226 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44230 var fel = Roo.get(footDisp.el);
44231 fel.addClass('x-editor-context');
44232 this.footDispWrap = fel;
44233 this.footDispWrap.overflow = 'hidden';
44235 this.footDisp = fel.createChild();
44236 this.footDispWrap.on('click', this.onContextClick, this)
44240 onContextClick : function (ev,dom)
44242 ev.preventDefault();
44243 var cn = dom.className;
44245 if (!cn.match(/x-ed-loc-/)) {
44248 var n = cn.split('-').pop();
44249 var ans = this.footerEls;
44253 var range = this.editorcore.createRange();
44255 range.selectNodeContents(sel);
44256 //range.selectNode(sel);
44259 var selection = this.editorcore.getSelection();
44260 selection.removeAllRanges();
44261 selection.addRange(range);
44265 this.updateToolbar(null, null, sel);
44282 * Ext JS Library 1.1.1
44283 * Copyright(c) 2006-2007, Ext JS, LLC.
44285 * Originally Released Under LGPL - original licence link has changed is not relivant.
44288 * <script type="text/javascript">
44292 * @class Roo.form.BasicForm
44293 * @extends Roo.util.Observable
44294 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44296 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44297 * @param {Object} config Configuration options
44299 Roo.form.BasicForm = function(el, config){
44300 this.allItems = [];
44301 this.childForms = [];
44302 Roo.apply(this, config);
44304 * The Roo.form.Field items in this form.
44305 * @type MixedCollection
44309 this.items = new Roo.util.MixedCollection(false, function(o){
44310 return o.id || (o.id = Roo.id());
44314 * @event beforeaction
44315 * Fires before any action is performed. Return false to cancel the action.
44316 * @param {Form} this
44317 * @param {Action} action The action to be performed
44319 beforeaction: true,
44321 * @event actionfailed
44322 * Fires when an action fails.
44323 * @param {Form} this
44324 * @param {Action} action The action that failed
44326 actionfailed : true,
44328 * @event actioncomplete
44329 * Fires when an action is completed.
44330 * @param {Form} this
44331 * @param {Action} action The action that completed
44333 actioncomplete : true
44338 Roo.form.BasicForm.superclass.constructor.call(this);
44341 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44343 * @cfg {String} method
44344 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44347 * @cfg {DataReader} reader
44348 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44349 * This is optional as there is built-in support for processing JSON.
44352 * @cfg {DataReader} errorReader
44353 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44354 * This is completely optional as there is built-in support for processing JSON.
44357 * @cfg {String} url
44358 * The URL to use for form actions if one isn't supplied in the action options.
44361 * @cfg {Boolean} fileUpload
44362 * Set to true if this form is a file upload.
44366 * @cfg {Object} baseParams
44367 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44372 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44377 activeAction : null,
44380 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44381 * or setValues() data instead of when the form was first created.
44383 trackResetOnLoad : false,
44387 * childForms - used for multi-tab forms
44390 childForms : false,
44393 * allItems - full list of fields.
44399 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44400 * element by passing it or its id or mask the form itself by passing in true.
44403 waitMsgTarget : false,
44406 initEl : function(el){
44407 this.el = Roo.get(el);
44408 this.id = this.el.id || Roo.id();
44409 this.el.on('submit', this.onSubmit, this);
44410 this.el.addClass('x-form');
44414 onSubmit : function(e){
44419 * Returns true if client-side validation on the form is successful.
44422 isValid : function(){
44424 this.items.each(function(f){
44433 * Returns true if any fields in this form have changed since their original load.
44436 isDirty : function(){
44438 this.items.each(function(f){
44448 * Performs a predefined action (submit or load) or custom actions you define on this form.
44449 * @param {String} actionName The name of the action type
44450 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44451 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44452 * accept other config options):
44454 Property Type Description
44455 ---------------- --------------- ----------------------------------------------------------------------------------
44456 url String The url for the action (defaults to the form's url)
44457 method String The form method to use (defaults to the form's method, or POST if not defined)
44458 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44459 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44460 validate the form on the client (defaults to false)
44462 * @return {BasicForm} this
44464 doAction : function(action, options){
44465 if(typeof action == 'string'){
44466 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44468 if(this.fireEvent('beforeaction', this, action) !== false){
44469 this.beforeAction(action);
44470 action.run.defer(100, action);
44476 * Shortcut to do a submit action.
44477 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44478 * @return {BasicForm} this
44480 submit : function(options){
44481 this.doAction('submit', options);
44486 * Shortcut to do a load action.
44487 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44488 * @return {BasicForm} this
44490 load : function(options){
44491 this.doAction('load', options);
44496 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44497 * @param {Record} record The record to edit
44498 * @return {BasicForm} this
44500 updateRecord : function(record){
44501 record.beginEdit();
44502 var fs = record.fields;
44503 fs.each(function(f){
44504 var field = this.findField(f.name);
44506 record.set(f.name, field.getValue());
44514 * Loads an Roo.data.Record into this form.
44515 * @param {Record} record The record to load
44516 * @return {BasicForm} this
44518 loadRecord : function(record){
44519 this.setValues(record.data);
44524 beforeAction : function(action){
44525 var o = action.options;
44528 if(this.waitMsgTarget === true){
44529 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44530 }else if(this.waitMsgTarget){
44531 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44532 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44534 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44540 afterAction : function(action, success){
44541 this.activeAction = null;
44542 var o = action.options;
44544 if(this.waitMsgTarget === true){
44546 }else if(this.waitMsgTarget){
44547 this.waitMsgTarget.unmask();
44549 Roo.MessageBox.updateProgress(1);
44550 Roo.MessageBox.hide();
44557 Roo.callback(o.success, o.scope, [this, action]);
44558 this.fireEvent('actioncomplete', this, action);
44562 // failure condition..
44563 // we have a scenario where updates need confirming.
44564 // eg. if a locking scenario exists..
44565 // we look for { errors : { needs_confirm : true }} in the response.
44567 (typeof(action.result) != 'undefined') &&
44568 (typeof(action.result.errors) != 'undefined') &&
44569 (typeof(action.result.errors.needs_confirm) != 'undefined')
44572 Roo.MessageBox.confirm(
44573 "Change requires confirmation",
44574 action.result.errorMsg,
44579 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44589 Roo.callback(o.failure, o.scope, [this, action]);
44590 // show an error message if no failed handler is set..
44591 if (!this.hasListener('actionfailed')) {
44592 Roo.MessageBox.alert("Error",
44593 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44594 action.result.errorMsg :
44595 "Saving Failed, please check your entries or try again"
44599 this.fireEvent('actionfailed', this, action);
44605 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44606 * @param {String} id The value to search for
44609 findField : function(id){
44610 var field = this.items.get(id);
44612 this.items.each(function(f){
44613 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44619 return field || null;
44623 * Add a secondary form to this one,
44624 * Used to provide tabbed forms. One form is primary, with hidden values
44625 * which mirror the elements from the other forms.
44627 * @param {Roo.form.Form} form to add.
44630 addForm : function(form)
44633 if (this.childForms.indexOf(form) > -1) {
44637 this.childForms.push(form);
44639 Roo.each(form.allItems, function (fe) {
44641 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44642 if (this.findField(n)) { // already added..
44645 var add = new Roo.form.Hidden({
44648 add.render(this.el);
44655 * Mark fields in this form invalid in bulk.
44656 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44657 * @return {BasicForm} this
44659 markInvalid : function(errors){
44660 if(errors instanceof Array){
44661 for(var i = 0, len = errors.length; i < len; i++){
44662 var fieldError = errors[i];
44663 var f = this.findField(fieldError.id);
44665 f.markInvalid(fieldError.msg);
44671 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44672 field.markInvalid(errors[id]);
44676 Roo.each(this.childForms || [], function (f) {
44677 f.markInvalid(errors);
44684 * Set values for fields in this form in bulk.
44685 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44686 * @return {BasicForm} this
44688 setValues : function(values){
44689 if(values instanceof Array){ // array of objects
44690 for(var i = 0, len = values.length; i < len; i++){
44692 var f = this.findField(v.id);
44694 f.setValue(v.value);
44695 if(this.trackResetOnLoad){
44696 f.originalValue = f.getValue();
44700 }else{ // object hash
44703 if(typeof values[id] != 'function' && (field = this.findField(id))){
44705 if (field.setFromData &&
44706 field.valueField &&
44707 field.displayField &&
44708 // combos' with local stores can
44709 // be queried via setValue()
44710 // to set their value..
44711 (field.store && !field.store.isLocal)
44715 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44716 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44717 field.setFromData(sd);
44720 field.setValue(values[id]);
44724 if(this.trackResetOnLoad){
44725 field.originalValue = field.getValue();
44731 Roo.each(this.childForms || [], function (f) {
44732 f.setValues(values);
44739 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44740 * they are returned as an array.
44741 * @param {Boolean} asString
44744 getValues : function(asString){
44745 if (this.childForms) {
44746 // copy values from the child forms
44747 Roo.each(this.childForms, function (f) {
44748 this.setValues(f.getValues());
44754 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44755 if(asString === true){
44758 return Roo.urlDecode(fs);
44762 * Returns the fields in this form as an object with key/value pairs.
44763 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44766 getFieldValues : function(with_hidden)
44768 if (this.childForms) {
44769 // copy values from the child forms
44770 // should this call getFieldValues - probably not as we do not currently copy
44771 // hidden fields when we generate..
44772 Roo.each(this.childForms, function (f) {
44773 this.setValues(f.getValues());
44778 this.items.each(function(f){
44779 if (!f.getName()) {
44782 var v = f.getValue();
44783 if (f.inputType =='radio') {
44784 if (typeof(ret[f.getName()]) == 'undefined') {
44785 ret[f.getName()] = ''; // empty..
44788 if (!f.el.dom.checked) {
44792 v = f.el.dom.value;
44796 // not sure if this supported any more..
44797 if ((typeof(v) == 'object') && f.getRawValue) {
44798 v = f.getRawValue() ; // dates..
44800 // combo boxes where name != hiddenName...
44801 if (f.name != f.getName()) {
44802 ret[f.name] = f.getRawValue();
44804 ret[f.getName()] = v;
44811 * Clears all invalid messages in this form.
44812 * @return {BasicForm} this
44814 clearInvalid : function(){
44815 this.items.each(function(f){
44819 Roo.each(this.childForms || [], function (f) {
44828 * Resets this form.
44829 * @return {BasicForm} this
44831 reset : function(){
44832 this.items.each(function(f){
44836 Roo.each(this.childForms || [], function (f) {
44845 * Add Roo.form components to this form.
44846 * @param {Field} field1
44847 * @param {Field} field2 (optional)
44848 * @param {Field} etc (optional)
44849 * @return {BasicForm} this
44852 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44858 * Removes a field from the items collection (does NOT remove its markup).
44859 * @param {Field} field
44860 * @return {BasicForm} this
44862 remove : function(field){
44863 this.items.remove(field);
44868 * Looks at the fields in this form, checks them for an id attribute,
44869 * and calls applyTo on the existing dom element with that id.
44870 * @return {BasicForm} this
44872 render : function(){
44873 this.items.each(function(f){
44874 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44882 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44883 * @param {Object} values
44884 * @return {BasicForm} this
44886 applyToFields : function(o){
44887 this.items.each(function(f){
44894 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44895 * @param {Object} values
44896 * @return {BasicForm} this
44898 applyIfToFields : function(o){
44899 this.items.each(function(f){
44907 Roo.BasicForm = Roo.form.BasicForm;/*
44909 * Ext JS Library 1.1.1
44910 * Copyright(c) 2006-2007, Ext JS, LLC.
44912 * Originally Released Under LGPL - original licence link has changed is not relivant.
44915 * <script type="text/javascript">
44919 * @class Roo.form.Form
44920 * @extends Roo.form.BasicForm
44921 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44923 * @param {Object} config Configuration options
44925 Roo.form.Form = function(config){
44927 if (config.items) {
44928 xitems = config.items;
44929 delete config.items;
44933 Roo.form.Form.superclass.constructor.call(this, null, config);
44934 this.url = this.url || this.action;
44936 this.root = new Roo.form.Layout(Roo.applyIf({
44940 this.active = this.root;
44942 * Array of all the buttons that have been added to this form via {@link addButton}
44946 this.allItems = [];
44949 * @event clientvalidation
44950 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
44951 * @param {Form} this
44952 * @param {Boolean} valid true if the form has passed client-side validation
44954 clientvalidation: true,
44957 * Fires when the form is rendered
44958 * @param {Roo.form.Form} form
44963 if (this.progressUrl) {
44964 // push a hidden field onto the list of fields..
44968 name : 'UPLOAD_IDENTIFIER'
44973 Roo.each(xitems, this.addxtype, this);
44979 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
44981 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
44984 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
44987 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
44989 buttonAlign:'center',
44992 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
44997 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
44998 * This property cascades to child containers if not set.
45003 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45004 * fires a looping event with that state. This is required to bind buttons to the valid
45005 * state using the config value formBind:true on the button.
45007 monitorValid : false,
45010 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45015 * @cfg {String} progressUrl - Url to return progress data
45018 progressUrl : false,
45021 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45022 * fields are added and the column is closed. If no fields are passed the column remains open
45023 * until end() is called.
45024 * @param {Object} config The config to pass to the column
45025 * @param {Field} field1 (optional)
45026 * @param {Field} field2 (optional)
45027 * @param {Field} etc (optional)
45028 * @return Column The column container object
45030 column : function(c){
45031 var col = new Roo.form.Column(c);
45033 if(arguments.length > 1){ // duplicate code required because of Opera
45034 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45041 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45042 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45043 * until end() is called.
45044 * @param {Object} config The config to pass to the fieldset
45045 * @param {Field} field1 (optional)
45046 * @param {Field} field2 (optional)
45047 * @param {Field} etc (optional)
45048 * @return FieldSet The fieldset container object
45050 fieldset : function(c){
45051 var fs = new Roo.form.FieldSet(c);
45053 if(arguments.length > 1){ // duplicate code required because of Opera
45054 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45061 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45062 * fields are added and the container is closed. If no fields are passed the container remains open
45063 * until end() is called.
45064 * @param {Object} config The config to pass to the Layout
45065 * @param {Field} field1 (optional)
45066 * @param {Field} field2 (optional)
45067 * @param {Field} etc (optional)
45068 * @return Layout The container object
45070 container : function(c){
45071 var l = new Roo.form.Layout(c);
45073 if(arguments.length > 1){ // duplicate code required because of Opera
45074 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45081 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45082 * @param {Object} container A Roo.form.Layout or subclass of Layout
45083 * @return {Form} this
45085 start : function(c){
45086 // cascade label info
45087 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45088 this.active.stack.push(c);
45089 c.ownerCt = this.active;
45095 * Closes the current open container
45096 * @return {Form} this
45099 if(this.active == this.root){
45102 this.active = this.active.ownerCt;
45107 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45108 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45109 * as the label of the field.
45110 * @param {Field} field1
45111 * @param {Field} field2 (optional)
45112 * @param {Field} etc. (optional)
45113 * @return {Form} this
45116 this.active.stack.push.apply(this.active.stack, arguments);
45117 this.allItems.push.apply(this.allItems,arguments);
45119 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45120 if(a[i].isFormField){
45125 Roo.form.Form.superclass.add.apply(this, r);
45135 * Find any element that has been added to a form, using it's ID or name
45136 * This can include framesets, columns etc. along with regular fields..
45137 * @param {String} id - id or name to find.
45139 * @return {Element} e - or false if nothing found.
45141 findbyId : function(id)
45147 Roo.each(this.allItems, function(f){
45148 if (f.id == id || f.name == id ){
45159 * Render this form into the passed container. This should only be called once!
45160 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45161 * @return {Form} this
45163 render : function(ct)
45169 var o = this.autoCreate || {
45171 method : this.method || 'POST',
45172 id : this.id || Roo.id()
45174 this.initEl(ct.createChild(o));
45176 this.root.render(this.el);
45180 this.items.each(function(f){
45181 f.render('x-form-el-'+f.id);
45184 if(this.buttons.length > 0){
45185 // tables are required to maintain order and for correct IE layout
45186 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45187 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45188 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45190 var tr = tb.getElementsByTagName('tr')[0];
45191 for(var i = 0, len = this.buttons.length; i < len; i++) {
45192 var b = this.buttons[i];
45193 var td = document.createElement('td');
45194 td.className = 'x-form-btn-td';
45195 b.render(tr.appendChild(td));
45198 if(this.monitorValid){ // initialize after render
45199 this.startMonitoring();
45201 this.fireEvent('rendered', this);
45206 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45207 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45208 * object or a valid Roo.DomHelper element config
45209 * @param {Function} handler The function called when the button is clicked
45210 * @param {Object} scope (optional) The scope of the handler function
45211 * @return {Roo.Button}
45213 addButton : function(config, handler, scope){
45217 minWidth: this.minButtonWidth,
45220 if(typeof config == "string"){
45223 Roo.apply(bc, config);
45225 var btn = new Roo.Button(null, bc);
45226 this.buttons.push(btn);
45231 * Adds a series of form elements (using the xtype property as the factory method.
45232 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45233 * @param {Object} config
45236 addxtype : function()
45238 var ar = Array.prototype.slice.call(arguments, 0);
45240 for(var i = 0; i < ar.length; i++) {
45242 continue; // skip -- if this happends something invalid got sent, we
45243 // should ignore it, as basically that interface element will not show up
45244 // and that should be pretty obvious!!
45247 if (Roo.form[ar[i].xtype]) {
45249 var fe = Roo.factory(ar[i], Roo.form);
45255 fe.store.form = this;
45260 this.allItems.push(fe);
45261 if (fe.items && fe.addxtype) {
45262 fe.addxtype.apply(fe, fe.items);
45272 // console.log('adding ' + ar[i].xtype);
45274 if (ar[i].xtype == 'Button') {
45275 //console.log('adding button');
45276 //console.log(ar[i]);
45277 this.addButton(ar[i]);
45278 this.allItems.push(fe);
45282 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45283 alert('end is not supported on xtype any more, use items');
45285 // //console.log('adding end');
45293 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45294 * option "monitorValid"
45296 startMonitoring : function(){
45299 Roo.TaskMgr.start({
45300 run : this.bindHandler,
45301 interval : this.monitorPoll || 200,
45308 * Stops monitoring of the valid state of this form
45310 stopMonitoring : function(){
45311 this.bound = false;
45315 bindHandler : function(){
45317 return false; // stops binding
45320 this.items.each(function(f){
45321 if(!f.isValid(true)){
45326 for(var i = 0, len = this.buttons.length; i < len; i++){
45327 var btn = this.buttons[i];
45328 if(btn.formBind === true && btn.disabled === valid){
45329 btn.setDisabled(!valid);
45332 this.fireEvent('clientvalidation', this, valid);
45346 Roo.Form = Roo.form.Form;
45349 * Ext JS Library 1.1.1
45350 * Copyright(c) 2006-2007, Ext JS, LLC.
45352 * Originally Released Under LGPL - original licence link has changed is not relivant.
45355 * <script type="text/javascript">
45358 // as we use this in bootstrap.
45359 Roo.namespace('Roo.form');
45361 * @class Roo.form.Action
45362 * Internal Class used to handle form actions
45364 * @param {Roo.form.BasicForm} el The form element or its id
45365 * @param {Object} config Configuration options
45370 // define the action interface
45371 Roo.form.Action = function(form, options){
45373 this.options = options || {};
45376 * Client Validation Failed
45379 Roo.form.Action.CLIENT_INVALID = 'client';
45381 * Server Validation Failed
45384 Roo.form.Action.SERVER_INVALID = 'server';
45386 * Connect to Server Failed
45389 Roo.form.Action.CONNECT_FAILURE = 'connect';
45391 * Reading Data from Server Failed
45394 Roo.form.Action.LOAD_FAILURE = 'load';
45396 Roo.form.Action.prototype = {
45398 failureType : undefined,
45399 response : undefined,
45400 result : undefined,
45402 // interface method
45403 run : function(options){
45407 // interface method
45408 success : function(response){
45412 // interface method
45413 handleResponse : function(response){
45417 // default connection failure
45418 failure : function(response){
45420 this.response = response;
45421 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45422 this.form.afterAction(this, false);
45425 processResponse : function(response){
45426 this.response = response;
45427 if(!response.responseText){
45430 this.result = this.handleResponse(response);
45431 return this.result;
45434 // utility functions used internally
45435 getUrl : function(appendParams){
45436 var url = this.options.url || this.form.url || this.form.el.dom.action;
45438 var p = this.getParams();
45440 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45446 getMethod : function(){
45447 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45450 getParams : function(){
45451 var bp = this.form.baseParams;
45452 var p = this.options.params;
45454 if(typeof p == "object"){
45455 p = Roo.urlEncode(Roo.applyIf(p, bp));
45456 }else if(typeof p == 'string' && bp){
45457 p += '&' + Roo.urlEncode(bp);
45460 p = Roo.urlEncode(bp);
45465 createCallback : function(){
45467 success: this.success,
45468 failure: this.failure,
45470 timeout: (this.form.timeout*1000),
45471 upload: this.form.fileUpload ? this.success : undefined
45476 Roo.form.Action.Submit = function(form, options){
45477 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45480 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45483 haveProgress : false,
45484 uploadComplete : false,
45486 // uploadProgress indicator.
45487 uploadProgress : function()
45489 if (!this.form.progressUrl) {
45493 if (!this.haveProgress) {
45494 Roo.MessageBox.progress("Uploading", "Uploading");
45496 if (this.uploadComplete) {
45497 Roo.MessageBox.hide();
45501 this.haveProgress = true;
45503 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45505 var c = new Roo.data.Connection();
45507 url : this.form.progressUrl,
45512 success : function(req){
45513 //console.log(data);
45517 rdata = Roo.decode(req.responseText)
45519 Roo.log("Invalid data from server..");
45523 if (!rdata || !rdata.success) {
45525 Roo.MessageBox.alert(Roo.encode(rdata));
45528 var data = rdata.data;
45530 if (this.uploadComplete) {
45531 Roo.MessageBox.hide();
45536 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45537 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45540 this.uploadProgress.defer(2000,this);
45543 failure: function(data) {
45544 Roo.log('progress url failed ');
45555 // run get Values on the form, so it syncs any secondary forms.
45556 this.form.getValues();
45558 var o = this.options;
45559 var method = this.getMethod();
45560 var isPost = method == 'POST';
45561 if(o.clientValidation === false || this.form.isValid()){
45563 if (this.form.progressUrl) {
45564 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45565 (new Date() * 1) + '' + Math.random());
45570 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45571 form:this.form.el.dom,
45572 url:this.getUrl(!isPost),
45574 params:isPost ? this.getParams() : null,
45575 isUpload: this.form.fileUpload
45578 this.uploadProgress();
45580 }else if (o.clientValidation !== false){ // client validation failed
45581 this.failureType = Roo.form.Action.CLIENT_INVALID;
45582 this.form.afterAction(this, false);
45586 success : function(response)
45588 this.uploadComplete= true;
45589 if (this.haveProgress) {
45590 Roo.MessageBox.hide();
45594 var result = this.processResponse(response);
45595 if(result === true || result.success){
45596 this.form.afterAction(this, true);
45600 this.form.markInvalid(result.errors);
45601 this.failureType = Roo.form.Action.SERVER_INVALID;
45603 this.form.afterAction(this, false);
45605 failure : function(response)
45607 this.uploadComplete= true;
45608 if (this.haveProgress) {
45609 Roo.MessageBox.hide();
45612 this.response = response;
45613 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45614 this.form.afterAction(this, false);
45617 handleResponse : function(response){
45618 if(this.form.errorReader){
45619 var rs = this.form.errorReader.read(response);
45622 for(var i = 0, len = rs.records.length; i < len; i++) {
45623 var r = rs.records[i];
45624 errors[i] = r.data;
45627 if(errors.length < 1){
45631 success : rs.success,
45637 ret = Roo.decode(response.responseText);
45641 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45651 Roo.form.Action.Load = function(form, options){
45652 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45653 this.reader = this.form.reader;
45656 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45661 Roo.Ajax.request(Roo.apply(
45662 this.createCallback(), {
45663 method:this.getMethod(),
45664 url:this.getUrl(false),
45665 params:this.getParams()
45669 success : function(response){
45671 var result = this.processResponse(response);
45672 if(result === true || !result.success || !result.data){
45673 this.failureType = Roo.form.Action.LOAD_FAILURE;
45674 this.form.afterAction(this, false);
45677 this.form.clearInvalid();
45678 this.form.setValues(result.data);
45679 this.form.afterAction(this, true);
45682 handleResponse : function(response){
45683 if(this.form.reader){
45684 var rs = this.form.reader.read(response);
45685 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45687 success : rs.success,
45691 return Roo.decode(response.responseText);
45695 Roo.form.Action.ACTION_TYPES = {
45696 'load' : Roo.form.Action.Load,
45697 'submit' : Roo.form.Action.Submit
45700 * Ext JS Library 1.1.1
45701 * Copyright(c) 2006-2007, Ext JS, LLC.
45703 * Originally Released Under LGPL - original licence link has changed is not relivant.
45706 * <script type="text/javascript">
45710 * @class Roo.form.Layout
45711 * @extends Roo.Component
45712 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45714 * @param {Object} config Configuration options
45716 Roo.form.Layout = function(config){
45718 if (config.items) {
45719 xitems = config.items;
45720 delete config.items;
45722 Roo.form.Layout.superclass.constructor.call(this, config);
45724 Roo.each(xitems, this.addxtype, this);
45728 Roo.extend(Roo.form.Layout, Roo.Component, {
45730 * @cfg {String/Object} autoCreate
45731 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45734 * @cfg {String/Object/Function} style
45735 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45736 * a function which returns such a specification.
45739 * @cfg {String} labelAlign
45740 * Valid values are "left," "top" and "right" (defaults to "left")
45743 * @cfg {Number} labelWidth
45744 * Fixed width in pixels of all field labels (defaults to undefined)
45747 * @cfg {Boolean} clear
45748 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45752 * @cfg {String} labelSeparator
45753 * The separator to use after field labels (defaults to ':')
45755 labelSeparator : ':',
45757 * @cfg {Boolean} hideLabels
45758 * True to suppress the display of field labels in this layout (defaults to false)
45760 hideLabels : false,
45763 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45768 onRender : function(ct, position){
45769 if(this.el){ // from markup
45770 this.el = Roo.get(this.el);
45771 }else { // generate
45772 var cfg = this.getAutoCreate();
45773 this.el = ct.createChild(cfg, position);
45776 this.el.applyStyles(this.style);
45778 if(this.labelAlign){
45779 this.el.addClass('x-form-label-'+this.labelAlign);
45781 if(this.hideLabels){
45782 this.labelStyle = "display:none";
45783 this.elementStyle = "padding-left:0;";
45785 if(typeof this.labelWidth == 'number'){
45786 this.labelStyle = "width:"+this.labelWidth+"px;";
45787 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45789 if(this.labelAlign == 'top'){
45790 this.labelStyle = "width:auto;";
45791 this.elementStyle = "padding-left:0;";
45794 var stack = this.stack;
45795 var slen = stack.length;
45797 if(!this.fieldTpl){
45798 var t = new Roo.Template(
45799 '<div class="x-form-item {5}">',
45800 '<label for="{0}" style="{2}">{1}{4}</label>',
45801 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45803 '</div><div class="x-form-clear-left"></div>'
45805 t.disableFormats = true;
45807 Roo.form.Layout.prototype.fieldTpl = t;
45809 for(var i = 0; i < slen; i++) {
45810 if(stack[i].isFormField){
45811 this.renderField(stack[i]);
45813 this.renderComponent(stack[i]);
45818 this.el.createChild({cls:'x-form-clear'});
45823 renderField : function(f){
45824 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45827 f.labelStyle||this.labelStyle||'', //2
45828 this.elementStyle||'', //3
45829 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45830 f.itemCls||this.itemCls||'' //5
45831 ], true).getPrevSibling());
45835 renderComponent : function(c){
45836 c.render(c.isLayout ? this.el : this.el.createChild());
45839 * Adds a object form elements (using the xtype property as the factory method.)
45840 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45841 * @param {Object} config
45843 addxtype : function(o)
45845 // create the lement.
45846 o.form = this.form;
45847 var fe = Roo.factory(o, Roo.form);
45848 this.form.allItems.push(fe);
45849 this.stack.push(fe);
45851 if (fe.isFormField) {
45852 this.form.items.add(fe);
45860 * @class Roo.form.Column
45861 * @extends Roo.form.Layout
45862 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45864 * @param {Object} config Configuration options
45866 Roo.form.Column = function(config){
45867 Roo.form.Column.superclass.constructor.call(this, config);
45870 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45872 * @cfg {Number/String} width
45873 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45876 * @cfg {String/Object} autoCreate
45877 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45881 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45884 onRender : function(ct, position){
45885 Roo.form.Column.superclass.onRender.call(this, ct, position);
45887 this.el.setWidth(this.width);
45894 * @class Roo.form.Row
45895 * @extends Roo.form.Layout
45896 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45898 * @param {Object} config Configuration options
45902 Roo.form.Row = function(config){
45903 Roo.form.Row.superclass.constructor.call(this, config);
45906 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45908 * @cfg {Number/String} width
45909 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45912 * @cfg {Number/String} height
45913 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45915 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45919 onRender : function(ct, position){
45920 //console.log('row render');
45922 var t = new Roo.Template(
45923 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45924 '<label for="{0}" style="{2}">{1}{4}</label>',
45925 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45929 t.disableFormats = true;
45931 Roo.form.Layout.prototype.rowTpl = t;
45933 this.fieldTpl = this.rowTpl;
45935 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
45936 var labelWidth = 100;
45938 if ((this.labelAlign != 'top')) {
45939 if (typeof this.labelWidth == 'number') {
45940 labelWidth = this.labelWidth
45942 this.padWidth = 20 + labelWidth;
45946 Roo.form.Column.superclass.onRender.call(this, ct, position);
45948 this.el.setWidth(this.width);
45951 this.el.setHeight(this.height);
45956 renderField : function(f){
45957 f.fieldEl = this.fieldTpl.append(this.el, [
45958 f.id, f.fieldLabel,
45959 f.labelStyle||this.labelStyle||'',
45960 this.elementStyle||'',
45961 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
45962 f.itemCls||this.itemCls||'',
45963 f.width ? f.width + this.padWidth : 160 + this.padWidth
45970 * @class Roo.form.FieldSet
45971 * @extends Roo.form.Layout
45972 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
45974 * @param {Object} config Configuration options
45976 Roo.form.FieldSet = function(config){
45977 Roo.form.FieldSet.superclass.constructor.call(this, config);
45980 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
45982 * @cfg {String} legend
45983 * The text to display as the legend for the FieldSet (defaults to '')
45986 * @cfg {String/Object} autoCreate
45987 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
45991 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
45994 onRender : function(ct, position){
45995 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
45997 this.setLegend(this.legend);
46002 setLegend : function(text){
46004 this.el.child('legend').update(text);
46009 * Ext JS Library 1.1.1
46010 * Copyright(c) 2006-2007, Ext JS, LLC.
46012 * Originally Released Under LGPL - original licence link has changed is not relivant.
46015 * <script type="text/javascript">
46018 * @class Roo.form.VTypes
46019 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46022 Roo.form.VTypes = function(){
46023 // closure these in so they are only created once.
46024 var alpha = /^[a-zA-Z_]+$/;
46025 var alphanum = /^[a-zA-Z0-9_]+$/;
46026 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46027 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46029 // All these messages and functions are configurable
46032 * The function used to validate email addresses
46033 * @param {String} value The email address
46035 'email' : function(v){
46036 return email.test(v);
46039 * The error text to display when the email validation function returns false
46042 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46044 * The keystroke filter mask to be applied on email input
46047 'emailMask' : /[a-z0-9_\.\-@]/i,
46050 * The function used to validate URLs
46051 * @param {String} value The URL
46053 'url' : function(v){
46054 return url.test(v);
46057 * The error text to display when the url validation function returns false
46060 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46063 * The function used to validate alpha values
46064 * @param {String} value The value
46066 'alpha' : function(v){
46067 return alpha.test(v);
46070 * The error text to display when the alpha validation function returns false
46073 'alphaText' : 'This field should only contain letters and _',
46075 * The keystroke filter mask to be applied on alpha input
46078 'alphaMask' : /[a-z_]/i,
46081 * The function used to validate alphanumeric values
46082 * @param {String} value The value
46084 'alphanum' : function(v){
46085 return alphanum.test(v);
46088 * The error text to display when the alphanumeric validation function returns false
46091 'alphanumText' : 'This field should only contain letters, numbers and _',
46093 * The keystroke filter mask to be applied on alphanumeric input
46096 'alphanumMask' : /[a-z0-9_]/i
46098 }();//<script type="text/javascript">
46101 * @class Roo.form.FCKeditor
46102 * @extends Roo.form.TextArea
46103 * Wrapper around the FCKEditor http://www.fckeditor.net
46105 * Creates a new FCKeditor
46106 * @param {Object} config Configuration options
46108 Roo.form.FCKeditor = function(config){
46109 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46112 * @event editorinit
46113 * Fired when the editor is initialized - you can add extra handlers here..
46114 * @param {FCKeditor} this
46115 * @param {Object} the FCK object.
46122 Roo.form.FCKeditor.editors = { };
46123 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46125 //defaultAutoCreate : {
46126 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46130 * @cfg {Object} fck options - see fck manual for details.
46135 * @cfg {Object} fck toolbar set (Basic or Default)
46137 toolbarSet : 'Basic',
46139 * @cfg {Object} fck BasePath
46141 basePath : '/fckeditor/',
46149 onRender : function(ct, position)
46152 this.defaultAutoCreate = {
46154 style:"width:300px;height:60px;",
46155 autocomplete: "off"
46158 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46161 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46162 if(this.preventScrollbars){
46163 this.el.setStyle("overflow", "hidden");
46165 this.el.setHeight(this.growMin);
46168 //console.log('onrender' + this.getId() );
46169 Roo.form.FCKeditor.editors[this.getId()] = this;
46172 this.replaceTextarea() ;
46176 getEditor : function() {
46177 return this.fckEditor;
46180 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46181 * @param {Mixed} value The value to set
46185 setValue : function(value)
46187 //console.log('setValue: ' + value);
46189 if(typeof(value) == 'undefined') { // not sure why this is happending...
46192 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46194 //if(!this.el || !this.getEditor()) {
46195 // this.value = value;
46196 //this.setValue.defer(100,this,[value]);
46200 if(!this.getEditor()) {
46204 this.getEditor().SetData(value);
46211 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46212 * @return {Mixed} value The field value
46214 getValue : function()
46217 if (this.frame && this.frame.dom.style.display == 'none') {
46218 return Roo.form.FCKeditor.superclass.getValue.call(this);
46221 if(!this.el || !this.getEditor()) {
46223 // this.getValue.defer(100,this);
46228 var value=this.getEditor().GetData();
46229 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46230 return Roo.form.FCKeditor.superclass.getValue.call(this);
46236 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46237 * @return {Mixed} value The field value
46239 getRawValue : function()
46241 if (this.frame && this.frame.dom.style.display == 'none') {
46242 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46245 if(!this.el || !this.getEditor()) {
46246 //this.getRawValue.defer(100,this);
46253 var value=this.getEditor().GetData();
46254 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46255 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46259 setSize : function(w,h) {
46263 //if (this.frame && this.frame.dom.style.display == 'none') {
46264 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46267 //if(!this.el || !this.getEditor()) {
46268 // this.setSize.defer(100,this, [w,h]);
46274 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46276 this.frame.dom.setAttribute('width', w);
46277 this.frame.dom.setAttribute('height', h);
46278 this.frame.setSize(w,h);
46282 toggleSourceEdit : function(value) {
46286 this.el.dom.style.display = value ? '' : 'none';
46287 this.frame.dom.style.display = value ? 'none' : '';
46292 focus: function(tag)
46294 if (this.frame.dom.style.display == 'none') {
46295 return Roo.form.FCKeditor.superclass.focus.call(this);
46297 if(!this.el || !this.getEditor()) {
46298 this.focus.defer(100,this, [tag]);
46305 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46306 this.getEditor().Focus();
46308 if (!this.getEditor().Selection.GetSelection()) {
46309 this.focus.defer(100,this, [tag]);
46314 var r = this.getEditor().EditorDocument.createRange();
46315 r.setStart(tgs[0],0);
46316 r.setEnd(tgs[0],0);
46317 this.getEditor().Selection.GetSelection().removeAllRanges();
46318 this.getEditor().Selection.GetSelection().addRange(r);
46319 this.getEditor().Focus();
46326 replaceTextarea : function()
46328 if ( document.getElementById( this.getId() + '___Frame' ) )
46330 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46332 // We must check the elements firstly using the Id and then the name.
46333 var oTextarea = document.getElementById( this.getId() );
46335 var colElementsByName = document.getElementsByName( this.getId() ) ;
46337 oTextarea.style.display = 'none' ;
46339 if ( oTextarea.tabIndex ) {
46340 this.TabIndex = oTextarea.tabIndex ;
46343 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46344 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46345 this.frame = Roo.get(this.getId() + '___Frame')
46348 _getConfigHtml : function()
46352 for ( var o in this.fckconfig ) {
46353 sConfig += sConfig.length > 0 ? '&' : '';
46354 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46357 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46361 _getIFrameHtml : function()
46363 var sFile = 'fckeditor.html' ;
46364 /* no idea what this is about..
46367 if ( (/fcksource=true/i).test( window.top.location.search ) )
46368 sFile = 'fckeditor.original.html' ;
46373 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46374 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46377 var html = '<iframe id="' + this.getId() +
46378 '___Frame" src="' + sLink +
46379 '" width="' + this.width +
46380 '" height="' + this.height + '"' +
46381 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46382 ' frameborder="0" scrolling="no"></iframe>' ;
46387 _insertHtmlBefore : function( html, element )
46389 if ( element.insertAdjacentHTML ) {
46391 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46393 var oRange = document.createRange() ;
46394 oRange.setStartBefore( element ) ;
46395 var oFragment = oRange.createContextualFragment( html );
46396 element.parentNode.insertBefore( oFragment, element ) ;
46409 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46411 function FCKeditor_OnComplete(editorInstance){
46412 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46413 f.fckEditor = editorInstance;
46414 //console.log("loaded");
46415 f.fireEvent('editorinit', f, editorInstance);
46435 //<script type="text/javascript">
46437 * @class Roo.form.GridField
46438 * @extends Roo.form.Field
46439 * Embed a grid (or editable grid into a form)
46442 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46444 * xgrid.store = Roo.data.Store
46445 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46446 * xgrid.store.reader = Roo.data.JsonReader
46450 * Creates a new GridField
46451 * @param {Object} config Configuration options
46453 Roo.form.GridField = function(config){
46454 Roo.form.GridField.superclass.constructor.call(this, config);
46458 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46460 * @cfg {Number} width - used to restrict width of grid..
46464 * @cfg {Number} height - used to restrict height of grid..
46468 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46474 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46475 * {tag: "input", type: "checkbox", autocomplete: "off"})
46477 // defaultAutoCreate : { tag: 'div' },
46478 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46480 * @cfg {String} addTitle Text to include for adding a title.
46484 onResize : function(){
46485 Roo.form.Field.superclass.onResize.apply(this, arguments);
46488 initEvents : function(){
46489 // Roo.form.Checkbox.superclass.initEvents.call(this);
46490 // has no events...
46495 getResizeEl : function(){
46499 getPositionEl : function(){
46504 onRender : function(ct, position){
46506 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46507 var style = this.style;
46510 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46511 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46512 this.viewEl = this.wrap.createChild({ tag: 'div' });
46514 this.viewEl.applyStyles(style);
46517 this.viewEl.setWidth(this.width);
46520 this.viewEl.setHeight(this.height);
46522 //if(this.inputValue !== undefined){
46523 //this.setValue(this.value);
46526 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46529 this.grid.render();
46530 this.grid.getDataSource().on('remove', this.refreshValue, this);
46531 this.grid.getDataSource().on('update', this.refreshValue, this);
46532 this.grid.on('afteredit', this.refreshValue, this);
46538 * Sets the value of the item.
46539 * @param {String} either an object or a string..
46541 setValue : function(v){
46543 v = v || []; // empty set..
46544 // this does not seem smart - it really only affects memoryproxy grids..
46545 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46546 var ds = this.grid.getDataSource();
46547 // assumes a json reader..
46549 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46550 ds.loadData( data);
46552 // clear selection so it does not get stale.
46553 if (this.grid.sm) {
46554 this.grid.sm.clearSelections();
46557 Roo.form.GridField.superclass.setValue.call(this, v);
46558 this.refreshValue();
46559 // should load data in the grid really....
46563 refreshValue: function() {
46565 this.grid.getDataSource().each(function(r) {
46568 this.el.dom.value = Roo.encode(val);
46576 * Ext JS Library 1.1.1
46577 * Copyright(c) 2006-2007, Ext JS, LLC.
46579 * Originally Released Under LGPL - original licence link has changed is not relivant.
46582 * <script type="text/javascript">
46585 * @class Roo.form.DisplayField
46586 * @extends Roo.form.Field
46587 * A generic Field to display non-editable data.
46589 * Creates a new Display Field item.
46590 * @param {Object} config Configuration options
46592 Roo.form.DisplayField = function(config){
46593 Roo.form.DisplayField.superclass.constructor.call(this, config);
46597 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46598 inputType: 'hidden',
46604 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46606 focusClass : undefined,
46608 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46610 fieldClass: 'x-form-field',
46613 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46615 valueRenderer: undefined,
46619 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46620 * {tag: "input", type: "checkbox", autocomplete: "off"})
46623 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46625 onResize : function(){
46626 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46630 initEvents : function(){
46631 // Roo.form.Checkbox.superclass.initEvents.call(this);
46632 // has no events...
46637 getResizeEl : function(){
46641 getPositionEl : function(){
46646 onRender : function(ct, position){
46648 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46649 //if(this.inputValue !== undefined){
46650 this.wrap = this.el.wrap();
46652 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46654 if (this.bodyStyle) {
46655 this.viewEl.applyStyles(this.bodyStyle);
46657 //this.viewEl.setStyle('padding', '2px');
46659 this.setValue(this.value);
46664 initValue : Roo.emptyFn,
46669 onClick : function(){
46674 * Sets the checked state of the checkbox.
46675 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46677 setValue : function(v){
46679 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46680 // this might be called before we have a dom element..
46681 if (!this.viewEl) {
46684 this.viewEl.dom.innerHTML = html;
46685 Roo.form.DisplayField.superclass.setValue.call(this, v);
46695 * @class Roo.form.DayPicker
46696 * @extends Roo.form.Field
46697 * A Day picker show [M] [T] [W] ....
46699 * Creates a new Day Picker
46700 * @param {Object} config Configuration options
46702 Roo.form.DayPicker= function(config){
46703 Roo.form.DayPicker.superclass.constructor.call(this, config);
46707 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46709 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46711 focusClass : undefined,
46713 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46715 fieldClass: "x-form-field",
46718 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46719 * {tag: "input", type: "checkbox", autocomplete: "off"})
46721 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46724 actionMode : 'viewEl',
46728 inputType : 'hidden',
46731 inputElement: false, // real input element?
46732 basedOn: false, // ????
46734 isFormField: true, // not sure where this is needed!!!!
46736 onResize : function(){
46737 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46738 if(!this.boxLabel){
46739 this.el.alignTo(this.wrap, 'c-c');
46743 initEvents : function(){
46744 Roo.form.Checkbox.superclass.initEvents.call(this);
46745 this.el.on("click", this.onClick, this);
46746 this.el.on("change", this.onClick, this);
46750 getResizeEl : function(){
46754 getPositionEl : function(){
46760 onRender : function(ct, position){
46761 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46763 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46765 var r1 = '<table><tr>';
46766 var r2 = '<tr class="x-form-daypick-icons">';
46767 for (var i=0; i < 7; i++) {
46768 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46769 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46772 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46773 viewEl.select('img').on('click', this.onClick, this);
46774 this.viewEl = viewEl;
46777 // this will not work on Chrome!!!
46778 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46779 this.el.on('propertychange', this.setFromHidden, this); //ie
46787 initValue : Roo.emptyFn,
46790 * Returns the checked state of the checkbox.
46791 * @return {Boolean} True if checked, else false
46793 getValue : function(){
46794 return this.el.dom.value;
46799 onClick : function(e){
46800 //this.setChecked(!this.checked);
46801 Roo.get(e.target).toggleClass('x-menu-item-checked');
46802 this.refreshValue();
46803 //if(this.el.dom.checked != this.checked){
46804 // this.setValue(this.el.dom.checked);
46809 refreshValue : function()
46812 this.viewEl.select('img',true).each(function(e,i,n) {
46813 val += e.is(".x-menu-item-checked") ? String(n) : '';
46815 this.setValue(val, true);
46819 * Sets the checked state of the checkbox.
46820 * On is always based on a string comparison between inputValue and the param.
46821 * @param {Boolean/String} value - the value to set
46822 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46824 setValue : function(v,suppressEvent){
46825 if (!this.el.dom) {
46828 var old = this.el.dom.value ;
46829 this.el.dom.value = v;
46830 if (suppressEvent) {
46834 // update display..
46835 this.viewEl.select('img',true).each(function(e,i,n) {
46837 var on = e.is(".x-menu-item-checked");
46838 var newv = v.indexOf(String(n)) > -1;
46840 e.toggleClass('x-menu-item-checked');
46846 this.fireEvent('change', this, v, old);
46851 // handle setting of hidden value by some other method!!?!?
46852 setFromHidden: function()
46857 //console.log("SET FROM HIDDEN");
46858 //alert('setFrom hidden');
46859 this.setValue(this.el.dom.value);
46862 onDestroy : function()
46865 Roo.get(this.viewEl).remove();
46868 Roo.form.DayPicker.superclass.onDestroy.call(this);
46872 * RooJS Library 1.1.1
46873 * Copyright(c) 2008-2011 Alan Knowles
46880 * @class Roo.form.ComboCheck
46881 * @extends Roo.form.ComboBox
46882 * A combobox for multiple select items.
46884 * FIXME - could do with a reset button..
46887 * Create a new ComboCheck
46888 * @param {Object} config Configuration options
46890 Roo.form.ComboCheck = function(config){
46891 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46892 // should verify some data...
46894 // hiddenName = required..
46895 // displayField = required
46896 // valudField == required
46897 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46899 Roo.each(req, function(e) {
46900 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46901 throw "Roo.form.ComboCheck : missing value for: " + e;
46908 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46913 selectedClass: 'x-menu-item-checked',
46916 onRender : function(ct, position){
46922 var cls = 'x-combo-list';
46925 this.tpl = new Roo.Template({
46926 html : '<div class="'+cls+'-item x-menu-check-item">' +
46927 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
46928 '<span>{' + this.displayField + '}</span>' +
46935 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
46936 this.view.singleSelect = false;
46937 this.view.multiSelect = true;
46938 this.view.toggleSelect = true;
46939 this.pageTb.add(new Roo.Toolbar.Fill(), {
46942 handler: function()
46949 onViewOver : function(e, t){
46955 onViewClick : function(doFocus,index){
46959 select: function () {
46960 //Roo.log("SELECT CALLED");
46963 selectByValue : function(xv, scrollIntoView){
46964 var ar = this.getValueArray();
46967 Roo.each(ar, function(v) {
46968 if(v === undefined || v === null){
46971 var r = this.findRecord(this.valueField, v);
46973 sels.push(this.store.indexOf(r))
46977 this.view.select(sels);
46983 onSelect : function(record, index){
46984 // Roo.log("onselect Called");
46985 // this is only called by the clear button now..
46986 this.view.clearSelections();
46987 this.setValue('[]');
46988 if (this.value != this.valueBefore) {
46989 this.fireEvent('change', this, this.value, this.valueBefore);
46990 this.valueBefore = this.value;
46993 getValueArray : function()
46998 //Roo.log(this.value);
46999 if (typeof(this.value) == 'undefined') {
47002 var ar = Roo.decode(this.value);
47003 return ar instanceof Array ? ar : []; //?? valid?
47006 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47011 expand : function ()
47014 Roo.form.ComboCheck.superclass.expand.call(this);
47015 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47016 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47021 collapse : function(){
47022 Roo.form.ComboCheck.superclass.collapse.call(this);
47023 var sl = this.view.getSelectedIndexes();
47024 var st = this.store;
47028 Roo.each(sl, function(i) {
47030 nv.push(r.get(this.valueField));
47032 this.setValue(Roo.encode(nv));
47033 if (this.value != this.valueBefore) {
47035 this.fireEvent('change', this, this.value, this.valueBefore);
47036 this.valueBefore = this.value;
47041 setValue : function(v){
47045 var vals = this.getValueArray();
47047 Roo.each(vals, function(k) {
47048 var r = this.findRecord(this.valueField, k);
47050 tv.push(r.data[this.displayField]);
47051 }else if(this.valueNotFoundText !== undefined){
47052 tv.push( this.valueNotFoundText );
47057 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47058 this.hiddenField.value = v;
47064 * Ext JS Library 1.1.1
47065 * Copyright(c) 2006-2007, Ext JS, LLC.
47067 * Originally Released Under LGPL - original licence link has changed is not relivant.
47070 * <script type="text/javascript">
47074 * @class Roo.form.Signature
47075 * @extends Roo.form.Field
47079 * @param {Object} config Configuration options
47082 Roo.form.Signature = function(config){
47083 Roo.form.Signature.superclass.constructor.call(this, config);
47085 this.addEvents({// not in used??
47088 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47089 * @param {Roo.form.Signature} combo This combo box
47094 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47095 * @param {Roo.form.ComboBox} combo This combo box
47096 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47102 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47104 * @cfg {Object} labels Label to use when rendering a form.
47108 * confirm : "Confirm"
47113 confirm : "Confirm"
47116 * @cfg {Number} width The signature panel width (defaults to 300)
47120 * @cfg {Number} height The signature panel height (defaults to 100)
47124 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47126 allowBlank : false,
47129 // {Object} signPanel The signature SVG panel element (defaults to {})
47131 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47132 isMouseDown : false,
47133 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47134 isConfirmed : false,
47135 // {String} signatureTmp SVG mapping string (defaults to empty string)
47139 defaultAutoCreate : { // modified by initCompnoent..
47145 onRender : function(ct, position){
47147 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47149 this.wrap = this.el.wrap({
47150 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47153 this.createToolbar(this);
47154 this.signPanel = this.wrap.createChild({
47156 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47160 this.svgID = Roo.id();
47161 this.svgEl = this.signPanel.createChild({
47162 xmlns : 'http://www.w3.org/2000/svg',
47164 id : this.svgID + "-svg",
47166 height: this.height,
47167 viewBox: '0 0 '+this.width+' '+this.height,
47171 id: this.svgID + "-svg-r",
47173 height: this.height,
47178 id: this.svgID + "-svg-l",
47180 y1: (this.height*0.8), // start set the line in 80% of height
47181 x2: this.width, // end
47182 y2: (this.height*0.8), // end set the line in 80% of height
47184 'stroke-width': "1",
47185 'stroke-dasharray': "3",
47186 'shape-rendering': "crispEdges",
47187 'pointer-events': "none"
47191 id: this.svgID + "-svg-p",
47193 'stroke-width': "3",
47195 'pointer-events': 'none'
47200 this.svgBox = this.svgEl.dom.getScreenCTM();
47202 createSVG : function(){
47203 var svg = this.signPanel;
47204 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47207 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47208 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47209 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47210 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47211 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47212 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47213 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47216 isTouchEvent : function(e){
47217 return e.type.match(/^touch/);
47219 getCoords : function (e) {
47220 var pt = this.svgEl.dom.createSVGPoint();
47223 if (this.isTouchEvent(e)) {
47224 pt.x = e.targetTouches[0].clientX
47225 pt.y = e.targetTouches[0].clientY;
47227 var a = this.svgEl.dom.getScreenCTM();
47228 var b = a.inverse();
47229 var mx = pt.matrixTransform(b);
47230 return mx.x + ',' + mx.y;
47232 //mouse event headler
47233 down : function (e) {
47234 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47235 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47237 this.isMouseDown = true;
47239 e.preventDefault();
47241 move : function (e) {
47242 if (this.isMouseDown) {
47243 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47244 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47247 e.preventDefault();
47249 up : function (e) {
47250 this.isMouseDown = false;
47251 var sp = this.signatureTmp.split(' ');
47254 if(!sp[sp.length-2].match(/^L/)){
47258 this.signatureTmp = sp.join(" ");
47261 if(this.getValue() != this.signatureTmp){
47262 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47263 this.isConfirmed = false;
47265 e.preventDefault();
47269 * Protected method that will not generally be called directly. It
47270 * is called when the editor creates its toolbar. Override this method if you need to
47271 * add custom toolbar buttons.
47272 * @param {HtmlEditor} editor
47274 createToolbar : function(editor){
47275 function btn(id, toggle, handler){
47276 var xid = fid + '-'+ id ;
47280 cls : 'x-btn-icon x-edit-'+id,
47281 enableToggle:toggle !== false,
47282 scope: editor, // was editor...
47283 handler:handler||editor.relayBtnCmd,
47284 clickEvent:'mousedown',
47285 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47291 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47295 cls : ' x-signature-btn x-signature-'+id,
47296 scope: editor, // was editor...
47297 handler: this.reset,
47298 clickEvent:'mousedown',
47299 text: this.labels.clear
47306 cls : ' x-signature-btn x-signature-'+id,
47307 scope: editor, // was editor...
47308 handler: this.confirmHandler,
47309 clickEvent:'mousedown',
47310 text: this.labels.confirm
47317 * when user is clicked confirm then show this image.....
47319 * @return {String} Image Data URI
47321 getImageDataURI : function(){
47322 var svg = this.svgEl.dom.parentNode.innerHTML;
47323 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47328 * @return {Boolean} this.isConfirmed
47330 getConfirmed : function(){
47331 return this.isConfirmed;
47335 * @return {Number} this.width
47337 getWidth : function(){
47342 * @return {Number} this.height
47344 getHeight : function(){
47345 return this.height;
47348 getSignature : function(){
47349 return this.signatureTmp;
47352 reset : function(){
47353 this.signatureTmp = '';
47354 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47355 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47356 this.isConfirmed = false;
47357 Roo.form.Signature.superclass.reset.call(this);
47359 setSignature : function(s){
47360 this.signatureTmp = s;
47361 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47362 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47364 this.isConfirmed = false;
47365 Roo.form.Signature.superclass.reset.call(this);
47368 // Roo.log(this.signPanel.dom.contentWindow.up())
47371 setConfirmed : function(){
47375 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47378 confirmHandler : function(){
47379 if(!this.getSignature()){
47383 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47384 this.setValue(this.getSignature());
47385 this.isConfirmed = true;
47387 this.fireEvent('confirm', this);
47390 // Subclasses should provide the validation implementation by overriding this
47391 validateValue : function(value){
47392 if(this.allowBlank){
47396 if(this.isConfirmed){
47403 * Ext JS Library 1.1.1
47404 * Copyright(c) 2006-2007, Ext JS, LLC.
47406 * Originally Released Under LGPL - original licence link has changed is not relivant.
47409 * <script type="text/javascript">
47414 * @class Roo.form.ComboBox
47415 * @extends Roo.form.TriggerField
47416 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47418 * Create a new ComboBox.
47419 * @param {Object} config Configuration options
47421 Roo.form.Select = function(config){
47422 Roo.form.Select.superclass.constructor.call(this, config);
47426 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47428 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47431 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47432 * rendering into an Roo.Editor, defaults to false)
47435 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47436 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47439 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47442 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47443 * the dropdown list (defaults to undefined, with no header element)
47447 * @cfg {String/Roo.Template} tpl The template to use to render the output
47451 defaultAutoCreate : {tag: "select" },
47453 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47455 listWidth: undefined,
47457 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47458 * mode = 'remote' or 'text' if mode = 'local')
47460 displayField: undefined,
47462 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47463 * mode = 'remote' or 'value' if mode = 'local').
47464 * Note: use of a valueField requires the user make a selection
47465 * in order for a value to be mapped.
47467 valueField: undefined,
47471 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47472 * field's data value (defaults to the underlying DOM element's name)
47474 hiddenName: undefined,
47476 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47480 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47482 selectedClass: 'x-combo-selected',
47484 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47485 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47486 * which displays a downward arrow icon).
47488 triggerClass : 'x-form-arrow-trigger',
47490 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47494 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47495 * anchor positions (defaults to 'tl-bl')
47497 listAlign: 'tl-bl?',
47499 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47503 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47504 * query specified by the allQuery config option (defaults to 'query')
47506 triggerAction: 'query',
47508 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47509 * (defaults to 4, does not apply if editable = false)
47513 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47514 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47518 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47519 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47523 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47524 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47528 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47529 * when editable = true (defaults to false)
47531 selectOnFocus:false,
47533 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47535 queryParam: 'query',
47537 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47538 * when mode = 'remote' (defaults to 'Loading...')
47540 loadingText: 'Loading...',
47542 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47546 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47550 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47551 * traditional select (defaults to true)
47555 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47559 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47563 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47564 * listWidth has a higher value)
47568 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47569 * allow the user to set arbitrary text into the field (defaults to false)
47571 forceSelection:false,
47573 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47574 * if typeAhead = true (defaults to 250)
47576 typeAheadDelay : 250,
47578 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47579 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47581 valueNotFoundText : undefined,
47584 * @cfg {String} defaultValue The value displayed after loading the store.
47589 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47591 blockFocus : false,
47594 * @cfg {Boolean} disableClear Disable showing of clear button.
47596 disableClear : false,
47598 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47600 alwaysQuery : false,
47606 // element that contains real text value.. (when hidden is used..)
47609 onRender : function(ct, position){
47610 Roo.form.Field.prototype.onRender.call(this, ct, position);
47613 this.store.on('beforeload', this.onBeforeLoad, this);
47614 this.store.on('load', this.onLoad, this);
47615 this.store.on('loadexception', this.onLoadException, this);
47616 this.store.load({});
47624 initEvents : function(){
47625 //Roo.form.ComboBox.superclass.initEvents.call(this);
47629 onDestroy : function(){
47632 this.store.un('beforeload', this.onBeforeLoad, this);
47633 this.store.un('load', this.onLoad, this);
47634 this.store.un('loadexception', this.onLoadException, this);
47636 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47640 fireKey : function(e){
47641 if(e.isNavKeyPress() && !this.list.isVisible()){
47642 this.fireEvent("specialkey", this, e);
47647 onResize: function(w, h){
47655 * Allow or prevent the user from directly editing the field text. If false is passed,
47656 * the user will only be able to select from the items defined in the dropdown list. This method
47657 * is the runtime equivalent of setting the 'editable' config option at config time.
47658 * @param {Boolean} value True to allow the user to directly edit the field text
47660 setEditable : function(value){
47665 onBeforeLoad : function(){
47667 Roo.log("Select before load");
47670 this.innerList.update(this.loadingText ?
47671 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47672 //this.restrictHeight();
47673 this.selectedIndex = -1;
47677 onLoad : function(){
47680 var dom = this.el.dom;
47681 dom.innerHTML = '';
47682 var od = dom.ownerDocument;
47684 if (this.emptyText) {
47685 var op = od.createElement('option');
47686 op.setAttribute('value', '');
47687 op.innerHTML = String.format('{0}', this.emptyText);
47688 dom.appendChild(op);
47690 if(this.store.getCount() > 0){
47692 var vf = this.valueField;
47693 var df = this.displayField;
47694 this.store.data.each(function(r) {
47695 // which colmsn to use... testing - cdoe / title..
47696 var op = od.createElement('option');
47697 op.setAttribute('value', r.data[vf]);
47698 op.innerHTML = String.format('{0}', r.data[df]);
47699 dom.appendChild(op);
47701 if (typeof(this.defaultValue != 'undefined')) {
47702 this.setValue(this.defaultValue);
47707 //this.onEmptyResults();
47712 onLoadException : function()
47714 dom.innerHTML = '';
47716 Roo.log("Select on load exception");
47720 Roo.log(this.store.reader.jsonData);
47721 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47722 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47728 onTypeAhead : function(){
47733 onSelect : function(record, index){
47734 Roo.log('on select?');
47736 if(this.fireEvent('beforeselect', this, record, index) !== false){
47737 this.setFromData(index > -1 ? record.data : false);
47739 this.fireEvent('select', this, record, index);
47744 * Returns the currently selected field value or empty string if no value is set.
47745 * @return {String} value The selected value
47747 getValue : function(){
47748 var dom = this.el.dom;
47749 this.value = dom.options[dom.selectedIndex].value;
47755 * Clears any text/value currently set in the field
47757 clearValue : function(){
47759 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47764 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47765 * will be displayed in the field. If the value does not match the data value of an existing item,
47766 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47767 * Otherwise the field will be blank (although the value will still be set).
47768 * @param {String} value The value to match
47770 setValue : function(v){
47771 var d = this.el.dom;
47772 for (var i =0; i < d.options.length;i++) {
47773 if (v == d.options[i].value) {
47774 d.selectedIndex = i;
47782 * @property {Object} the last set data for the element
47787 * Sets the value of the field based on a object which is related to the record format for the store.
47788 * @param {Object} value the value to set as. or false on reset?
47790 setFromData : function(o){
47791 Roo.log('setfrom data?');
47797 reset : function(){
47801 findRecord : function(prop, value){
47806 if(this.store.getCount() > 0){
47807 this.store.each(function(r){
47808 if(r.data[prop] == value){
47818 getName: function()
47820 // returns hidden if it's set..
47821 if (!this.rendered) {return ''};
47822 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47830 onEmptyResults : function(){
47831 Roo.log('empty results');
47836 * Returns true if the dropdown list is expanded, else false.
47838 isExpanded : function(){
47843 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47844 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47845 * @param {String} value The data value of the item to select
47846 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47847 * selected item if it is not currently in view (defaults to true)
47848 * @return {Boolean} True if the value matched an item in the list, else false
47850 selectByValue : function(v, scrollIntoView){
47851 Roo.log('select By Value');
47854 if(v !== undefined && v !== null){
47855 var r = this.findRecord(this.valueField || this.displayField, v);
47857 this.select(this.store.indexOf(r), scrollIntoView);
47865 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47866 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47867 * @param {Number} index The zero-based index of the list item to select
47868 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47869 * selected item if it is not currently in view (defaults to true)
47871 select : function(index, scrollIntoView){
47872 Roo.log('select ');
47875 this.selectedIndex = index;
47876 this.view.select(index);
47877 if(scrollIntoView !== false){
47878 var el = this.view.getNode(index);
47880 this.innerList.scrollChildIntoView(el, false);
47888 validateBlur : function(){
47895 initQuery : function(){
47896 this.doQuery(this.getRawValue());
47900 doForce : function(){
47901 if(this.el.dom.value.length > 0){
47902 this.el.dom.value =
47903 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47909 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47910 * query allowing the query action to be canceled if needed.
47911 * @param {String} query The SQL query to execute
47912 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47913 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47914 * saved in the current store (defaults to false)
47916 doQuery : function(q, forceAll){
47918 Roo.log('doQuery?');
47919 if(q === undefined || q === null){
47924 forceAll: forceAll,
47928 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
47932 forceAll = qe.forceAll;
47933 if(forceAll === true || (q.length >= this.minChars)){
47934 if(this.lastQuery != q || this.alwaysQuery){
47935 this.lastQuery = q;
47936 if(this.mode == 'local'){
47937 this.selectedIndex = -1;
47939 this.store.clearFilter();
47941 this.store.filter(this.displayField, q);
47945 this.store.baseParams[this.queryParam] = q;
47947 params: this.getParams(q)
47952 this.selectedIndex = -1;
47959 getParams : function(q){
47961 //p[this.queryParam] = q;
47964 p.limit = this.pageSize;
47970 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
47972 collapse : function(){
47977 collapseIf : function(e){
47982 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
47984 expand : function(){
47992 * @cfg {Boolean} grow
47996 * @cfg {Number} growMin
48000 * @cfg {Number} growMax
48008 setWidth : function()
48012 getResizeEl : function(){
48015 });//<script type="text/javasscript">
48019 * @class Roo.DDView
48020 * A DnD enabled version of Roo.View.
48021 * @param {Element/String} container The Element in which to create the View.
48022 * @param {String} tpl The template string used to create the markup for each element of the View
48023 * @param {Object} config The configuration properties. These include all the config options of
48024 * {@link Roo.View} plus some specific to this class.<br>
48026 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48027 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48029 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48030 .x-view-drag-insert-above {
48031 border-top:1px dotted #3366cc;
48033 .x-view-drag-insert-below {
48034 border-bottom:1px dotted #3366cc;
48040 Roo.DDView = function(container, tpl, config) {
48041 Roo.DDView.superclass.constructor.apply(this, arguments);
48042 this.getEl().setStyle("outline", "0px none");
48043 this.getEl().unselectable();
48044 if (this.dragGroup) {
48045 this.setDraggable(this.dragGroup.split(","));
48047 if (this.dropGroup) {
48048 this.setDroppable(this.dropGroup.split(","));
48050 if (this.deletable) {
48051 this.setDeletable();
48053 this.isDirtyFlag = false;
48059 Roo.extend(Roo.DDView, Roo.View, {
48060 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48061 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48062 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48063 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48067 reset: Roo.emptyFn,
48069 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48071 validate: function() {
48075 destroy: function() {
48076 this.purgeListeners();
48077 this.getEl.removeAllListeners();
48078 this.getEl().remove();
48079 if (this.dragZone) {
48080 if (this.dragZone.destroy) {
48081 this.dragZone.destroy();
48084 if (this.dropZone) {
48085 if (this.dropZone.destroy) {
48086 this.dropZone.destroy();
48091 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48092 getName: function() {
48096 /** Loads the View from a JSON string representing the Records to put into the Store. */
48097 setValue: function(v) {
48099 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48102 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48103 this.store.proxy = new Roo.data.MemoryProxy(data);
48107 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48108 getValue: function() {
48110 this.store.each(function(rec) {
48111 result += rec.id + ',';
48113 return result.substr(0, result.length - 1) + ')';
48116 getIds: function() {
48117 var i = 0, result = new Array(this.store.getCount());
48118 this.store.each(function(rec) {
48119 result[i++] = rec.id;
48124 isDirty: function() {
48125 return this.isDirtyFlag;
48129 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48130 * whole Element becomes the target, and this causes the drop gesture to append.
48132 getTargetFromEvent : function(e) {
48133 var target = e.getTarget();
48134 while ((target !== null) && (target.parentNode != this.el.dom)) {
48135 target = target.parentNode;
48138 target = this.el.dom.lastChild || this.el.dom;
48144 * Create the drag data which consists of an object which has the property "ddel" as
48145 * the drag proxy element.
48147 getDragData : function(e) {
48148 var target = this.findItemFromChild(e.getTarget());
48150 this.handleSelection(e);
48151 var selNodes = this.getSelectedNodes();
48154 copy: this.copy || (this.allowCopy && e.ctrlKey),
48158 var selectedIndices = this.getSelectedIndexes();
48159 for (var i = 0; i < selectedIndices.length; i++) {
48160 dragData.records.push(this.store.getAt(selectedIndices[i]));
48162 if (selNodes.length == 1) {
48163 dragData.ddel = target.cloneNode(true); // the div element
48165 var div = document.createElement('div'); // create the multi element drag "ghost"
48166 div.className = 'multi-proxy';
48167 for (var i = 0, len = selNodes.length; i < len; i++) {
48168 div.appendChild(selNodes[i].cloneNode(true));
48170 dragData.ddel = div;
48172 //console.log(dragData)
48173 //console.log(dragData.ddel.innerHTML)
48176 //console.log('nodragData')
48180 /** Specify to which ddGroup items in this DDView may be dragged. */
48181 setDraggable: function(ddGroup) {
48182 if (ddGroup instanceof Array) {
48183 Roo.each(ddGroup, this.setDraggable, this);
48186 if (this.dragZone) {
48187 this.dragZone.addToGroup(ddGroup);
48189 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48190 containerScroll: true,
48194 // Draggability implies selection. DragZone's mousedown selects the element.
48195 if (!this.multiSelect) { this.singleSelect = true; }
48197 // Wire the DragZone's handlers up to methods in *this*
48198 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48202 /** Specify from which ddGroup this DDView accepts drops. */
48203 setDroppable: function(ddGroup) {
48204 if (ddGroup instanceof Array) {
48205 Roo.each(ddGroup, this.setDroppable, this);
48208 if (this.dropZone) {
48209 this.dropZone.addToGroup(ddGroup);
48211 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48212 containerScroll: true,
48216 // Wire the DropZone's handlers up to methods in *this*
48217 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48218 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48219 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48220 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48221 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48225 /** Decide whether to drop above or below a View node. */
48226 getDropPoint : function(e, n, dd){
48227 if (n == this.el.dom) { return "above"; }
48228 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48229 var c = t + (b - t) / 2;
48230 var y = Roo.lib.Event.getPageY(e);
48238 onNodeEnter : function(n, dd, e, data){
48242 onNodeOver : function(n, dd, e, data){
48243 var pt = this.getDropPoint(e, n, dd);
48244 // set the insert point style on the target node
48245 var dragElClass = this.dropNotAllowed;
48248 if (pt == "above"){
48249 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48250 targetElClass = "x-view-drag-insert-above";
48252 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48253 targetElClass = "x-view-drag-insert-below";
48255 if (this.lastInsertClass != targetElClass){
48256 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48257 this.lastInsertClass = targetElClass;
48260 return dragElClass;
48263 onNodeOut : function(n, dd, e, data){
48264 this.removeDropIndicators(n);
48267 onNodeDrop : function(n, dd, e, data){
48268 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48271 var pt = this.getDropPoint(e, n, dd);
48272 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48273 if (pt == "below") { insertAt++; }
48274 for (var i = 0; i < data.records.length; i++) {
48275 var r = data.records[i];
48276 var dup = this.store.getById(r.id);
48277 if (dup && (dd != this.dragZone)) {
48278 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48281 this.store.insert(insertAt++, r.copy());
48283 data.source.isDirtyFlag = true;
48285 this.store.insert(insertAt++, r);
48287 this.isDirtyFlag = true;
48290 this.dragZone.cachedTarget = null;
48294 removeDropIndicators : function(n){
48296 Roo.fly(n).removeClass([
48297 "x-view-drag-insert-above",
48298 "x-view-drag-insert-below"]);
48299 this.lastInsertClass = "_noclass";
48304 * Utility method. Add a delete option to the DDView's context menu.
48305 * @param {String} imageUrl The URL of the "delete" icon image.
48307 setDeletable: function(imageUrl) {
48308 if (!this.singleSelect && !this.multiSelect) {
48309 this.singleSelect = true;
48311 var c = this.getContextMenu();
48312 this.contextMenu.on("itemclick", function(item) {
48315 this.remove(this.getSelectedIndexes());
48319 this.contextMenu.add({
48326 /** Return the context menu for this DDView. */
48327 getContextMenu: function() {
48328 if (!this.contextMenu) {
48329 // Create the View's context menu
48330 this.contextMenu = new Roo.menu.Menu({
48331 id: this.id + "-contextmenu"
48333 this.el.on("contextmenu", this.showContextMenu, this);
48335 return this.contextMenu;
48338 disableContextMenu: function() {
48339 if (this.contextMenu) {
48340 this.el.un("contextmenu", this.showContextMenu, this);
48344 showContextMenu: function(e, item) {
48345 item = this.findItemFromChild(e.getTarget());
48348 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48349 this.contextMenu.showAt(e.getXY());
48354 * Remove {@link Roo.data.Record}s at the specified indices.
48355 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48357 remove: function(selectedIndices) {
48358 selectedIndices = [].concat(selectedIndices);
48359 for (var i = 0; i < selectedIndices.length; i++) {
48360 var rec = this.store.getAt(selectedIndices[i]);
48361 this.store.remove(rec);
48366 * Double click fires the event, but also, if this is draggable, and there is only one other
48367 * related DropZone, it transfers the selected node.
48369 onDblClick : function(e){
48370 var item = this.findItemFromChild(e.getTarget());
48372 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48375 if (this.dragGroup) {
48376 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48377 while (targets.indexOf(this.dropZone) > -1) {
48378 targets.remove(this.dropZone);
48380 if (targets.length == 1) {
48381 this.dragZone.cachedTarget = null;
48382 var el = Roo.get(targets[0].getEl());
48383 var box = el.getBox(true);
48384 targets[0].onNodeDrop(el.dom, {
48386 xy: [box.x, box.y + box.height - 1]
48387 }, null, this.getDragData(e));
48393 handleSelection: function(e) {
48394 this.dragZone.cachedTarget = null;
48395 var item = this.findItemFromChild(e.getTarget());
48397 this.clearSelections(true);
48400 if (item && (this.multiSelect || this.singleSelect)){
48401 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48402 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48403 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48404 this.unselect(item);
48406 this.select(item, this.multiSelect && e.ctrlKey);
48407 this.lastSelection = item;
48412 onItemClick : function(item, index, e){
48413 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48419 unselect : function(nodeInfo, suppressEvent){
48420 var node = this.getNode(nodeInfo);
48421 if(node && this.isSelected(node)){
48422 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48423 Roo.fly(node).removeClass(this.selectedClass);
48424 this.selections.remove(node);
48425 if(!suppressEvent){
48426 this.fireEvent("selectionchange", this, this.selections);
48434 * Ext JS Library 1.1.1
48435 * Copyright(c) 2006-2007, Ext JS, LLC.
48437 * Originally Released Under LGPL - original licence link has changed is not relivant.
48440 * <script type="text/javascript">
48444 * @class Roo.LayoutManager
48445 * @extends Roo.util.Observable
48446 * Base class for layout managers.
48448 Roo.LayoutManager = function(container, config){
48449 Roo.LayoutManager.superclass.constructor.call(this);
48450 this.el = Roo.get(container);
48451 // ie scrollbar fix
48452 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48453 document.body.scroll = "no";
48454 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48455 this.el.position('relative');
48457 this.id = this.el.id;
48458 this.el.addClass("x-layout-container");
48459 /** false to disable window resize monitoring @type Boolean */
48460 this.monitorWindowResize = true;
48465 * Fires when a layout is performed.
48466 * @param {Roo.LayoutManager} this
48470 * @event regionresized
48471 * Fires when the user resizes a region.
48472 * @param {Roo.LayoutRegion} region The resized region
48473 * @param {Number} newSize The new size (width for east/west, height for north/south)
48475 "regionresized" : true,
48477 * @event regioncollapsed
48478 * Fires when a region is collapsed.
48479 * @param {Roo.LayoutRegion} region The collapsed region
48481 "regioncollapsed" : true,
48483 * @event regionexpanded
48484 * Fires when a region is expanded.
48485 * @param {Roo.LayoutRegion} region The expanded region
48487 "regionexpanded" : true
48489 this.updating = false;
48490 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48493 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48495 * Returns true if this layout is currently being updated
48496 * @return {Boolean}
48498 isUpdating : function(){
48499 return this.updating;
48503 * Suspend the LayoutManager from doing auto-layouts while
48504 * making multiple add or remove calls
48506 beginUpdate : function(){
48507 this.updating = true;
48511 * Restore auto-layouts and optionally disable the manager from performing a layout
48512 * @param {Boolean} noLayout true to disable a layout update
48514 endUpdate : function(noLayout){
48515 this.updating = false;
48521 layout: function(){
48525 onRegionResized : function(region, newSize){
48526 this.fireEvent("regionresized", region, newSize);
48530 onRegionCollapsed : function(region){
48531 this.fireEvent("regioncollapsed", region);
48534 onRegionExpanded : function(region){
48535 this.fireEvent("regionexpanded", region);
48539 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48540 * performs box-model adjustments.
48541 * @return {Object} The size as an object {width: (the width), height: (the height)}
48543 getViewSize : function(){
48545 if(this.el.dom != document.body){
48546 size = this.el.getSize();
48548 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48550 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48551 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48556 * Returns the Element this layout is bound to.
48557 * @return {Roo.Element}
48559 getEl : function(){
48564 * Returns the specified region.
48565 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48566 * @return {Roo.LayoutRegion}
48568 getRegion : function(target){
48569 return this.regions[target.toLowerCase()];
48572 onWindowResize : function(){
48573 if(this.monitorWindowResize){
48579 * Ext JS Library 1.1.1
48580 * Copyright(c) 2006-2007, Ext JS, LLC.
48582 * Originally Released Under LGPL - original licence link has changed is not relivant.
48585 * <script type="text/javascript">
48588 * @class Roo.BorderLayout
48589 * @extends Roo.LayoutManager
48590 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48591 * please see: <br><br>
48592 * <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>
48593 * <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>
48596 var layout = new Roo.BorderLayout(document.body, {
48630 preferredTabWidth: 150
48635 var CP = Roo.ContentPanel;
48637 layout.beginUpdate();
48638 layout.add("north", new CP("north", "North"));
48639 layout.add("south", new CP("south", {title: "South", closable: true}));
48640 layout.add("west", new CP("west", {title: "West"}));
48641 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48642 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48643 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48644 layout.getRegion("center").showPanel("center1");
48645 layout.endUpdate();
48648 <b>The container the layout is rendered into can be either the body element or any other element.
48649 If it is not the body element, the container needs to either be an absolute positioned element,
48650 or you will need to add "position:relative" to the css of the container. You will also need to specify
48651 the container size if it is not the body element.</b>
48654 * Create a new BorderLayout
48655 * @param {String/HTMLElement/Element} container The container this layout is bound to
48656 * @param {Object} config Configuration options
48658 Roo.BorderLayout = function(container, config){
48659 config = config || {};
48660 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48661 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48662 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48663 var target = this.factory.validRegions[i];
48664 if(config[target]){
48665 this.addRegion(target, config[target]);
48670 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48672 * Creates and adds a new region if it doesn't already exist.
48673 * @param {String} target The target region key (north, south, east, west or center).
48674 * @param {Object} config The regions config object
48675 * @return {BorderLayoutRegion} The new region
48677 addRegion : function(target, config){
48678 if(!this.regions[target]){
48679 var r = this.factory.create(target, this, config);
48680 this.bindRegion(target, r);
48682 return this.regions[target];
48686 bindRegion : function(name, r){
48687 this.regions[name] = r;
48688 r.on("visibilitychange", this.layout, this);
48689 r.on("paneladded", this.layout, this);
48690 r.on("panelremoved", this.layout, this);
48691 r.on("invalidated", this.layout, this);
48692 r.on("resized", this.onRegionResized, this);
48693 r.on("collapsed", this.onRegionCollapsed, this);
48694 r.on("expanded", this.onRegionExpanded, this);
48698 * Performs a layout update.
48700 layout : function(){
48701 if(this.updating) return;
48702 var size = this.getViewSize();
48703 var w = size.width;
48704 var h = size.height;
48709 //var x = 0, y = 0;
48711 var rs = this.regions;
48712 var north = rs["north"];
48713 var south = rs["south"];
48714 var west = rs["west"];
48715 var east = rs["east"];
48716 var center = rs["center"];
48717 //if(this.hideOnLayout){ // not supported anymore
48718 //c.el.setStyle("display", "none");
48720 if(north && north.isVisible()){
48721 var b = north.getBox();
48722 var m = north.getMargins();
48723 b.width = w - (m.left+m.right);
48726 centerY = b.height + b.y + m.bottom;
48727 centerH -= centerY;
48728 north.updateBox(this.safeBox(b));
48730 if(south && south.isVisible()){
48731 var b = south.getBox();
48732 var m = south.getMargins();
48733 b.width = w - (m.left+m.right);
48735 var totalHeight = (b.height + m.top + m.bottom);
48736 b.y = h - totalHeight + m.top;
48737 centerH -= totalHeight;
48738 south.updateBox(this.safeBox(b));
48740 if(west && west.isVisible()){
48741 var b = west.getBox();
48742 var m = west.getMargins();
48743 b.height = centerH - (m.top+m.bottom);
48745 b.y = centerY + m.top;
48746 var totalWidth = (b.width + m.left + m.right);
48747 centerX += totalWidth;
48748 centerW -= totalWidth;
48749 west.updateBox(this.safeBox(b));
48751 if(east && east.isVisible()){
48752 var b = east.getBox();
48753 var m = east.getMargins();
48754 b.height = centerH - (m.top+m.bottom);
48755 var totalWidth = (b.width + m.left + m.right);
48756 b.x = w - totalWidth + m.left;
48757 b.y = centerY + m.top;
48758 centerW -= totalWidth;
48759 east.updateBox(this.safeBox(b));
48762 var m = center.getMargins();
48764 x: centerX + m.left,
48765 y: centerY + m.top,
48766 width: centerW - (m.left+m.right),
48767 height: centerH - (m.top+m.bottom)
48769 //if(this.hideOnLayout){
48770 //center.el.setStyle("display", "block");
48772 center.updateBox(this.safeBox(centerBox));
48775 this.fireEvent("layout", this);
48779 safeBox : function(box){
48780 box.width = Math.max(0, box.width);
48781 box.height = Math.max(0, box.height);
48786 * Adds a ContentPanel (or subclass) to this layout.
48787 * @param {String} target The target region key (north, south, east, west or center).
48788 * @param {Roo.ContentPanel} panel The panel to add
48789 * @return {Roo.ContentPanel} The added panel
48791 add : function(target, panel){
48793 target = target.toLowerCase();
48794 return this.regions[target].add(panel);
48798 * Remove a ContentPanel (or subclass) to this layout.
48799 * @param {String} target The target region key (north, south, east, west or center).
48800 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48801 * @return {Roo.ContentPanel} The removed panel
48803 remove : function(target, panel){
48804 target = target.toLowerCase();
48805 return this.regions[target].remove(panel);
48809 * Searches all regions for a panel with the specified id
48810 * @param {String} panelId
48811 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48813 findPanel : function(panelId){
48814 var rs = this.regions;
48815 for(var target in rs){
48816 if(typeof rs[target] != "function"){
48817 var p = rs[target].getPanel(panelId);
48827 * Searches all regions for a panel with the specified id and activates (shows) it.
48828 * @param {String/ContentPanel} panelId The panels id or the panel itself
48829 * @return {Roo.ContentPanel} The shown panel or null
48831 showPanel : function(panelId) {
48832 var rs = this.regions;
48833 for(var target in rs){
48834 var r = rs[target];
48835 if(typeof r != "function"){
48836 if(r.hasPanel(panelId)){
48837 return r.showPanel(panelId);
48845 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48846 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48848 restoreState : function(provider){
48850 provider = Roo.state.Manager;
48852 var sm = new Roo.LayoutStateManager();
48853 sm.init(this, provider);
48857 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48858 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48859 * a valid ContentPanel config object. Example:
48861 // Create the main layout
48862 var layout = new Roo.BorderLayout('main-ct', {
48873 // Create and add multiple ContentPanels at once via configs
48876 id: 'source-files',
48878 title:'Ext Source Files',
48891 * @param {Object} regions An object containing ContentPanel configs by region name
48893 batchAdd : function(regions){
48894 this.beginUpdate();
48895 for(var rname in regions){
48896 var lr = this.regions[rname];
48898 this.addTypedPanels(lr, regions[rname]);
48905 addTypedPanels : function(lr, ps){
48906 if(typeof ps == 'string'){
48907 lr.add(new Roo.ContentPanel(ps));
48909 else if(ps instanceof Array){
48910 for(var i =0, len = ps.length; i < len; i++){
48911 this.addTypedPanels(lr, ps[i]);
48914 else if(!ps.events){ // raw config?
48916 delete ps.el; // prevent conflict
48917 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48919 else { // panel object assumed!
48924 * Adds a xtype elements to the layout.
48928 xtype : 'ContentPanel',
48935 xtype : 'NestedLayoutPanel',
48941 items : [ ... list of content panels or nested layout panels.. ]
48945 * @param {Object} cfg Xtype definition of item to add.
48947 addxtype : function(cfg)
48949 // basically accepts a pannel...
48950 // can accept a layout region..!?!?
48951 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
48953 if (!cfg.xtype.match(/Panel$/)) {
48958 if (typeof(cfg.region) == 'undefined') {
48959 Roo.log("Failed to add Panel, region was not set");
48963 var region = cfg.region;
48969 xitems = cfg.items;
48976 case 'ContentPanel': // ContentPanel (el, cfg)
48977 case 'ScrollPanel': // ContentPanel (el, cfg)
48979 if(cfg.autoCreate) {
48980 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48982 var el = this.el.createChild();
48983 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
48986 this.add(region, ret);
48990 case 'TreePanel': // our new panel!
48991 cfg.el = this.el.createChild();
48992 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48993 this.add(region, ret);
48996 case 'NestedLayoutPanel':
48997 // create a new Layout (which is a Border Layout...
48998 var el = this.el.createChild();
48999 var clayout = cfg.layout;
49001 clayout.items = clayout.items || [];
49002 // replace this exitems with the clayout ones..
49003 xitems = clayout.items;
49006 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49007 cfg.background = false;
49009 var layout = new Roo.BorderLayout(el, clayout);
49011 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49012 //console.log('adding nested layout panel ' + cfg.toSource());
49013 this.add(region, ret);
49014 nb = {}; /// find first...
49019 // needs grid and region
49021 //var el = this.getRegion(region).el.createChild();
49022 var el = this.el.createChild();
49023 // create the grid first...
49025 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49027 if (region == 'center' && this.active ) {
49028 cfg.background = false;
49030 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49032 this.add(region, ret);
49033 if (cfg.background) {
49034 ret.on('activate', function(gp) {
49035 if (!gp.grid.rendered) {
49050 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49052 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49053 this.add(region, ret);
49056 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49060 // GridPanel (grid, cfg)
49063 this.beginUpdate();
49067 Roo.each(xitems, function(i) {
49068 region = nb && i.region ? i.region : false;
49070 var add = ret.addxtype(i);
49073 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49074 if (!i.background) {
49075 abn[region] = nb[region] ;
49082 // make the last non-background panel active..
49083 //if (nb) { Roo.log(abn); }
49086 for(var r in abn) {
49087 region = this.getRegion(r);
49089 // tried using nb[r], but it does not work..
49091 region.showPanel(abn[r]);
49102 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49103 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49104 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49105 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49108 var CP = Roo.ContentPanel;
49110 var layout = Roo.BorderLayout.create({
49114 panels: [new CP("north", "North")]
49123 panels: [new CP("west", {title: "West"})]
49132 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49141 panels: [new CP("south", {title: "South", closable: true})]
49148 preferredTabWidth: 150,
49150 new CP("center1", {title: "Close Me", closable: true}),
49151 new CP("center2", {title: "Center Panel", closable: false})
49156 layout.getRegion("center").showPanel("center1");
49161 Roo.BorderLayout.create = function(config, targetEl){
49162 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49163 layout.beginUpdate();
49164 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49165 for(var j = 0, jlen = regions.length; j < jlen; j++){
49166 var lr = regions[j];
49167 if(layout.regions[lr] && config[lr].panels){
49168 var r = layout.regions[lr];
49169 var ps = config[lr].panels;
49170 layout.addTypedPanels(r, ps);
49173 layout.endUpdate();
49178 Roo.BorderLayout.RegionFactory = {
49180 validRegions : ["north","south","east","west","center"],
49183 create : function(target, mgr, config){
49184 target = target.toLowerCase();
49185 if(config.lightweight || config.basic){
49186 return new Roo.BasicLayoutRegion(mgr, config, target);
49190 return new Roo.NorthLayoutRegion(mgr, config);
49192 return new Roo.SouthLayoutRegion(mgr, config);
49194 return new Roo.EastLayoutRegion(mgr, config);
49196 return new Roo.WestLayoutRegion(mgr, config);
49198 return new Roo.CenterLayoutRegion(mgr, config);
49200 throw 'Layout region "'+target+'" not supported.';
49204 * Ext JS Library 1.1.1
49205 * Copyright(c) 2006-2007, Ext JS, LLC.
49207 * Originally Released Under LGPL - original licence link has changed is not relivant.
49210 * <script type="text/javascript">
49214 * @class Roo.BasicLayoutRegion
49215 * @extends Roo.util.Observable
49216 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49217 * and does not have a titlebar, tabs or any other features. All it does is size and position
49218 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49220 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49222 this.position = pos;
49225 * @scope Roo.BasicLayoutRegion
49229 * @event beforeremove
49230 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49231 * @param {Roo.LayoutRegion} this
49232 * @param {Roo.ContentPanel} panel The panel
49233 * @param {Object} e The cancel event object
49235 "beforeremove" : true,
49237 * @event invalidated
49238 * Fires when the layout for this region is changed.
49239 * @param {Roo.LayoutRegion} this
49241 "invalidated" : true,
49243 * @event visibilitychange
49244 * Fires when this region is shown or hidden
49245 * @param {Roo.LayoutRegion} this
49246 * @param {Boolean} visibility true or false
49248 "visibilitychange" : true,
49250 * @event paneladded
49251 * Fires when a panel is added.
49252 * @param {Roo.LayoutRegion} this
49253 * @param {Roo.ContentPanel} panel The panel
49255 "paneladded" : true,
49257 * @event panelremoved
49258 * Fires when a panel is removed.
49259 * @param {Roo.LayoutRegion} this
49260 * @param {Roo.ContentPanel} panel The panel
49262 "panelremoved" : true,
49265 * Fires when this region is collapsed.
49266 * @param {Roo.LayoutRegion} this
49268 "collapsed" : true,
49271 * Fires when this region is expanded.
49272 * @param {Roo.LayoutRegion} this
49277 * Fires when this region is slid into view.
49278 * @param {Roo.LayoutRegion} this
49280 "slideshow" : true,
49283 * Fires when this region slides out of view.
49284 * @param {Roo.LayoutRegion} this
49286 "slidehide" : true,
49288 * @event panelactivated
49289 * Fires when a panel is activated.
49290 * @param {Roo.LayoutRegion} this
49291 * @param {Roo.ContentPanel} panel The activated panel
49293 "panelactivated" : true,
49296 * Fires when the user resizes this region.
49297 * @param {Roo.LayoutRegion} this
49298 * @param {Number} newSize The new size (width for east/west, height for north/south)
49302 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49303 this.panels = new Roo.util.MixedCollection();
49304 this.panels.getKey = this.getPanelId.createDelegate(this);
49306 this.activePanel = null;
49307 // ensure listeners are added...
49309 if (config.listeners || config.events) {
49310 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49311 listeners : config.listeners || {},
49312 events : config.events || {}
49316 if(skipConfig !== true){
49317 this.applyConfig(config);
49321 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49322 getPanelId : function(p){
49326 applyConfig : function(config){
49327 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49328 this.config = config;
49333 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49334 * the width, for horizontal (north, south) the height.
49335 * @param {Number} newSize The new width or height
49337 resizeTo : function(newSize){
49338 var el = this.el ? this.el :
49339 (this.activePanel ? this.activePanel.getEl() : null);
49341 switch(this.position){
49344 el.setWidth(newSize);
49345 this.fireEvent("resized", this, newSize);
49349 el.setHeight(newSize);
49350 this.fireEvent("resized", this, newSize);
49356 getBox : function(){
49357 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49360 getMargins : function(){
49361 return this.margins;
49364 updateBox : function(box){
49366 var el = this.activePanel.getEl();
49367 el.dom.style.left = box.x + "px";
49368 el.dom.style.top = box.y + "px";
49369 this.activePanel.setSize(box.width, box.height);
49373 * Returns the container element for this region.
49374 * @return {Roo.Element}
49376 getEl : function(){
49377 return this.activePanel;
49381 * Returns true if this region is currently visible.
49382 * @return {Boolean}
49384 isVisible : function(){
49385 return this.activePanel ? true : false;
49388 setActivePanel : function(panel){
49389 panel = this.getPanel(panel);
49390 if(this.activePanel && this.activePanel != panel){
49391 this.activePanel.setActiveState(false);
49392 this.activePanel.getEl().setLeftTop(-10000,-10000);
49394 this.activePanel = panel;
49395 panel.setActiveState(true);
49397 panel.setSize(this.box.width, this.box.height);
49399 this.fireEvent("panelactivated", this, panel);
49400 this.fireEvent("invalidated");
49404 * Show the specified panel.
49405 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49406 * @return {Roo.ContentPanel} The shown panel or null
49408 showPanel : function(panel){
49409 if(panel = this.getPanel(panel)){
49410 this.setActivePanel(panel);
49416 * Get the active panel for this region.
49417 * @return {Roo.ContentPanel} The active panel or null
49419 getActivePanel : function(){
49420 return this.activePanel;
49424 * Add the passed ContentPanel(s)
49425 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49426 * @return {Roo.ContentPanel} The panel added (if only one was added)
49428 add : function(panel){
49429 if(arguments.length > 1){
49430 for(var i = 0, len = arguments.length; i < len; i++) {
49431 this.add(arguments[i]);
49435 if(this.hasPanel(panel)){
49436 this.showPanel(panel);
49439 var el = panel.getEl();
49440 if(el.dom.parentNode != this.mgr.el.dom){
49441 this.mgr.el.dom.appendChild(el.dom);
49443 if(panel.setRegion){
49444 panel.setRegion(this);
49446 this.panels.add(panel);
49447 el.setStyle("position", "absolute");
49448 if(!panel.background){
49449 this.setActivePanel(panel);
49450 if(this.config.initialSize && this.panels.getCount()==1){
49451 this.resizeTo(this.config.initialSize);
49454 this.fireEvent("paneladded", this, panel);
49459 * Returns true if the panel is in this region.
49460 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49461 * @return {Boolean}
49463 hasPanel : function(panel){
49464 if(typeof panel == "object"){ // must be panel obj
49465 panel = panel.getId();
49467 return this.getPanel(panel) ? true : false;
49471 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49472 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49473 * @param {Boolean} preservePanel Overrides the config preservePanel option
49474 * @return {Roo.ContentPanel} The panel that was removed
49476 remove : function(panel, preservePanel){
49477 panel = this.getPanel(panel);
49482 this.fireEvent("beforeremove", this, panel, e);
49483 if(e.cancel === true){
49486 var panelId = panel.getId();
49487 this.panels.removeKey(panelId);
49492 * Returns the panel specified or null if it's not in this region.
49493 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49494 * @return {Roo.ContentPanel}
49496 getPanel : function(id){
49497 if(typeof id == "object"){ // must be panel obj
49500 return this.panels.get(id);
49504 * Returns this regions position (north/south/east/west/center).
49507 getPosition: function(){
49508 return this.position;
49512 * Ext JS Library 1.1.1
49513 * Copyright(c) 2006-2007, Ext JS, LLC.
49515 * Originally Released Under LGPL - original licence link has changed is not relivant.
49518 * <script type="text/javascript">
49522 * @class Roo.LayoutRegion
49523 * @extends Roo.BasicLayoutRegion
49524 * This class represents a region in a layout manager.
49525 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49526 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49527 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49528 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49529 * @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})
49530 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49531 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49532 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49533 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49534 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49535 * @cfg {String} title The title for the region (overrides panel titles)
49536 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49537 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49538 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49539 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49540 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49541 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49542 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49543 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49544 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49545 * @cfg {Boolean} showPin True to show a pin button
49546 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49547 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49548 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49549 * @cfg {Number} width For East/West panels
49550 * @cfg {Number} height For North/South panels
49551 * @cfg {Boolean} split To show the splitter
49552 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49554 Roo.LayoutRegion = function(mgr, config, pos){
49555 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49556 var dh = Roo.DomHelper;
49557 /** This region's container element
49558 * @type Roo.Element */
49559 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49560 /** This region's title element
49561 * @type Roo.Element */
49563 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49564 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49565 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49567 this.titleEl.enableDisplayMode();
49568 /** This region's title text element
49569 * @type HTMLElement */
49570 this.titleTextEl = this.titleEl.dom.firstChild;
49571 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49572 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49573 this.closeBtn.enableDisplayMode();
49574 this.closeBtn.on("click", this.closeClicked, this);
49575 this.closeBtn.hide();
49577 this.createBody(config);
49578 this.visible = true;
49579 this.collapsed = false;
49581 if(config.hideWhenEmpty){
49583 this.on("paneladded", this.validateVisibility, this);
49584 this.on("panelremoved", this.validateVisibility, this);
49586 this.applyConfig(config);
49589 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49591 createBody : function(){
49592 /** This region's body element
49593 * @type Roo.Element */
49594 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49597 applyConfig : function(c){
49598 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49599 var dh = Roo.DomHelper;
49600 if(c.titlebar !== false){
49601 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49602 this.collapseBtn.on("click", this.collapse, this);
49603 this.collapseBtn.enableDisplayMode();
49605 if(c.showPin === true || this.showPin){
49606 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49607 this.stickBtn.enableDisplayMode();
49608 this.stickBtn.on("click", this.expand, this);
49609 this.stickBtn.hide();
49612 /** This region's collapsed element
49613 * @type Roo.Element */
49614 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49615 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49617 if(c.floatable !== false){
49618 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49619 this.collapsedEl.on("click", this.collapseClick, this);
49622 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49623 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49624 id: "message", unselectable: "on", style:{"float":"left"}});
49625 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49627 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49628 this.expandBtn.on("click", this.expand, this);
49630 if(this.collapseBtn){
49631 this.collapseBtn.setVisible(c.collapsible == true);
49633 this.cmargins = c.cmargins || this.cmargins ||
49634 (this.position == "west" || this.position == "east" ?
49635 {top: 0, left: 2, right:2, bottom: 0} :
49636 {top: 2, left: 0, right:0, bottom: 2});
49637 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49638 this.bottomTabs = c.tabPosition != "top";
49639 this.autoScroll = c.autoScroll || false;
49640 if(this.autoScroll){
49641 this.bodyEl.setStyle("overflow", "auto");
49643 this.bodyEl.setStyle("overflow", "hidden");
49645 //if(c.titlebar !== false){
49646 if((!c.titlebar && !c.title) || c.titlebar === false){
49647 this.titleEl.hide();
49649 this.titleEl.show();
49651 this.titleTextEl.innerHTML = c.title;
49655 this.duration = c.duration || .30;
49656 this.slideDuration = c.slideDuration || .45;
49659 this.collapse(true);
49666 * Returns true if this region is currently visible.
49667 * @return {Boolean}
49669 isVisible : function(){
49670 return this.visible;
49674 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49675 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49677 setCollapsedTitle : function(title){
49678 title = title || " ";
49679 if(this.collapsedTitleTextEl){
49680 this.collapsedTitleTextEl.innerHTML = title;
49684 getBox : function(){
49686 if(!this.collapsed){
49687 b = this.el.getBox(false, true);
49689 b = this.collapsedEl.getBox(false, true);
49694 getMargins : function(){
49695 return this.collapsed ? this.cmargins : this.margins;
49698 highlight : function(){
49699 this.el.addClass("x-layout-panel-dragover");
49702 unhighlight : function(){
49703 this.el.removeClass("x-layout-panel-dragover");
49706 updateBox : function(box){
49708 if(!this.collapsed){
49709 this.el.dom.style.left = box.x + "px";
49710 this.el.dom.style.top = box.y + "px";
49711 this.updateBody(box.width, box.height);
49713 this.collapsedEl.dom.style.left = box.x + "px";
49714 this.collapsedEl.dom.style.top = box.y + "px";
49715 this.collapsedEl.setSize(box.width, box.height);
49718 this.tabs.autoSizeTabs();
49722 updateBody : function(w, h){
49724 this.el.setWidth(w);
49725 w -= this.el.getBorderWidth("rl");
49726 if(this.config.adjustments){
49727 w += this.config.adjustments[0];
49731 this.el.setHeight(h);
49732 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49733 h -= this.el.getBorderWidth("tb");
49734 if(this.config.adjustments){
49735 h += this.config.adjustments[1];
49737 this.bodyEl.setHeight(h);
49739 h = this.tabs.syncHeight(h);
49742 if(this.panelSize){
49743 w = w !== null ? w : this.panelSize.width;
49744 h = h !== null ? h : this.panelSize.height;
49746 if(this.activePanel){
49747 var el = this.activePanel.getEl();
49748 w = w !== null ? w : el.getWidth();
49749 h = h !== null ? h : el.getHeight();
49750 this.panelSize = {width: w, height: h};
49751 this.activePanel.setSize(w, h);
49753 if(Roo.isIE && this.tabs){
49754 this.tabs.el.repaint();
49759 * Returns the container element for this region.
49760 * @return {Roo.Element}
49762 getEl : function(){
49767 * Hides this region.
49770 if(!this.collapsed){
49771 this.el.dom.style.left = "-2000px";
49774 this.collapsedEl.dom.style.left = "-2000px";
49775 this.collapsedEl.hide();
49777 this.visible = false;
49778 this.fireEvent("visibilitychange", this, false);
49782 * Shows this region if it was previously hidden.
49785 if(!this.collapsed){
49788 this.collapsedEl.show();
49790 this.visible = true;
49791 this.fireEvent("visibilitychange", this, true);
49794 closeClicked : function(){
49795 if(this.activePanel){
49796 this.remove(this.activePanel);
49800 collapseClick : function(e){
49802 e.stopPropagation();
49805 e.stopPropagation();
49811 * Collapses this region.
49812 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49814 collapse : function(skipAnim){
49815 if(this.collapsed) return;
49816 this.collapsed = true;
49818 this.split.el.hide();
49820 if(this.config.animate && skipAnim !== true){
49821 this.fireEvent("invalidated", this);
49822 this.animateCollapse();
49824 this.el.setLocation(-20000,-20000);
49826 this.collapsedEl.show();
49827 this.fireEvent("collapsed", this);
49828 this.fireEvent("invalidated", this);
49832 animateCollapse : function(){
49837 * Expands this region if it was previously collapsed.
49838 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49839 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49841 expand : function(e, skipAnim){
49842 if(e) e.stopPropagation();
49843 if(!this.collapsed || this.el.hasActiveFx()) return;
49845 this.afterSlideIn();
49848 this.collapsed = false;
49849 if(this.config.animate && skipAnim !== true){
49850 this.animateExpand();
49854 this.split.el.show();
49856 this.collapsedEl.setLocation(-2000,-2000);
49857 this.collapsedEl.hide();
49858 this.fireEvent("invalidated", this);
49859 this.fireEvent("expanded", this);
49863 animateExpand : function(){
49867 initTabs : function()
49869 this.bodyEl.setStyle("overflow", "hidden");
49870 var ts = new Roo.TabPanel(
49873 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49874 disableTooltips: this.config.disableTabTips,
49875 toolbar : this.config.toolbar
49878 if(this.config.hideTabs){
49879 ts.stripWrap.setDisplayed(false);
49882 ts.resizeTabs = this.config.resizeTabs === true;
49883 ts.minTabWidth = this.config.minTabWidth || 40;
49884 ts.maxTabWidth = this.config.maxTabWidth || 250;
49885 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49886 ts.monitorResize = false;
49887 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49888 ts.bodyEl.addClass('x-layout-tabs-body');
49889 this.panels.each(this.initPanelAsTab, this);
49892 initPanelAsTab : function(panel){
49893 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49894 this.config.closeOnTab && panel.isClosable());
49895 if(panel.tabTip !== undefined){
49896 ti.setTooltip(panel.tabTip);
49898 ti.on("activate", function(){
49899 this.setActivePanel(panel);
49901 if(this.config.closeOnTab){
49902 ti.on("beforeclose", function(t, e){
49904 this.remove(panel);
49910 updatePanelTitle : function(panel, title){
49911 if(this.activePanel == panel){
49912 this.updateTitle(title);
49915 var ti = this.tabs.getTab(panel.getEl().id);
49917 if(panel.tabTip !== undefined){
49918 ti.setTooltip(panel.tabTip);
49923 updateTitle : function(title){
49924 if(this.titleTextEl && !this.config.title){
49925 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
49929 setActivePanel : function(panel){
49930 panel = this.getPanel(panel);
49931 if(this.activePanel && this.activePanel != panel){
49932 this.activePanel.setActiveState(false);
49934 this.activePanel = panel;
49935 panel.setActiveState(true);
49936 if(this.panelSize){
49937 panel.setSize(this.panelSize.width, this.panelSize.height);
49940 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
49942 this.updateTitle(panel.getTitle());
49944 this.fireEvent("invalidated", this);
49946 this.fireEvent("panelactivated", this, panel);
49950 * Shows the specified panel.
49951 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
49952 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
49954 showPanel : function(panel){
49955 if(panel = this.getPanel(panel)){
49957 var tab = this.tabs.getTab(panel.getEl().id);
49958 if(tab.isHidden()){
49959 this.tabs.unhideTab(tab.id);
49963 this.setActivePanel(panel);
49970 * Get the active panel for this region.
49971 * @return {Roo.ContentPanel} The active panel or null
49973 getActivePanel : function(){
49974 return this.activePanel;
49977 validateVisibility : function(){
49978 if(this.panels.getCount() < 1){
49979 this.updateTitle(" ");
49980 this.closeBtn.hide();
49983 if(!this.isVisible()){
49990 * Adds the passed ContentPanel(s) to this region.
49991 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49992 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
49994 add : function(panel){
49995 if(arguments.length > 1){
49996 for(var i = 0, len = arguments.length; i < len; i++) {
49997 this.add(arguments[i]);
50001 if(this.hasPanel(panel)){
50002 this.showPanel(panel);
50005 panel.setRegion(this);
50006 this.panels.add(panel);
50007 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50008 this.bodyEl.dom.appendChild(panel.getEl().dom);
50009 if(panel.background !== true){
50010 this.setActivePanel(panel);
50012 this.fireEvent("paneladded", this, panel);
50018 this.initPanelAsTab(panel);
50020 if(panel.background !== true){
50021 this.tabs.activate(panel.getEl().id);
50023 this.fireEvent("paneladded", this, panel);
50028 * Hides the tab for the specified panel.
50029 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50031 hidePanel : function(panel){
50032 if(this.tabs && (panel = this.getPanel(panel))){
50033 this.tabs.hideTab(panel.getEl().id);
50038 * Unhides the tab for a previously hidden panel.
50039 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50041 unhidePanel : function(panel){
50042 if(this.tabs && (panel = this.getPanel(panel))){
50043 this.tabs.unhideTab(panel.getEl().id);
50047 clearPanels : function(){
50048 while(this.panels.getCount() > 0){
50049 this.remove(this.panels.first());
50054 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50055 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50056 * @param {Boolean} preservePanel Overrides the config preservePanel option
50057 * @return {Roo.ContentPanel} The panel that was removed
50059 remove : function(panel, preservePanel){
50060 panel = this.getPanel(panel);
50065 this.fireEvent("beforeremove", this, panel, e);
50066 if(e.cancel === true){
50069 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50070 var panelId = panel.getId();
50071 this.panels.removeKey(panelId);
50073 document.body.appendChild(panel.getEl().dom);
50076 this.tabs.removeTab(panel.getEl().id);
50077 }else if (!preservePanel){
50078 this.bodyEl.dom.removeChild(panel.getEl().dom);
50080 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50081 var p = this.panels.first();
50082 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50083 tempEl.appendChild(p.getEl().dom);
50084 this.bodyEl.update("");
50085 this.bodyEl.dom.appendChild(p.getEl().dom);
50087 this.updateTitle(p.getTitle());
50089 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50090 this.setActivePanel(p);
50092 panel.setRegion(null);
50093 if(this.activePanel == panel){
50094 this.activePanel = null;
50096 if(this.config.autoDestroy !== false && preservePanel !== true){
50097 try{panel.destroy();}catch(e){}
50099 this.fireEvent("panelremoved", this, panel);
50104 * Returns the TabPanel component used by this region
50105 * @return {Roo.TabPanel}
50107 getTabs : function(){
50111 createTool : function(parentEl, className){
50112 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50113 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50114 btn.addClassOnOver("x-layout-tools-button-over");
50119 * Ext JS Library 1.1.1
50120 * Copyright(c) 2006-2007, Ext JS, LLC.
50122 * Originally Released Under LGPL - original licence link has changed is not relivant.
50125 * <script type="text/javascript">
50131 * @class Roo.SplitLayoutRegion
50132 * @extends Roo.LayoutRegion
50133 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50135 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50136 this.cursor = cursor;
50137 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50140 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50141 splitTip : "Drag to resize.",
50142 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50143 useSplitTips : false,
50145 applyConfig : function(config){
50146 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50149 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50150 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50151 /** The SplitBar for this region
50152 * @type Roo.SplitBar */
50153 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50154 this.split.on("moved", this.onSplitMove, this);
50155 this.split.useShim = config.useShim === true;
50156 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50157 if(this.useSplitTips){
50158 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50160 if(config.collapsible){
50161 this.split.el.on("dblclick", this.collapse, this);
50164 if(typeof config.minSize != "undefined"){
50165 this.split.minSize = config.minSize;
50167 if(typeof config.maxSize != "undefined"){
50168 this.split.maxSize = config.maxSize;
50170 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50171 this.hideSplitter();
50176 getHMaxSize : function(){
50177 var cmax = this.config.maxSize || 10000;
50178 var center = this.mgr.getRegion("center");
50179 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50182 getVMaxSize : function(){
50183 var cmax = this.config.maxSize || 10000;
50184 var center = this.mgr.getRegion("center");
50185 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50188 onSplitMove : function(split, newSize){
50189 this.fireEvent("resized", this, newSize);
50193 * Returns the {@link Roo.SplitBar} for this region.
50194 * @return {Roo.SplitBar}
50196 getSplitBar : function(){
50201 this.hideSplitter();
50202 Roo.SplitLayoutRegion.superclass.hide.call(this);
50205 hideSplitter : function(){
50207 this.split.el.setLocation(-2000,-2000);
50208 this.split.el.hide();
50214 this.split.el.show();
50216 Roo.SplitLayoutRegion.superclass.show.call(this);
50219 beforeSlide: function(){
50220 if(Roo.isGecko){// firefox overflow auto bug workaround
50221 this.bodyEl.clip();
50222 if(this.tabs) this.tabs.bodyEl.clip();
50223 if(this.activePanel){
50224 this.activePanel.getEl().clip();
50226 if(this.activePanel.beforeSlide){
50227 this.activePanel.beforeSlide();
50233 afterSlide : function(){
50234 if(Roo.isGecko){// firefox overflow auto bug workaround
50235 this.bodyEl.unclip();
50236 if(this.tabs) this.tabs.bodyEl.unclip();
50237 if(this.activePanel){
50238 this.activePanel.getEl().unclip();
50239 if(this.activePanel.afterSlide){
50240 this.activePanel.afterSlide();
50246 initAutoHide : function(){
50247 if(this.autoHide !== false){
50248 if(!this.autoHideHd){
50249 var st = new Roo.util.DelayedTask(this.slideIn, this);
50250 this.autoHideHd = {
50251 "mouseout": function(e){
50252 if(!e.within(this.el, true)){
50256 "mouseover" : function(e){
50262 this.el.on(this.autoHideHd);
50266 clearAutoHide : function(){
50267 if(this.autoHide !== false){
50268 this.el.un("mouseout", this.autoHideHd.mouseout);
50269 this.el.un("mouseover", this.autoHideHd.mouseover);
50273 clearMonitor : function(){
50274 Roo.get(document).un("click", this.slideInIf, this);
50277 // these names are backwards but not changed for compat
50278 slideOut : function(){
50279 if(this.isSlid || this.el.hasActiveFx()){
50282 this.isSlid = true;
50283 if(this.collapseBtn){
50284 this.collapseBtn.hide();
50286 this.closeBtnState = this.closeBtn.getStyle('display');
50287 this.closeBtn.hide();
50289 this.stickBtn.show();
50292 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50293 this.beforeSlide();
50294 this.el.setStyle("z-index", 10001);
50295 this.el.slideIn(this.getSlideAnchor(), {
50296 callback: function(){
50298 this.initAutoHide();
50299 Roo.get(document).on("click", this.slideInIf, this);
50300 this.fireEvent("slideshow", this);
50307 afterSlideIn : function(){
50308 this.clearAutoHide();
50309 this.isSlid = false;
50310 this.clearMonitor();
50311 this.el.setStyle("z-index", "");
50312 if(this.collapseBtn){
50313 this.collapseBtn.show();
50315 this.closeBtn.setStyle('display', this.closeBtnState);
50317 this.stickBtn.hide();
50319 this.fireEvent("slidehide", this);
50322 slideIn : function(cb){
50323 if(!this.isSlid || this.el.hasActiveFx()){
50327 this.isSlid = false;
50328 this.beforeSlide();
50329 this.el.slideOut(this.getSlideAnchor(), {
50330 callback: function(){
50331 this.el.setLeftTop(-10000, -10000);
50333 this.afterSlideIn();
50341 slideInIf : function(e){
50342 if(!e.within(this.el)){
50347 animateCollapse : function(){
50348 this.beforeSlide();
50349 this.el.setStyle("z-index", 20000);
50350 var anchor = this.getSlideAnchor();
50351 this.el.slideOut(anchor, {
50352 callback : function(){
50353 this.el.setStyle("z-index", "");
50354 this.collapsedEl.slideIn(anchor, {duration:.3});
50356 this.el.setLocation(-10000,-10000);
50358 this.fireEvent("collapsed", this);
50365 animateExpand : function(){
50366 this.beforeSlide();
50367 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50368 this.el.setStyle("z-index", 20000);
50369 this.collapsedEl.hide({
50372 this.el.slideIn(this.getSlideAnchor(), {
50373 callback : function(){
50374 this.el.setStyle("z-index", "");
50377 this.split.el.show();
50379 this.fireEvent("invalidated", this);
50380 this.fireEvent("expanded", this);
50408 getAnchor : function(){
50409 return this.anchors[this.position];
50412 getCollapseAnchor : function(){
50413 return this.canchors[this.position];
50416 getSlideAnchor : function(){
50417 return this.sanchors[this.position];
50420 getAlignAdj : function(){
50421 var cm = this.cmargins;
50422 switch(this.position){
50438 getExpandAdj : function(){
50439 var c = this.collapsedEl, cm = this.cmargins;
50440 switch(this.position){
50442 return [-(cm.right+c.getWidth()+cm.left), 0];
50445 return [cm.right+c.getWidth()+cm.left, 0];
50448 return [0, -(cm.top+cm.bottom+c.getHeight())];
50451 return [0, cm.top+cm.bottom+c.getHeight()];
50457 * Ext JS Library 1.1.1
50458 * Copyright(c) 2006-2007, Ext JS, LLC.
50460 * Originally Released Under LGPL - original licence link has changed is not relivant.
50463 * <script type="text/javascript">
50466 * These classes are private internal classes
50468 Roo.CenterLayoutRegion = function(mgr, config){
50469 Roo.LayoutRegion.call(this, mgr, config, "center");
50470 this.visible = true;
50471 this.minWidth = config.minWidth || 20;
50472 this.minHeight = config.minHeight || 20;
50475 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50477 // center panel can't be hidden
50481 // center panel can't be hidden
50484 getMinWidth: function(){
50485 return this.minWidth;
50488 getMinHeight: function(){
50489 return this.minHeight;
50494 Roo.NorthLayoutRegion = function(mgr, config){
50495 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50497 this.split.placement = Roo.SplitBar.TOP;
50498 this.split.orientation = Roo.SplitBar.VERTICAL;
50499 this.split.el.addClass("x-layout-split-v");
50501 var size = config.initialSize || config.height;
50502 if(typeof size != "undefined"){
50503 this.el.setHeight(size);
50506 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50507 orientation: Roo.SplitBar.VERTICAL,
50508 getBox : function(){
50509 if(this.collapsed){
50510 return this.collapsedEl.getBox();
50512 var box = this.el.getBox();
50514 box.height += this.split.el.getHeight();
50519 updateBox : function(box){
50520 if(this.split && !this.collapsed){
50521 box.height -= this.split.el.getHeight();
50522 this.split.el.setLeft(box.x);
50523 this.split.el.setTop(box.y+box.height);
50524 this.split.el.setWidth(box.width);
50526 if(this.collapsed){
50527 this.updateBody(box.width, null);
50529 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50533 Roo.SouthLayoutRegion = function(mgr, config){
50534 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50536 this.split.placement = Roo.SplitBar.BOTTOM;
50537 this.split.orientation = Roo.SplitBar.VERTICAL;
50538 this.split.el.addClass("x-layout-split-v");
50540 var size = config.initialSize || config.height;
50541 if(typeof size != "undefined"){
50542 this.el.setHeight(size);
50545 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50546 orientation: Roo.SplitBar.VERTICAL,
50547 getBox : function(){
50548 if(this.collapsed){
50549 return this.collapsedEl.getBox();
50551 var box = this.el.getBox();
50553 var sh = this.split.el.getHeight();
50560 updateBox : function(box){
50561 if(this.split && !this.collapsed){
50562 var sh = this.split.el.getHeight();
50565 this.split.el.setLeft(box.x);
50566 this.split.el.setTop(box.y-sh);
50567 this.split.el.setWidth(box.width);
50569 if(this.collapsed){
50570 this.updateBody(box.width, null);
50572 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50576 Roo.EastLayoutRegion = function(mgr, config){
50577 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50579 this.split.placement = Roo.SplitBar.RIGHT;
50580 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50581 this.split.el.addClass("x-layout-split-h");
50583 var size = config.initialSize || config.width;
50584 if(typeof size != "undefined"){
50585 this.el.setWidth(size);
50588 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50589 orientation: Roo.SplitBar.HORIZONTAL,
50590 getBox : function(){
50591 if(this.collapsed){
50592 return this.collapsedEl.getBox();
50594 var box = this.el.getBox();
50596 var sw = this.split.el.getWidth();
50603 updateBox : function(box){
50604 if(this.split && !this.collapsed){
50605 var sw = this.split.el.getWidth();
50607 this.split.el.setLeft(box.x);
50608 this.split.el.setTop(box.y);
50609 this.split.el.setHeight(box.height);
50612 if(this.collapsed){
50613 this.updateBody(null, box.height);
50615 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50619 Roo.WestLayoutRegion = function(mgr, config){
50620 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50622 this.split.placement = Roo.SplitBar.LEFT;
50623 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50624 this.split.el.addClass("x-layout-split-h");
50626 var size = config.initialSize || config.width;
50627 if(typeof size != "undefined"){
50628 this.el.setWidth(size);
50631 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50632 orientation: Roo.SplitBar.HORIZONTAL,
50633 getBox : function(){
50634 if(this.collapsed){
50635 return this.collapsedEl.getBox();
50637 var box = this.el.getBox();
50639 box.width += this.split.el.getWidth();
50644 updateBox : function(box){
50645 if(this.split && !this.collapsed){
50646 var sw = this.split.el.getWidth();
50648 this.split.el.setLeft(box.x+box.width);
50649 this.split.el.setTop(box.y);
50650 this.split.el.setHeight(box.height);
50652 if(this.collapsed){
50653 this.updateBody(null, box.height);
50655 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50660 * Ext JS Library 1.1.1
50661 * Copyright(c) 2006-2007, Ext JS, LLC.
50663 * Originally Released Under LGPL - original licence link has changed is not relivant.
50666 * <script type="text/javascript">
50671 * Private internal class for reading and applying state
50673 Roo.LayoutStateManager = function(layout){
50674 // default empty state
50683 Roo.LayoutStateManager.prototype = {
50684 init : function(layout, provider){
50685 this.provider = provider;
50686 var state = provider.get(layout.id+"-layout-state");
50688 var wasUpdating = layout.isUpdating();
50690 layout.beginUpdate();
50692 for(var key in state){
50693 if(typeof state[key] != "function"){
50694 var rstate = state[key];
50695 var r = layout.getRegion(key);
50698 r.resizeTo(rstate.size);
50700 if(rstate.collapsed == true){
50703 r.expand(null, true);
50709 layout.endUpdate();
50711 this.state = state;
50713 this.layout = layout;
50714 layout.on("regionresized", this.onRegionResized, this);
50715 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50716 layout.on("regionexpanded", this.onRegionExpanded, this);
50719 storeState : function(){
50720 this.provider.set(this.layout.id+"-layout-state", this.state);
50723 onRegionResized : function(region, newSize){
50724 this.state[region.getPosition()].size = newSize;
50728 onRegionCollapsed : function(region){
50729 this.state[region.getPosition()].collapsed = true;
50733 onRegionExpanded : function(region){
50734 this.state[region.getPosition()].collapsed = false;
50739 * Ext JS Library 1.1.1
50740 * Copyright(c) 2006-2007, Ext JS, LLC.
50742 * Originally Released Under LGPL - original licence link has changed is not relivant.
50745 * <script type="text/javascript">
50748 * @class Roo.ContentPanel
50749 * @extends Roo.util.Observable
50750 * A basic ContentPanel element.
50751 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50752 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50753 * @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
50754 * @cfg {Boolean} closable True if the panel can be closed/removed
50755 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50756 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50757 * @cfg {Toolbar} toolbar A toolbar for this panel
50758 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50759 * @cfg {String} title The title for this panel
50760 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50761 * @cfg {String} url Calls {@link #setUrl} with this value
50762 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50763 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50764 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50765 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50768 * Create a new ContentPanel.
50769 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50770 * @param {String/Object} config A string to set only the title or a config object
50771 * @param {String} content (optional) Set the HTML content for this panel
50772 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50774 Roo.ContentPanel = function(el, config, content){
50778 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50782 if (config && config.parentLayout) {
50783 el = config.parentLayout.el.createChild();
50786 if(el.autoCreate){ // xtype is available if this is called from factory
50790 this.el = Roo.get(el);
50791 if(!this.el && config && config.autoCreate){
50792 if(typeof config.autoCreate == "object"){
50793 if(!config.autoCreate.id){
50794 config.autoCreate.id = config.id||el;
50796 this.el = Roo.DomHelper.append(document.body,
50797 config.autoCreate, true);
50799 this.el = Roo.DomHelper.append(document.body,
50800 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50803 this.closable = false;
50804 this.loaded = false;
50805 this.active = false;
50806 if(typeof config == "string"){
50807 this.title = config;
50809 Roo.apply(this, config);
50812 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50813 this.wrapEl = this.el.wrap();
50814 this.toolbar.container = this.el.insertSibling(false, 'before');
50815 this.toolbar = new Roo.Toolbar(this.toolbar);
50818 // xtype created footer. - not sure if will work as we normally have to render first..
50819 if (this.footer && !this.footer.el && this.footer.xtype) {
50820 if (!this.wrapEl) {
50821 this.wrapEl = this.el.wrap();
50824 this.footer.container = this.wrapEl.createChild();
50826 this.footer = Roo.factory(this.footer, Roo);
50831 this.resizeEl = Roo.get(this.resizeEl, true);
50833 this.resizeEl = this.el;
50835 // handle view.xtype
50843 * Fires when this panel is activated.
50844 * @param {Roo.ContentPanel} this
50848 * @event deactivate
50849 * Fires when this panel is activated.
50850 * @param {Roo.ContentPanel} this
50852 "deactivate" : true,
50856 * Fires when this panel is resized if fitToFrame is true.
50857 * @param {Roo.ContentPanel} this
50858 * @param {Number} width The width after any component adjustments
50859 * @param {Number} height The height after any component adjustments
50865 * Fires when this tab is created
50866 * @param {Roo.ContentPanel} this
50877 if(this.autoScroll){
50878 this.resizeEl.setStyle("overflow", "auto");
50880 // fix randome scrolling
50881 this.el.on('scroll', function() {
50882 Roo.log('fix random scolling');
50883 this.scrollTo('top',0);
50886 content = content || this.content;
50888 this.setContent(content);
50890 if(config && config.url){
50891 this.setUrl(this.url, this.params, this.loadOnce);
50896 Roo.ContentPanel.superclass.constructor.call(this);
50898 if (this.view && typeof(this.view.xtype) != 'undefined') {
50899 this.view.el = this.el.appendChild(document.createElement("div"));
50900 this.view = Roo.factory(this.view);
50901 this.view.render && this.view.render(false, '');
50905 this.fireEvent('render', this);
50908 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50910 setRegion : function(region){
50911 this.region = region;
50913 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50915 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50920 * Returns the toolbar for this Panel if one was configured.
50921 * @return {Roo.Toolbar}
50923 getToolbar : function(){
50924 return this.toolbar;
50927 setActiveState : function(active){
50928 this.active = active;
50930 this.fireEvent("deactivate", this);
50932 this.fireEvent("activate", this);
50936 * Updates this panel's element
50937 * @param {String} content The new content
50938 * @param {Boolean} loadScripts (optional) true to look for and process scripts
50940 setContent : function(content, loadScripts){
50941 this.el.update(content, loadScripts);
50944 ignoreResize : function(w, h){
50945 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
50948 this.lastSize = {width: w, height: h};
50953 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
50954 * @return {Roo.UpdateManager} The UpdateManager
50956 getUpdateManager : function(){
50957 return this.el.getUpdateManager();
50960 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
50961 * @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:
50964 url: "your-url.php",
50965 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
50966 callback: yourFunction,
50967 scope: yourObject, //(optional scope)
50970 text: "Loading...",
50975 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
50976 * 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.
50977 * @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}
50978 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
50979 * @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.
50980 * @return {Roo.ContentPanel} this
50983 var um = this.el.getUpdateManager();
50984 um.update.apply(um, arguments);
50990 * 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.
50991 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
50992 * @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)
50993 * @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)
50994 * @return {Roo.UpdateManager} The UpdateManager
50996 setUrl : function(url, params, loadOnce){
50997 if(this.refreshDelegate){
50998 this.removeListener("activate", this.refreshDelegate);
51000 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51001 this.on("activate", this.refreshDelegate);
51002 return this.el.getUpdateManager();
51005 _handleRefresh : function(url, params, loadOnce){
51006 if(!loadOnce || !this.loaded){
51007 var updater = this.el.getUpdateManager();
51008 updater.update(url, params, this._setLoaded.createDelegate(this));
51012 _setLoaded : function(){
51013 this.loaded = true;
51017 * Returns this panel's id
51020 getId : function(){
51025 * Returns this panel's element - used by regiosn to add.
51026 * @return {Roo.Element}
51028 getEl : function(){
51029 return this.wrapEl || this.el;
51032 adjustForComponents : function(width, height)
51034 //Roo.log('adjustForComponents ');
51035 if(this.resizeEl != this.el){
51036 width -= this.el.getFrameWidth('lr');
51037 height -= this.el.getFrameWidth('tb');
51040 var te = this.toolbar.getEl();
51041 height -= te.getHeight();
51042 te.setWidth(width);
51045 var te = this.footer.getEl();
51046 Roo.log("footer:" + te.getHeight());
51048 height -= te.getHeight();
51049 te.setWidth(width);
51053 if(this.adjustments){
51054 width += this.adjustments[0];
51055 height += this.adjustments[1];
51057 return {"width": width, "height": height};
51060 setSize : function(width, height){
51061 if(this.fitToFrame && !this.ignoreResize(width, height)){
51062 if(this.fitContainer && this.resizeEl != this.el){
51063 this.el.setSize(width, height);
51065 var size = this.adjustForComponents(width, height);
51066 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51067 this.fireEvent('resize', this, size.width, size.height);
51072 * Returns this panel's title
51075 getTitle : function(){
51080 * Set this panel's title
51081 * @param {String} title
51083 setTitle : function(title){
51084 this.title = title;
51086 this.region.updatePanelTitle(this, title);
51091 * Returns true is this panel was configured to be closable
51092 * @return {Boolean}
51094 isClosable : function(){
51095 return this.closable;
51098 beforeSlide : function(){
51100 this.resizeEl.clip();
51103 afterSlide : function(){
51105 this.resizeEl.unclip();
51109 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51110 * Will fail silently if the {@link #setUrl} method has not been called.
51111 * This does not activate the panel, just updates its content.
51113 refresh : function(){
51114 if(this.refreshDelegate){
51115 this.loaded = false;
51116 this.refreshDelegate();
51121 * Destroys this panel
51123 destroy : function(){
51124 this.el.removeAllListeners();
51125 var tempEl = document.createElement("span");
51126 tempEl.appendChild(this.el.dom);
51127 tempEl.innerHTML = "";
51133 * form - if the content panel contains a form - this is a reference to it.
51134 * @type {Roo.form.Form}
51138 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51139 * This contains a reference to it.
51145 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51155 * @param {Object} cfg Xtype definition of item to add.
51158 addxtype : function(cfg) {
51160 if (cfg.xtype.match(/^Form$/)) {
51163 //if (this.footer) {
51164 // el = this.footer.container.insertSibling(false, 'before');
51166 el = this.el.createChild();
51169 this.form = new Roo.form.Form(cfg);
51172 if ( this.form.allItems.length) this.form.render(el.dom);
51175 // should only have one of theses..
51176 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51177 // views.. should not be just added - used named prop 'view''
51179 cfg.el = this.el.appendChild(document.createElement("div"));
51182 var ret = new Roo.factory(cfg);
51184 ret.render && ret.render(false, ''); // render blank..
51193 * @class Roo.GridPanel
51194 * @extends Roo.ContentPanel
51196 * Create a new GridPanel.
51197 * @param {Roo.grid.Grid} grid The grid for this panel
51198 * @param {String/Object} config A string to set only the panel's title, or a config object
51200 Roo.GridPanel = function(grid, config){
51203 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51204 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51206 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51208 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51211 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51213 // xtype created footer. - not sure if will work as we normally have to render first..
51214 if (this.footer && !this.footer.el && this.footer.xtype) {
51216 this.footer.container = this.grid.getView().getFooterPanel(true);
51217 this.footer.dataSource = this.grid.dataSource;
51218 this.footer = Roo.factory(this.footer, Roo);
51222 grid.monitorWindowResize = false; // turn off autosizing
51223 grid.autoHeight = false;
51224 grid.autoWidth = false;
51226 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51229 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51230 getId : function(){
51231 return this.grid.id;
51235 * Returns the grid for this panel
51236 * @return {Roo.grid.Grid}
51238 getGrid : function(){
51242 setSize : function(width, height){
51243 if(!this.ignoreResize(width, height)){
51244 var grid = this.grid;
51245 var size = this.adjustForComponents(width, height);
51246 grid.getGridEl().setSize(size.width, size.height);
51251 beforeSlide : function(){
51252 this.grid.getView().scroller.clip();
51255 afterSlide : function(){
51256 this.grid.getView().scroller.unclip();
51259 destroy : function(){
51260 this.grid.destroy();
51262 Roo.GridPanel.superclass.destroy.call(this);
51268 * @class Roo.NestedLayoutPanel
51269 * @extends Roo.ContentPanel
51271 * Create a new NestedLayoutPanel.
51274 * @param {Roo.BorderLayout} layout The layout for this panel
51275 * @param {String/Object} config A string to set only the title or a config object
51277 Roo.NestedLayoutPanel = function(layout, config)
51279 // construct with only one argument..
51280 /* FIXME - implement nicer consturctors
51281 if (layout.layout) {
51283 layout = config.layout;
51284 delete config.layout;
51286 if (layout.xtype && !layout.getEl) {
51287 // then layout needs constructing..
51288 layout = Roo.factory(layout, Roo);
51293 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51295 layout.monitorWindowResize = false; // turn off autosizing
51296 this.layout = layout;
51297 this.layout.getEl().addClass("x-layout-nested-layout");
51304 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51306 setSize : function(width, height){
51307 if(!this.ignoreResize(width, height)){
51308 var size = this.adjustForComponents(width, height);
51309 var el = this.layout.getEl();
51310 el.setSize(size.width, size.height);
51311 var touch = el.dom.offsetWidth;
51312 this.layout.layout();
51313 // ie requires a double layout on the first pass
51314 if(Roo.isIE && !this.initialized){
51315 this.initialized = true;
51316 this.layout.layout();
51321 // activate all subpanels if not currently active..
51323 setActiveState : function(active){
51324 this.active = active;
51326 this.fireEvent("deactivate", this);
51330 this.fireEvent("activate", this);
51331 // not sure if this should happen before or after..
51332 if (!this.layout) {
51333 return; // should not happen..
51336 for (var r in this.layout.regions) {
51337 reg = this.layout.getRegion(r);
51338 if (reg.getActivePanel()) {
51339 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51340 reg.setActivePanel(reg.getActivePanel());
51343 if (!reg.panels.length) {
51346 reg.showPanel(reg.getPanel(0));
51355 * Returns the nested BorderLayout for this panel
51356 * @return {Roo.BorderLayout}
51358 getLayout : function(){
51359 return this.layout;
51363 * Adds a xtype elements to the layout of the nested panel
51367 xtype : 'ContentPanel',
51374 xtype : 'NestedLayoutPanel',
51380 items : [ ... list of content panels or nested layout panels.. ]
51384 * @param {Object} cfg Xtype definition of item to add.
51386 addxtype : function(cfg) {
51387 return this.layout.addxtype(cfg);
51392 Roo.ScrollPanel = function(el, config, content){
51393 config = config || {};
51394 config.fitToFrame = true;
51395 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51397 this.el.dom.style.overflow = "hidden";
51398 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51399 this.el.removeClass("x-layout-inactive-content");
51400 this.el.on("mousewheel", this.onWheel, this);
51402 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51403 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51404 up.unselectable(); down.unselectable();
51405 up.on("click", this.scrollUp, this);
51406 down.on("click", this.scrollDown, this);
51407 up.addClassOnOver("x-scroller-btn-over");
51408 down.addClassOnOver("x-scroller-btn-over");
51409 up.addClassOnClick("x-scroller-btn-click");
51410 down.addClassOnClick("x-scroller-btn-click");
51411 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51413 this.resizeEl = this.el;
51414 this.el = wrap; this.up = up; this.down = down;
51417 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51419 wheelIncrement : 5,
51420 scrollUp : function(){
51421 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51424 scrollDown : function(){
51425 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51428 afterScroll : function(){
51429 var el = this.resizeEl;
51430 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51431 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51432 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51435 setSize : function(){
51436 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51437 this.afterScroll();
51440 onWheel : function(e){
51441 var d = e.getWheelDelta();
51442 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51443 this.afterScroll();
51447 setContent : function(content, loadScripts){
51448 this.resizeEl.update(content, loadScripts);
51462 * @class Roo.TreePanel
51463 * @extends Roo.ContentPanel
51465 * Create a new TreePanel. - defaults to fit/scoll contents.
51466 * @param {String/Object} config A string to set only the panel's title, or a config object
51467 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51469 Roo.TreePanel = function(config){
51470 var el = config.el;
51471 var tree = config.tree;
51472 delete config.tree;
51473 delete config.el; // hopefull!
51475 // wrapper for IE7 strict & safari scroll issue
51477 var treeEl = el.createChild();
51478 config.resizeEl = treeEl;
51482 Roo.TreePanel.superclass.constructor.call(this, el, config);
51485 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51486 //console.log(tree);
51487 this.on('activate', function()
51489 if (this.tree.rendered) {
51492 //console.log('render tree');
51493 this.tree.render();
51495 // this should not be needed.. - it's actually the 'el' that resizes?
51496 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51498 //this.on('resize', function (cp, w, h) {
51499 // this.tree.innerCt.setWidth(w);
51500 // this.tree.innerCt.setHeight(h);
51501 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51508 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51525 * Ext JS Library 1.1.1
51526 * Copyright(c) 2006-2007, Ext JS, LLC.
51528 * Originally Released Under LGPL - original licence link has changed is not relivant.
51531 * <script type="text/javascript">
51536 * @class Roo.ReaderLayout
51537 * @extends Roo.BorderLayout
51538 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51539 * center region containing two nested regions (a top one for a list view and one for item preview below),
51540 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51541 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51542 * expedites the setup of the overall layout and regions for this common application style.
51545 var reader = new Roo.ReaderLayout();
51546 var CP = Roo.ContentPanel; // shortcut for adding
51548 reader.beginUpdate();
51549 reader.add("north", new CP("north", "North"));
51550 reader.add("west", new CP("west", {title: "West"}));
51551 reader.add("east", new CP("east", {title: "East"}));
51553 reader.regions.listView.add(new CP("listView", "List"));
51554 reader.regions.preview.add(new CP("preview", "Preview"));
51555 reader.endUpdate();
51558 * Create a new ReaderLayout
51559 * @param {Object} config Configuration options
51560 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51561 * document.body if omitted)
51563 Roo.ReaderLayout = function(config, renderTo){
51564 var c = config || {size:{}};
51565 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51566 north: c.north !== false ? Roo.apply({
51570 }, c.north) : false,
51571 west: c.west !== false ? Roo.apply({
51579 margins:{left:5,right:0,bottom:5,top:5},
51580 cmargins:{left:5,right:5,bottom:5,top:5}
51581 }, c.west) : false,
51582 east: c.east !== false ? Roo.apply({
51590 margins:{left:0,right:5,bottom:5,top:5},
51591 cmargins:{left:5,right:5,bottom:5,top:5}
51592 }, c.east) : false,
51593 center: Roo.apply({
51594 tabPosition: 'top',
51598 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51602 this.el.addClass('x-reader');
51604 this.beginUpdate();
51606 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51607 south: c.preview !== false ? Roo.apply({
51614 cmargins:{top:5,left:0, right:0, bottom:0}
51615 }, c.preview) : false,
51616 center: Roo.apply({
51622 this.add('center', new Roo.NestedLayoutPanel(inner,
51623 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51627 this.regions.preview = inner.getRegion('south');
51628 this.regions.listView = inner.getRegion('center');
51631 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51633 * Ext JS Library 1.1.1
51634 * Copyright(c) 2006-2007, Ext JS, LLC.
51636 * Originally Released Under LGPL - original licence link has changed is not relivant.
51639 * <script type="text/javascript">
51643 * @class Roo.grid.Grid
51644 * @extends Roo.util.Observable
51645 * This class represents the primary interface of a component based grid control.
51646 * <br><br>Usage:<pre><code>
51647 var grid = new Roo.grid.Grid("my-container-id", {
51650 selModel: mySelectionModel,
51651 autoSizeColumns: true,
51652 monitorWindowResize: false,
51653 trackMouseOver: true
51658 * <b>Common Problems:</b><br/>
51659 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51660 * element will correct this<br/>
51661 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51662 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51663 * are unpredictable.<br/>
51664 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51665 * grid to calculate dimensions/offsets.<br/>
51667 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51668 * The container MUST have some type of size defined for the grid to fill. The container will be
51669 * automatically set to position relative if it isn't already.
51670 * @param {Object} config A config object that sets properties on this grid.
51672 Roo.grid.Grid = function(container, config){
51673 // initialize the container
51674 this.container = Roo.get(container);
51675 this.container.update("");
51676 this.container.setStyle("overflow", "hidden");
51677 this.container.addClass('x-grid-container');
51679 this.id = this.container.id;
51681 Roo.apply(this, config);
51682 // check and correct shorthanded configs
51684 this.dataSource = this.ds;
51688 this.colModel = this.cm;
51692 this.selModel = this.sm;
51696 if (this.selModel) {
51697 this.selModel = Roo.factory(this.selModel, Roo.grid);
51698 this.sm = this.selModel;
51699 this.sm.xmodule = this.xmodule || false;
51701 if (typeof(this.colModel.config) == 'undefined') {
51702 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51703 this.cm = this.colModel;
51704 this.cm.xmodule = this.xmodule || false;
51706 if (this.dataSource) {
51707 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51708 this.ds = this.dataSource;
51709 this.ds.xmodule = this.xmodule || false;
51716 this.container.setWidth(this.width);
51720 this.container.setHeight(this.height);
51727 * The raw click event for the entire grid.
51728 * @param {Roo.EventObject} e
51733 * The raw dblclick event for the entire grid.
51734 * @param {Roo.EventObject} e
51738 * @event contextmenu
51739 * The raw contextmenu event for the entire grid.
51740 * @param {Roo.EventObject} e
51742 "contextmenu" : true,
51745 * The raw mousedown event for the entire grid.
51746 * @param {Roo.EventObject} e
51748 "mousedown" : true,
51751 * The raw mouseup event for the entire grid.
51752 * @param {Roo.EventObject} e
51757 * The raw mouseover event for the entire grid.
51758 * @param {Roo.EventObject} e
51760 "mouseover" : true,
51763 * The raw mouseout event for the entire grid.
51764 * @param {Roo.EventObject} e
51769 * The raw keypress event for the entire grid.
51770 * @param {Roo.EventObject} e
51775 * The raw keydown event for the entire grid.
51776 * @param {Roo.EventObject} e
51784 * Fires when a cell is clicked
51785 * @param {Grid} this
51786 * @param {Number} rowIndex
51787 * @param {Number} columnIndex
51788 * @param {Roo.EventObject} e
51790 "cellclick" : true,
51792 * @event celldblclick
51793 * Fires when a cell is double clicked
51794 * @param {Grid} this
51795 * @param {Number} rowIndex
51796 * @param {Number} columnIndex
51797 * @param {Roo.EventObject} e
51799 "celldblclick" : true,
51802 * Fires when a row is clicked
51803 * @param {Grid} this
51804 * @param {Number} rowIndex
51805 * @param {Roo.EventObject} e
51809 * @event rowdblclick
51810 * Fires when a row is double clicked
51811 * @param {Grid} this
51812 * @param {Number} rowIndex
51813 * @param {Roo.EventObject} e
51815 "rowdblclick" : true,
51817 * @event headerclick
51818 * Fires when a header is clicked
51819 * @param {Grid} this
51820 * @param {Number} columnIndex
51821 * @param {Roo.EventObject} e
51823 "headerclick" : true,
51825 * @event headerdblclick
51826 * Fires when a header cell is double clicked
51827 * @param {Grid} this
51828 * @param {Number} columnIndex
51829 * @param {Roo.EventObject} e
51831 "headerdblclick" : true,
51833 * @event rowcontextmenu
51834 * Fires when a row is right clicked
51835 * @param {Grid} this
51836 * @param {Number} rowIndex
51837 * @param {Roo.EventObject} e
51839 "rowcontextmenu" : true,
51841 * @event cellcontextmenu
51842 * Fires when a cell is right clicked
51843 * @param {Grid} this
51844 * @param {Number} rowIndex
51845 * @param {Number} cellIndex
51846 * @param {Roo.EventObject} e
51848 "cellcontextmenu" : true,
51850 * @event headercontextmenu
51851 * Fires when a header is right clicked
51852 * @param {Grid} this
51853 * @param {Number} columnIndex
51854 * @param {Roo.EventObject} e
51856 "headercontextmenu" : true,
51858 * @event bodyscroll
51859 * Fires when the body element is scrolled
51860 * @param {Number} scrollLeft
51861 * @param {Number} scrollTop
51863 "bodyscroll" : true,
51865 * @event columnresize
51866 * Fires when the user resizes a column
51867 * @param {Number} columnIndex
51868 * @param {Number} newSize
51870 "columnresize" : true,
51872 * @event columnmove
51873 * Fires when the user moves a column
51874 * @param {Number} oldIndex
51875 * @param {Number} newIndex
51877 "columnmove" : true,
51880 * Fires when row(s) start being dragged
51881 * @param {Grid} this
51882 * @param {Roo.GridDD} dd The drag drop object
51883 * @param {event} e The raw browser event
51885 "startdrag" : true,
51888 * Fires when a drag operation is complete
51889 * @param {Grid} this
51890 * @param {Roo.GridDD} dd The drag drop object
51891 * @param {event} e The raw browser event
51896 * Fires when dragged row(s) are dropped on a valid DD target
51897 * @param {Grid} this
51898 * @param {Roo.GridDD} dd The drag drop object
51899 * @param {String} targetId The target drag drop object
51900 * @param {event} e The raw browser event
51905 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51906 * @param {Grid} this
51907 * @param {Roo.GridDD} dd The drag drop object
51908 * @param {String} targetId The target drag drop object
51909 * @param {event} e The raw browser event
51914 * Fires when the dragged row(s) first cross another DD target while being dragged
51915 * @param {Grid} this
51916 * @param {Roo.GridDD} dd The drag drop object
51917 * @param {String} targetId The target drag drop object
51918 * @param {event} e The raw browser event
51920 "dragenter" : true,
51923 * Fires when the dragged row(s) leave another DD target while being dragged
51924 * @param {Grid} this
51925 * @param {Roo.GridDD} dd The drag drop object
51926 * @param {String} targetId The target drag drop object
51927 * @param {event} e The raw browser event
51932 * Fires when a row is rendered, so you can change add a style to it.
51933 * @param {GridView} gridview The grid view
51934 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
51940 * Fires when the grid is rendered
51941 * @param {Grid} grid
51946 Roo.grid.Grid.superclass.constructor.call(this);
51948 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
51951 * @cfg {String} ddGroup - drag drop group.
51955 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
51957 minColumnWidth : 25,
51960 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
51961 * <b>on initial render.</b> It is more efficient to explicitly size the columns
51962 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
51964 autoSizeColumns : false,
51967 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
51969 autoSizeHeaders : true,
51972 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
51974 monitorWindowResize : true,
51977 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
51978 * rows measured to get a columns size. Default is 0 (all rows).
51980 maxRowsToMeasure : 0,
51983 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
51985 trackMouseOver : true,
51988 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
51992 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
51994 enableDragDrop : false,
51997 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
51999 enableColumnMove : true,
52002 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52004 enableColumnHide : true,
52007 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52009 enableRowHeightSync : false,
52012 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52017 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52019 autoHeight : false,
52022 * @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.
52024 autoExpandColumn : false,
52027 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52030 autoExpandMin : 50,
52033 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52035 autoExpandMax : 1000,
52038 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52043 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52047 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52057 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52058 * of a fixed width. Default is false.
52061 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52064 * Called once after all setup has been completed and the grid is ready to be rendered.
52065 * @return {Roo.grid.Grid} this
52067 render : function()
52069 var c = this.container;
52070 // try to detect autoHeight/width mode
52071 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52072 this.autoHeight = true;
52074 var view = this.getView();
52077 c.on("click", this.onClick, this);
52078 c.on("dblclick", this.onDblClick, this);
52079 c.on("contextmenu", this.onContextMenu, this);
52080 c.on("keydown", this.onKeyDown, this);
52082 c.on("touchstart", this.onTouchStart, this);
52085 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52087 this.getSelectionModel().init(this);
52092 this.loadMask = new Roo.LoadMask(this.container,
52093 Roo.apply({store:this.dataSource}, this.loadMask));
52097 if (this.toolbar && this.toolbar.xtype) {
52098 this.toolbar.container = this.getView().getHeaderPanel(true);
52099 this.toolbar = new Roo.Toolbar(this.toolbar);
52101 if (this.footer && this.footer.xtype) {
52102 this.footer.dataSource = this.getDataSource();
52103 this.footer.container = this.getView().getFooterPanel(true);
52104 this.footer = Roo.factory(this.footer, Roo);
52106 if (this.dropTarget && this.dropTarget.xtype) {
52107 delete this.dropTarget.xtype;
52108 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52112 this.rendered = true;
52113 this.fireEvent('render', this);
52118 * Reconfigures the grid to use a different Store and Column Model.
52119 * The View will be bound to the new objects and refreshed.
52120 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52121 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52123 reconfigure : function(dataSource, colModel){
52125 this.loadMask.destroy();
52126 this.loadMask = new Roo.LoadMask(this.container,
52127 Roo.apply({store:dataSource}, this.loadMask));
52129 this.view.bind(dataSource, colModel);
52130 this.dataSource = dataSource;
52131 this.colModel = colModel;
52132 this.view.refresh(true);
52136 onKeyDown : function(e){
52137 this.fireEvent("keydown", e);
52141 * Destroy this grid.
52142 * @param {Boolean} removeEl True to remove the element
52144 destroy : function(removeEl, keepListeners){
52146 this.loadMask.destroy();
52148 var c = this.container;
52149 c.removeAllListeners();
52150 this.view.destroy();
52151 this.colModel.purgeListeners();
52152 if(!keepListeners){
52153 this.purgeListeners();
52156 if(removeEl === true){
52162 processEvent : function(name, e){
52163 // does this fire select???
52164 Roo.log('grid:processEvent ' + name);
52166 if (name != 'touchstart' ) {
52167 this.fireEvent(name, e);
52170 var t = e.getTarget();
52172 var header = v.findHeaderIndex(t);
52173 if(header !== false){
52174 var ename = name == 'touchstart' ? 'click' : name;
52176 this.fireEvent("header" + ename, this, header, e);
52178 var row = v.findRowIndex(t);
52179 var cell = v.findCellIndex(t);
52180 if (name == 'touchstart') {
52181 // first touch is always a click.
52182 // hopefull this happens after selection is updated.?
52185 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52186 var cs = this.selModel.getSelectedCell();
52187 if (row == cs[0] && cell == cs[1]){
52191 if (typeof(this.selModel.getSelections) != 'undefined') {
52192 var cs = this.selModel.getSelections();
52193 var ds = this.dataSource;
52194 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52205 this.fireEvent("row" + name, this, row, e);
52206 if(cell !== false){
52207 this.fireEvent("cell" + name, this, row, cell, e);
52214 onClick : function(e){
52215 this.processEvent("click", e);
52218 onTouchStart : function(e){
52219 this.processEvent("touchstart", e);
52223 onContextMenu : function(e, t){
52224 this.processEvent("contextmenu", e);
52228 onDblClick : function(e){
52229 this.processEvent("dblclick", e);
52233 walkCells : function(row, col, step, fn, scope){
52234 var cm = this.colModel, clen = cm.getColumnCount();
52235 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52247 if(fn.call(scope || this, row, col, cm) === true){
52265 if(fn.call(scope || this, row, col, cm) === true){
52277 getSelections : function(){
52278 return this.selModel.getSelections();
52282 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52283 * but if manual update is required this method will initiate it.
52285 autoSize : function(){
52287 this.view.layout();
52288 if(this.view.adjustForScroll){
52289 this.view.adjustForScroll();
52295 * Returns the grid's underlying element.
52296 * @return {Element} The element
52298 getGridEl : function(){
52299 return this.container;
52302 // private for compatibility, overridden by editor grid
52303 stopEditing : function(){},
52306 * Returns the grid's SelectionModel.
52307 * @return {SelectionModel}
52309 getSelectionModel : function(){
52310 if(!this.selModel){
52311 this.selModel = new Roo.grid.RowSelectionModel();
52313 return this.selModel;
52317 * Returns the grid's DataSource.
52318 * @return {DataSource}
52320 getDataSource : function(){
52321 return this.dataSource;
52325 * Returns the grid's ColumnModel.
52326 * @return {ColumnModel}
52328 getColumnModel : function(){
52329 return this.colModel;
52333 * Returns the grid's GridView object.
52334 * @return {GridView}
52336 getView : function(){
52338 this.view = new Roo.grid.GridView(this.viewConfig);
52343 * Called to get grid's drag proxy text, by default returns this.ddText.
52346 getDragDropText : function(){
52347 var count = this.selModel.getCount();
52348 return String.format(this.ddText, count, count == 1 ? '' : 's');
52352 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52353 * %0 is replaced with the number of selected rows.
52356 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52358 * Ext JS Library 1.1.1
52359 * Copyright(c) 2006-2007, Ext JS, LLC.
52361 * Originally Released Under LGPL - original licence link has changed is not relivant.
52364 * <script type="text/javascript">
52367 Roo.grid.AbstractGridView = function(){
52371 "beforerowremoved" : true,
52372 "beforerowsinserted" : true,
52373 "beforerefresh" : true,
52374 "rowremoved" : true,
52375 "rowsinserted" : true,
52376 "rowupdated" : true,
52379 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52382 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52383 rowClass : "x-grid-row",
52384 cellClass : "x-grid-cell",
52385 tdClass : "x-grid-td",
52386 hdClass : "x-grid-hd",
52387 splitClass : "x-grid-hd-split",
52389 init: function(grid){
52391 var cid = this.grid.getGridEl().id;
52392 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52393 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52394 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52395 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52398 getColumnRenderers : function(){
52399 var renderers = [];
52400 var cm = this.grid.colModel;
52401 var colCount = cm.getColumnCount();
52402 for(var i = 0; i < colCount; i++){
52403 renderers[i] = cm.getRenderer(i);
52408 getColumnIds : function(){
52410 var cm = this.grid.colModel;
52411 var colCount = cm.getColumnCount();
52412 for(var i = 0; i < colCount; i++){
52413 ids[i] = cm.getColumnId(i);
52418 getDataIndexes : function(){
52419 if(!this.indexMap){
52420 this.indexMap = this.buildIndexMap();
52422 return this.indexMap.colToData;
52425 getColumnIndexByDataIndex : function(dataIndex){
52426 if(!this.indexMap){
52427 this.indexMap = this.buildIndexMap();
52429 return this.indexMap.dataToCol[dataIndex];
52433 * Set a css style for a column dynamically.
52434 * @param {Number} colIndex The index of the column
52435 * @param {String} name The css property name
52436 * @param {String} value The css value
52438 setCSSStyle : function(colIndex, name, value){
52439 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52440 Roo.util.CSS.updateRule(selector, name, value);
52443 generateRules : function(cm){
52444 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52445 Roo.util.CSS.removeStyleSheet(rulesId);
52446 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52447 var cid = cm.getColumnId(i);
52448 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52449 this.tdSelector, cid, " {\n}\n",
52450 this.hdSelector, cid, " {\n}\n",
52451 this.splitSelector, cid, " {\n}\n");
52453 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52457 * Ext JS Library 1.1.1
52458 * Copyright(c) 2006-2007, Ext JS, LLC.
52460 * Originally Released Under LGPL - original licence link has changed is not relivant.
52463 * <script type="text/javascript">
52467 // This is a support class used internally by the Grid components
52468 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52470 this.view = grid.getView();
52471 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52472 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52474 this.setHandleElId(Roo.id(hd));
52475 this.setOuterHandleElId(Roo.id(hd2));
52477 this.scroll = false;
52479 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52481 getDragData : function(e){
52482 var t = Roo.lib.Event.getTarget(e);
52483 var h = this.view.findHeaderCell(t);
52485 return {ddel: h.firstChild, header:h};
52490 onInitDrag : function(e){
52491 this.view.headersDisabled = true;
52492 var clone = this.dragData.ddel.cloneNode(true);
52493 clone.id = Roo.id();
52494 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52495 this.proxy.update(clone);
52499 afterValidDrop : function(){
52501 setTimeout(function(){
52502 v.headersDisabled = false;
52506 afterInvalidDrop : function(){
52508 setTimeout(function(){
52509 v.headersDisabled = false;
52515 * Ext JS Library 1.1.1
52516 * Copyright(c) 2006-2007, Ext JS, LLC.
52518 * Originally Released Under LGPL - original licence link has changed is not relivant.
52521 * <script type="text/javascript">
52524 // This is a support class used internally by the Grid components
52525 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52527 this.view = grid.getView();
52528 // split the proxies so they don't interfere with mouse events
52529 this.proxyTop = Roo.DomHelper.append(document.body, {
52530 cls:"col-move-top", html:" "
52532 this.proxyBottom = Roo.DomHelper.append(document.body, {
52533 cls:"col-move-bottom", html:" "
52535 this.proxyTop.hide = this.proxyBottom.hide = function(){
52536 this.setLeftTop(-100,-100);
52537 this.setStyle("visibility", "hidden");
52539 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52540 // temporarily disabled
52541 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52542 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52544 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52545 proxyOffsets : [-4, -9],
52546 fly: Roo.Element.fly,
52548 getTargetFromEvent : function(e){
52549 var t = Roo.lib.Event.getTarget(e);
52550 var cindex = this.view.findCellIndex(t);
52551 if(cindex !== false){
52552 return this.view.getHeaderCell(cindex);
52557 nextVisible : function(h){
52558 var v = this.view, cm = this.grid.colModel;
52561 if(!cm.isHidden(v.getCellIndex(h))){
52569 prevVisible : function(h){
52570 var v = this.view, cm = this.grid.colModel;
52573 if(!cm.isHidden(v.getCellIndex(h))){
52581 positionIndicator : function(h, n, e){
52582 var x = Roo.lib.Event.getPageX(e);
52583 var r = Roo.lib.Dom.getRegion(n.firstChild);
52584 var px, pt, py = r.top + this.proxyOffsets[1];
52585 if((r.right - x) <= (r.right-r.left)/2){
52586 px = r.right+this.view.borderWidth;
52592 var oldIndex = this.view.getCellIndex(h);
52593 var newIndex = this.view.getCellIndex(n);
52595 if(this.grid.colModel.isFixed(newIndex)){
52599 var locked = this.grid.colModel.isLocked(newIndex);
52604 if(oldIndex < newIndex){
52607 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52610 px += this.proxyOffsets[0];
52611 this.proxyTop.setLeftTop(px, py);
52612 this.proxyTop.show();
52613 if(!this.bottomOffset){
52614 this.bottomOffset = this.view.mainHd.getHeight();
52616 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52617 this.proxyBottom.show();
52621 onNodeEnter : function(n, dd, e, data){
52622 if(data.header != n){
52623 this.positionIndicator(data.header, n, e);
52627 onNodeOver : function(n, dd, e, data){
52628 var result = false;
52629 if(data.header != n){
52630 result = this.positionIndicator(data.header, n, e);
52633 this.proxyTop.hide();
52634 this.proxyBottom.hide();
52636 return result ? this.dropAllowed : this.dropNotAllowed;
52639 onNodeOut : function(n, dd, e, data){
52640 this.proxyTop.hide();
52641 this.proxyBottom.hide();
52644 onNodeDrop : function(n, dd, e, data){
52645 var h = data.header;
52647 var cm = this.grid.colModel;
52648 var x = Roo.lib.Event.getPageX(e);
52649 var r = Roo.lib.Dom.getRegion(n.firstChild);
52650 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52651 var oldIndex = this.view.getCellIndex(h);
52652 var newIndex = this.view.getCellIndex(n);
52653 var locked = cm.isLocked(newIndex);
52657 if(oldIndex < newIndex){
52660 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52663 cm.setLocked(oldIndex, locked, true);
52664 cm.moveColumn(oldIndex, newIndex);
52665 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52673 * Ext JS Library 1.1.1
52674 * Copyright(c) 2006-2007, Ext JS, LLC.
52676 * Originally Released Under LGPL - original licence link has changed is not relivant.
52679 * <script type="text/javascript">
52683 * @class Roo.grid.GridView
52684 * @extends Roo.util.Observable
52687 * @param {Object} config
52689 Roo.grid.GridView = function(config){
52690 Roo.grid.GridView.superclass.constructor.call(this);
52693 Roo.apply(this, config);
52696 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52698 unselectable : 'unselectable="on"',
52699 unselectableCls : 'x-unselectable',
52702 rowClass : "x-grid-row",
52704 cellClass : "x-grid-col",
52706 tdClass : "x-grid-td",
52708 hdClass : "x-grid-hd",
52710 splitClass : "x-grid-split",
52712 sortClasses : ["sort-asc", "sort-desc"],
52714 enableMoveAnim : false,
52718 dh : Roo.DomHelper,
52720 fly : Roo.Element.fly,
52722 css : Roo.util.CSS,
52728 scrollIncrement : 22,
52730 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52732 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52734 bind : function(ds, cm){
52736 this.ds.un("load", this.onLoad, this);
52737 this.ds.un("datachanged", this.onDataChange, this);
52738 this.ds.un("add", this.onAdd, this);
52739 this.ds.un("remove", this.onRemove, this);
52740 this.ds.un("update", this.onUpdate, this);
52741 this.ds.un("clear", this.onClear, this);
52744 ds.on("load", this.onLoad, this);
52745 ds.on("datachanged", this.onDataChange, this);
52746 ds.on("add", this.onAdd, this);
52747 ds.on("remove", this.onRemove, this);
52748 ds.on("update", this.onUpdate, this);
52749 ds.on("clear", this.onClear, this);
52754 this.cm.un("widthchange", this.onColWidthChange, this);
52755 this.cm.un("headerchange", this.onHeaderChange, this);
52756 this.cm.un("hiddenchange", this.onHiddenChange, this);
52757 this.cm.un("columnmoved", this.onColumnMove, this);
52758 this.cm.un("columnlockchange", this.onColumnLock, this);
52761 this.generateRules(cm);
52762 cm.on("widthchange", this.onColWidthChange, this);
52763 cm.on("headerchange", this.onHeaderChange, this);
52764 cm.on("hiddenchange", this.onHiddenChange, this);
52765 cm.on("columnmoved", this.onColumnMove, this);
52766 cm.on("columnlockchange", this.onColumnLock, this);
52771 init: function(grid){
52772 Roo.grid.GridView.superclass.init.call(this, grid);
52774 this.bind(grid.dataSource, grid.colModel);
52776 grid.on("headerclick", this.handleHeaderClick, this);
52778 if(grid.trackMouseOver){
52779 grid.on("mouseover", this.onRowOver, this);
52780 grid.on("mouseout", this.onRowOut, this);
52782 grid.cancelTextSelection = function(){};
52783 this.gridId = grid.id;
52785 var tpls = this.templates || {};
52788 tpls.master = new Roo.Template(
52789 '<div class="x-grid" hidefocus="true">',
52790 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52791 '<div class="x-grid-topbar"></div>',
52792 '<div class="x-grid-scroller"><div></div></div>',
52793 '<div class="x-grid-locked">',
52794 '<div class="x-grid-header">{lockedHeader}</div>',
52795 '<div class="x-grid-body">{lockedBody}</div>',
52797 '<div class="x-grid-viewport">',
52798 '<div class="x-grid-header">{header}</div>',
52799 '<div class="x-grid-body">{body}</div>',
52801 '<div class="x-grid-bottombar"></div>',
52803 '<div class="x-grid-resize-proxy"> </div>',
52806 tpls.master.disableformats = true;
52810 tpls.header = new Roo.Template(
52811 '<table border="0" cellspacing="0" cellpadding="0">',
52812 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52815 tpls.header.disableformats = true;
52817 tpls.header.compile();
52820 tpls.hcell = new Roo.Template(
52821 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52822 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52825 tpls.hcell.disableFormats = true;
52827 tpls.hcell.compile();
52830 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52831 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52832 tpls.hsplit.disableFormats = true;
52834 tpls.hsplit.compile();
52837 tpls.body = new Roo.Template(
52838 '<table border="0" cellspacing="0" cellpadding="0">',
52839 "<tbody>{rows}</tbody>",
52842 tpls.body.disableFormats = true;
52844 tpls.body.compile();
52847 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52848 tpls.row.disableFormats = true;
52850 tpls.row.compile();
52853 tpls.cell = new Roo.Template(
52854 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52855 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52856 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52859 tpls.cell.disableFormats = true;
52861 tpls.cell.compile();
52863 this.templates = tpls;
52866 // remap these for backwards compat
52867 onColWidthChange : function(){
52868 this.updateColumns.apply(this, arguments);
52870 onHeaderChange : function(){
52871 this.updateHeaders.apply(this, arguments);
52873 onHiddenChange : function(){
52874 this.handleHiddenChange.apply(this, arguments);
52876 onColumnMove : function(){
52877 this.handleColumnMove.apply(this, arguments);
52879 onColumnLock : function(){
52880 this.handleLockChange.apply(this, arguments);
52883 onDataChange : function(){
52885 this.updateHeaderSortState();
52888 onClear : function(){
52892 onUpdate : function(ds, record){
52893 this.refreshRow(record);
52896 refreshRow : function(record){
52897 var ds = this.ds, index;
52898 if(typeof record == 'number'){
52900 record = ds.getAt(index);
52902 index = ds.indexOf(record);
52904 this.insertRows(ds, index, index, true);
52905 this.onRemove(ds, record, index+1, true);
52906 this.syncRowHeights(index, index);
52908 this.fireEvent("rowupdated", this, index, record);
52911 onAdd : function(ds, records, index){
52912 this.insertRows(ds, index, index + (records.length-1));
52915 onRemove : function(ds, record, index, isUpdate){
52916 if(isUpdate !== true){
52917 this.fireEvent("beforerowremoved", this, index, record);
52919 var bt = this.getBodyTable(), lt = this.getLockedTable();
52920 if(bt.rows[index]){
52921 bt.firstChild.removeChild(bt.rows[index]);
52923 if(lt.rows[index]){
52924 lt.firstChild.removeChild(lt.rows[index]);
52926 if(isUpdate !== true){
52927 this.stripeRows(index);
52928 this.syncRowHeights(index, index);
52930 this.fireEvent("rowremoved", this, index, record);
52934 onLoad : function(){
52935 this.scrollToTop();
52939 * Scrolls the grid to the top
52941 scrollToTop : function(){
52943 this.scroller.dom.scrollTop = 0;
52949 * Gets a panel in the header of the grid that can be used for toolbars etc.
52950 * After modifying the contents of this panel a call to grid.autoSize() may be
52951 * required to register any changes in size.
52952 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
52953 * @return Roo.Element
52955 getHeaderPanel : function(doShow){
52957 this.headerPanel.show();
52959 return this.headerPanel;
52963 * Gets a panel in the footer of the grid that can be used for toolbars etc.
52964 * After modifying the contents of this panel a call to grid.autoSize() may be
52965 * required to register any changes in size.
52966 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
52967 * @return Roo.Element
52969 getFooterPanel : function(doShow){
52971 this.footerPanel.show();
52973 return this.footerPanel;
52976 initElements : function(){
52977 var E = Roo.Element;
52978 var el = this.grid.getGridEl().dom.firstChild;
52979 var cs = el.childNodes;
52981 this.el = new E(el);
52983 this.focusEl = new E(el.firstChild);
52984 this.focusEl.swallowEvent("click", true);
52986 this.headerPanel = new E(cs[1]);
52987 this.headerPanel.enableDisplayMode("block");
52989 this.scroller = new E(cs[2]);
52990 this.scrollSizer = new E(this.scroller.dom.firstChild);
52992 this.lockedWrap = new E(cs[3]);
52993 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
52994 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
52996 this.mainWrap = new E(cs[4]);
52997 this.mainHd = new E(this.mainWrap.dom.firstChild);
52998 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53000 this.footerPanel = new E(cs[5]);
53001 this.footerPanel.enableDisplayMode("block");
53003 this.resizeProxy = new E(cs[6]);
53005 this.headerSelector = String.format(
53006 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53007 this.lockedHd.id, this.mainHd.id
53010 this.splitterSelector = String.format(
53011 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53012 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53015 idToCssName : function(s)
53017 return s.replace(/[^a-z0-9]+/ig, '-');
53020 getHeaderCell : function(index){
53021 return Roo.DomQuery.select(this.headerSelector)[index];
53024 getHeaderCellMeasure : function(index){
53025 return this.getHeaderCell(index).firstChild;
53028 getHeaderCellText : function(index){
53029 return this.getHeaderCell(index).firstChild.firstChild;
53032 getLockedTable : function(){
53033 return this.lockedBody.dom.firstChild;
53036 getBodyTable : function(){
53037 return this.mainBody.dom.firstChild;
53040 getLockedRow : function(index){
53041 return this.getLockedTable().rows[index];
53044 getRow : function(index){
53045 return this.getBodyTable().rows[index];
53048 getRowComposite : function(index){
53050 this.rowEl = new Roo.CompositeElementLite();
53052 var els = [], lrow, mrow;
53053 if(lrow = this.getLockedRow(index)){
53056 if(mrow = this.getRow(index)){
53059 this.rowEl.elements = els;
53063 * Gets the 'td' of the cell
53065 * @param {Integer} rowIndex row to select
53066 * @param {Integer} colIndex column to select
53070 getCell : function(rowIndex, colIndex){
53071 var locked = this.cm.getLockedCount();
53073 if(colIndex < locked){
53074 source = this.lockedBody.dom.firstChild;
53076 source = this.mainBody.dom.firstChild;
53077 colIndex -= locked;
53079 return source.rows[rowIndex].childNodes[colIndex];
53082 getCellText : function(rowIndex, colIndex){
53083 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53086 getCellBox : function(cell){
53087 var b = this.fly(cell).getBox();
53088 if(Roo.isOpera){ // opera fails to report the Y
53089 b.y = cell.offsetTop + this.mainBody.getY();
53094 getCellIndex : function(cell){
53095 var id = String(cell.className).match(this.cellRE);
53097 return parseInt(id[1], 10);
53102 findHeaderIndex : function(n){
53103 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53104 return r ? this.getCellIndex(r) : false;
53107 findHeaderCell : function(n){
53108 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53109 return r ? r : false;
53112 findRowIndex : function(n){
53116 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53117 return r ? r.rowIndex : false;
53120 findCellIndex : function(node){
53121 var stop = this.el.dom;
53122 while(node && node != stop){
53123 if(this.findRE.test(node.className)){
53124 return this.getCellIndex(node);
53126 node = node.parentNode;
53131 getColumnId : function(index){
53132 return this.cm.getColumnId(index);
53135 getSplitters : function()
53137 if(this.splitterSelector){
53138 return Roo.DomQuery.select(this.splitterSelector);
53144 getSplitter : function(index){
53145 return this.getSplitters()[index];
53148 onRowOver : function(e, t){
53150 if((row = this.findRowIndex(t)) !== false){
53151 this.getRowComposite(row).addClass("x-grid-row-over");
53155 onRowOut : function(e, t){
53157 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53158 this.getRowComposite(row).removeClass("x-grid-row-over");
53162 renderHeaders : function(){
53164 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53165 var cb = [], lb = [], sb = [], lsb = [], p = {};
53166 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53167 p.cellId = "x-grid-hd-0-" + i;
53168 p.splitId = "x-grid-csplit-0-" + i;
53169 p.id = cm.getColumnId(i);
53170 p.title = cm.getColumnTooltip(i) || "";
53171 p.value = cm.getColumnHeader(i) || "";
53172 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53173 if(!cm.isLocked(i)){
53174 cb[cb.length] = ct.apply(p);
53175 sb[sb.length] = st.apply(p);
53177 lb[lb.length] = ct.apply(p);
53178 lsb[lsb.length] = st.apply(p);
53181 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53182 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53185 updateHeaders : function(){
53186 var html = this.renderHeaders();
53187 this.lockedHd.update(html[0]);
53188 this.mainHd.update(html[1]);
53192 * Focuses the specified row.
53193 * @param {Number} row The row index
53195 focusRow : function(row)
53197 //Roo.log('GridView.focusRow');
53198 var x = this.scroller.dom.scrollLeft;
53199 this.focusCell(row, 0, false);
53200 this.scroller.dom.scrollLeft = x;
53204 * Focuses the specified cell.
53205 * @param {Number} row The row index
53206 * @param {Number} col The column index
53207 * @param {Boolean} hscroll false to disable horizontal scrolling
53209 focusCell : function(row, col, hscroll)
53211 //Roo.log('GridView.focusCell');
53212 var el = this.ensureVisible(row, col, hscroll);
53213 this.focusEl.alignTo(el, "tl-tl");
53215 this.focusEl.focus();
53217 this.focusEl.focus.defer(1, this.focusEl);
53222 * Scrolls the specified cell into view
53223 * @param {Number} row The row index
53224 * @param {Number} col The column index
53225 * @param {Boolean} hscroll false to disable horizontal scrolling
53227 ensureVisible : function(row, col, hscroll)
53229 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53230 //return null; //disable for testing.
53231 if(typeof row != "number"){
53232 row = row.rowIndex;
53234 if(row < 0 && row >= this.ds.getCount()){
53237 col = (col !== undefined ? col : 0);
53238 var cm = this.grid.colModel;
53239 while(cm.isHidden(col)){
53243 var el = this.getCell(row, col);
53247 var c = this.scroller.dom;
53249 var ctop = parseInt(el.offsetTop, 10);
53250 var cleft = parseInt(el.offsetLeft, 10);
53251 var cbot = ctop + el.offsetHeight;
53252 var cright = cleft + el.offsetWidth;
53254 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53255 var stop = parseInt(c.scrollTop, 10);
53256 var sleft = parseInt(c.scrollLeft, 10);
53257 var sbot = stop + ch;
53258 var sright = sleft + c.clientWidth;
53260 Roo.log('GridView.ensureVisible:' +
53262 ' c.clientHeight:' + c.clientHeight +
53263 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53271 c.scrollTop = ctop;
53272 //Roo.log("set scrolltop to ctop DISABLE?");
53273 }else if(cbot > sbot){
53274 //Roo.log("set scrolltop to cbot-ch");
53275 c.scrollTop = cbot-ch;
53278 if(hscroll !== false){
53280 c.scrollLeft = cleft;
53281 }else if(cright > sright){
53282 c.scrollLeft = cright-c.clientWidth;
53289 updateColumns : function(){
53290 this.grid.stopEditing();
53291 var cm = this.grid.colModel, colIds = this.getColumnIds();
53292 //var totalWidth = cm.getTotalWidth();
53294 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53295 //if(cm.isHidden(i)) continue;
53296 var w = cm.getColumnWidth(i);
53297 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53298 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53300 this.updateSplitters();
53303 generateRules : function(cm){
53304 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53305 Roo.util.CSS.removeStyleSheet(rulesId);
53306 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53307 var cid = cm.getColumnId(i);
53309 if(cm.config[i].align){
53310 align = 'text-align:'+cm.config[i].align+';';
53313 if(cm.isHidden(i)){
53314 hidden = 'display:none;';
53316 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53318 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53319 this.hdSelector, cid, " {\n", align, width, "}\n",
53320 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53321 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53323 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53326 updateSplitters : function(){
53327 var cm = this.cm, s = this.getSplitters();
53328 if(s){ // splitters not created yet
53329 var pos = 0, locked = true;
53330 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53331 if(cm.isHidden(i)) continue;
53332 var w = cm.getColumnWidth(i); // make sure it's a number
53333 if(!cm.isLocked(i) && locked){
53338 s[i].style.left = (pos-this.splitOffset) + "px";
53343 handleHiddenChange : function(colModel, colIndex, hidden){
53345 this.hideColumn(colIndex);
53347 this.unhideColumn(colIndex);
53351 hideColumn : function(colIndex){
53352 var cid = this.getColumnId(colIndex);
53353 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53354 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53356 this.updateHeaders();
53358 this.updateSplitters();
53362 unhideColumn : function(colIndex){
53363 var cid = this.getColumnId(colIndex);
53364 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53365 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53368 this.updateHeaders();
53370 this.updateSplitters();
53374 insertRows : function(dm, firstRow, lastRow, isUpdate){
53375 if(firstRow == 0 && lastRow == dm.getCount()-1){
53379 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53381 var s = this.getScrollState();
53382 var markup = this.renderRows(firstRow, lastRow);
53383 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53384 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53385 this.restoreScroll(s);
53387 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53388 this.syncRowHeights(firstRow, lastRow);
53389 this.stripeRows(firstRow);
53395 bufferRows : function(markup, target, index){
53396 var before = null, trows = target.rows, tbody = target.tBodies[0];
53397 if(index < trows.length){
53398 before = trows[index];
53400 var b = document.createElement("div");
53401 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53402 var rows = b.firstChild.rows;
53403 for(var i = 0, len = rows.length; i < len; i++){
53405 tbody.insertBefore(rows[0], before);
53407 tbody.appendChild(rows[0]);
53414 deleteRows : function(dm, firstRow, lastRow){
53415 if(dm.getRowCount()<1){
53416 this.fireEvent("beforerefresh", this);
53417 this.mainBody.update("");
53418 this.lockedBody.update("");
53419 this.fireEvent("refresh", this);
53421 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53422 var bt = this.getBodyTable();
53423 var tbody = bt.firstChild;
53424 var rows = bt.rows;
53425 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53426 tbody.removeChild(rows[firstRow]);
53428 this.stripeRows(firstRow);
53429 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53433 updateRows : function(dataSource, firstRow, lastRow){
53434 var s = this.getScrollState();
53436 this.restoreScroll(s);
53439 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53443 this.updateHeaderSortState();
53446 getScrollState : function(){
53448 var sb = this.scroller.dom;
53449 return {left: sb.scrollLeft, top: sb.scrollTop};
53452 stripeRows : function(startRow){
53453 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53456 startRow = startRow || 0;
53457 var rows = this.getBodyTable().rows;
53458 var lrows = this.getLockedTable().rows;
53459 var cls = ' x-grid-row-alt ';
53460 for(var i = startRow, len = rows.length; i < len; i++){
53461 var row = rows[i], lrow = lrows[i];
53462 var isAlt = ((i+1) % 2 == 0);
53463 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53464 if(isAlt == hasAlt){
53468 row.className += " x-grid-row-alt";
53470 row.className = row.className.replace("x-grid-row-alt", "");
53473 lrow.className = row.className;
53478 restoreScroll : function(state){
53479 //Roo.log('GridView.restoreScroll');
53480 var sb = this.scroller.dom;
53481 sb.scrollLeft = state.left;
53482 sb.scrollTop = state.top;
53486 syncScroll : function(){
53487 //Roo.log('GridView.syncScroll');
53488 var sb = this.scroller.dom;
53489 var sh = this.mainHd.dom;
53490 var bs = this.mainBody.dom;
53491 var lv = this.lockedBody.dom;
53492 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53493 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53496 handleScroll : function(e){
53498 var sb = this.scroller.dom;
53499 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53503 handleWheel : function(e){
53504 var d = e.getWheelDelta();
53505 this.scroller.dom.scrollTop -= d*22;
53506 // set this here to prevent jumpy scrolling on large tables
53507 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53511 renderRows : function(startRow, endRow){
53512 // pull in all the crap needed to render rows
53513 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53514 var colCount = cm.getColumnCount();
53516 if(ds.getCount() < 1){
53520 // build a map for all the columns
53522 for(var i = 0; i < colCount; i++){
53523 var name = cm.getDataIndex(i);
53525 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53526 renderer : cm.getRenderer(i),
53527 id : cm.getColumnId(i),
53528 locked : cm.isLocked(i)
53532 startRow = startRow || 0;
53533 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53535 // records to render
53536 var rs = ds.getRange(startRow, endRow);
53538 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53541 // As much as I hate to duplicate code, this was branched because FireFox really hates
53542 // [].join("") on strings. The performance difference was substantial enough to
53543 // branch this function
53544 doRender : Roo.isGecko ?
53545 function(cs, rs, ds, startRow, colCount, stripe){
53546 var ts = this.templates, ct = ts.cell, rt = ts.row;
53548 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53550 var hasListener = this.grid.hasListener('rowclass');
53552 for(var j = 0, len = rs.length; j < len; j++){
53553 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53554 for(var i = 0; i < colCount; i++){
53556 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53558 p.css = p.attr = "";
53559 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53560 if(p.value == undefined || p.value === "") p.value = " ";
53561 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53562 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53564 var markup = ct.apply(p);
53572 if(stripe && ((rowIndex+1) % 2 == 0)){
53573 alt.push("x-grid-row-alt")
53576 alt.push( " x-grid-dirty-row");
53579 if(this.getRowClass){
53580 alt.push(this.getRowClass(r, rowIndex));
53586 rowIndex : rowIndex,
53589 this.grid.fireEvent('rowclass', this, rowcfg);
53590 alt.push(rowcfg.rowClass);
53592 rp.alt = alt.join(" ");
53593 lbuf+= rt.apply(rp);
53595 buf+= rt.apply(rp);
53597 return [lbuf, buf];
53599 function(cs, rs, ds, startRow, colCount, stripe){
53600 var ts = this.templates, ct = ts.cell, rt = ts.row;
53602 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53603 var hasListener = this.grid.hasListener('rowclass');
53606 for(var j = 0, len = rs.length; j < len; j++){
53607 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53608 for(var i = 0; i < colCount; i++){
53610 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53612 p.css = p.attr = "";
53613 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53614 if(p.value == undefined || p.value === "") p.value = " ";
53615 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53616 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53619 var markup = ct.apply(p);
53621 cb[cb.length] = markup;
53623 lcb[lcb.length] = markup;
53627 if(stripe && ((rowIndex+1) % 2 == 0)){
53628 alt.push( "x-grid-row-alt");
53631 alt.push(" x-grid-dirty-row");
53634 if(this.getRowClass){
53635 alt.push( this.getRowClass(r, rowIndex));
53641 rowIndex : rowIndex,
53644 this.grid.fireEvent('rowclass', this, rowcfg);
53645 alt.push(rowcfg.rowClass);
53647 rp.alt = alt.join(" ");
53648 rp.cells = lcb.join("");
53649 lbuf[lbuf.length] = rt.apply(rp);
53650 rp.cells = cb.join("");
53651 buf[buf.length] = rt.apply(rp);
53653 return [lbuf.join(""), buf.join("")];
53656 renderBody : function(){
53657 var markup = this.renderRows();
53658 var bt = this.templates.body;
53659 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53663 * Refreshes the grid
53664 * @param {Boolean} headersToo
53666 refresh : function(headersToo){
53667 this.fireEvent("beforerefresh", this);
53668 this.grid.stopEditing();
53669 var result = this.renderBody();
53670 this.lockedBody.update(result[0]);
53671 this.mainBody.update(result[1]);
53672 if(headersToo === true){
53673 this.updateHeaders();
53674 this.updateColumns();
53675 this.updateSplitters();
53676 this.updateHeaderSortState();
53678 this.syncRowHeights();
53680 this.fireEvent("refresh", this);
53683 handleColumnMove : function(cm, oldIndex, newIndex){
53684 this.indexMap = null;
53685 var s = this.getScrollState();
53686 this.refresh(true);
53687 this.restoreScroll(s);
53688 this.afterMove(newIndex);
53691 afterMove : function(colIndex){
53692 if(this.enableMoveAnim && Roo.enableFx){
53693 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53695 // if multisort - fix sortOrder, and reload..
53696 if (this.grid.dataSource.multiSort) {
53697 // the we can call sort again..
53698 var dm = this.grid.dataSource;
53699 var cm = this.grid.colModel;
53701 for(var i = 0; i < cm.config.length; i++ ) {
53703 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53704 continue; // dont' bother, it's not in sort list or being set.
53707 so.push(cm.config[i].dataIndex);
53710 dm.load(dm.lastOptions);
53717 updateCell : function(dm, rowIndex, dataIndex){
53718 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53719 if(typeof colIndex == "undefined"){ // not present in grid
53722 var cm = this.grid.colModel;
53723 var cell = this.getCell(rowIndex, colIndex);
53724 var cellText = this.getCellText(rowIndex, colIndex);
53727 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53728 id : cm.getColumnId(colIndex),
53729 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53731 var renderer = cm.getRenderer(colIndex);
53732 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53733 if(typeof val == "undefined" || val === "") val = " ";
53734 cellText.innerHTML = val;
53735 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53736 this.syncRowHeights(rowIndex, rowIndex);
53739 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53741 if(this.grid.autoSizeHeaders){
53742 var h = this.getHeaderCellMeasure(colIndex);
53743 maxWidth = Math.max(maxWidth, h.scrollWidth);
53746 if(this.cm.isLocked(colIndex)){
53747 tb = this.getLockedTable();
53750 tb = this.getBodyTable();
53751 index = colIndex - this.cm.getLockedCount();
53754 var rows = tb.rows;
53755 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53756 for(var i = 0; i < stopIndex; i++){
53757 var cell = rows[i].childNodes[index].firstChild;
53758 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53761 return maxWidth + /*margin for error in IE*/ 5;
53764 * Autofit a column to its content.
53765 * @param {Number} colIndex
53766 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53768 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53769 if(this.cm.isHidden(colIndex)){
53770 return; // can't calc a hidden column
53773 var cid = this.cm.getColumnId(colIndex);
53774 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53775 if(this.grid.autoSizeHeaders){
53776 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53779 var newWidth = this.calcColumnWidth(colIndex);
53780 this.cm.setColumnWidth(colIndex,
53781 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53782 if(!suppressEvent){
53783 this.grid.fireEvent("columnresize", colIndex, newWidth);
53788 * Autofits all columns to their content and then expands to fit any extra space in the grid
53790 autoSizeColumns : function(){
53791 var cm = this.grid.colModel;
53792 var colCount = cm.getColumnCount();
53793 for(var i = 0; i < colCount; i++){
53794 this.autoSizeColumn(i, true, true);
53796 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53799 this.updateColumns();
53805 * Autofits all columns to the grid's width proportionate with their current size
53806 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53808 fitColumns : function(reserveScrollSpace){
53809 var cm = this.grid.colModel;
53810 var colCount = cm.getColumnCount();
53814 for (i = 0; i < colCount; i++){
53815 if(!cm.isHidden(i) && !cm.isFixed(i)){
53816 w = cm.getColumnWidth(i);
53822 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53823 if(reserveScrollSpace){
53826 var frac = (avail - cm.getTotalWidth())/width;
53827 while (cols.length){
53830 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53832 this.updateColumns();
53836 onRowSelect : function(rowIndex){
53837 var row = this.getRowComposite(rowIndex);
53838 row.addClass("x-grid-row-selected");
53841 onRowDeselect : function(rowIndex){
53842 var row = this.getRowComposite(rowIndex);
53843 row.removeClass("x-grid-row-selected");
53846 onCellSelect : function(row, col){
53847 var cell = this.getCell(row, col);
53849 Roo.fly(cell).addClass("x-grid-cell-selected");
53853 onCellDeselect : function(row, col){
53854 var cell = this.getCell(row, col);
53856 Roo.fly(cell).removeClass("x-grid-cell-selected");
53860 updateHeaderSortState : function(){
53862 // sort state can be single { field: xxx, direction : yyy}
53863 // or { xxx=>ASC , yyy : DESC ..... }
53866 if (!this.ds.multiSort) {
53867 var state = this.ds.getSortState();
53871 mstate[state.field] = state.direction;
53872 // FIXME... - this is not used here.. but might be elsewhere..
53873 this.sortState = state;
53876 mstate = this.ds.sortToggle;
53878 //remove existing sort classes..
53880 var sc = this.sortClasses;
53881 var hds = this.el.select(this.headerSelector).removeClass(sc);
53883 for(var f in mstate) {
53885 var sortColumn = this.cm.findColumnIndex(f);
53887 if(sortColumn != -1){
53888 var sortDir = mstate[f];
53889 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53898 handleHeaderClick : function(g, index,e){
53900 Roo.log("header click");
53903 // touch events on header are handled by context
53904 this.handleHdCtx(g,index,e);
53909 if(this.headersDisabled){
53912 var dm = g.dataSource, cm = g.colModel;
53913 if(!cm.isSortable(index)){
53918 if (dm.multiSort) {
53919 // update the sortOrder
53921 for(var i = 0; i < cm.config.length; i++ ) {
53923 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53924 continue; // dont' bother, it's not in sort list or being set.
53927 so.push(cm.config[i].dataIndex);
53933 dm.sort(cm.getDataIndex(index));
53937 destroy : function(){
53939 this.colMenu.removeAll();
53940 Roo.menu.MenuMgr.unregister(this.colMenu);
53941 this.colMenu.getEl().remove();
53942 delete this.colMenu;
53945 this.hmenu.removeAll();
53946 Roo.menu.MenuMgr.unregister(this.hmenu);
53947 this.hmenu.getEl().remove();
53950 if(this.grid.enableColumnMove){
53951 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53953 for(var dd in dds){
53954 if(!dds[dd].config.isTarget && dds[dd].dragElId){
53955 var elid = dds[dd].dragElId;
53957 Roo.get(elid).remove();
53958 } else if(dds[dd].config.isTarget){
53959 dds[dd].proxyTop.remove();
53960 dds[dd].proxyBottom.remove();
53963 if(Roo.dd.DDM.locationCache[dd]){
53964 delete Roo.dd.DDM.locationCache[dd];
53967 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53970 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
53971 this.bind(null, null);
53972 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
53975 handleLockChange : function(){
53976 this.refresh(true);
53979 onDenyColumnLock : function(){
53983 onDenyColumnHide : function(){
53987 handleHdMenuClick : function(item){
53988 var index = this.hdCtxIndex;
53989 var cm = this.cm, ds = this.ds;
53992 ds.sort(cm.getDataIndex(index), "ASC");
53995 ds.sort(cm.getDataIndex(index), "DESC");
53998 var lc = cm.getLockedCount();
53999 if(cm.getColumnCount(true) <= lc+1){
54000 this.onDenyColumnLock();
54004 cm.setLocked(index, true, true);
54005 cm.moveColumn(index, lc);
54006 this.grid.fireEvent("columnmove", index, lc);
54008 cm.setLocked(index, true);
54012 var lc = cm.getLockedCount();
54013 if((lc-1) != index){
54014 cm.setLocked(index, false, true);
54015 cm.moveColumn(index, lc-1);
54016 this.grid.fireEvent("columnmove", index, lc-1);
54018 cm.setLocked(index, false);
54021 case 'wider': // used to expand cols on touch..
54023 var cw = cm.getColumnWidth(index);
54024 cw += (item.id == 'wider' ? 1 : -1) * 50;
54025 cw = Math.max(0, cw);
54026 cw = Math.min(cw,4000);
54027 cm.setColumnWidth(index, cw);
54031 index = cm.getIndexById(item.id.substr(4));
54033 if(item.checked && cm.getColumnCount(true) <= 1){
54034 this.onDenyColumnHide();
54037 cm.setHidden(index, item.checked);
54043 beforeColMenuShow : function(){
54044 var cm = this.cm, colCount = cm.getColumnCount();
54045 this.colMenu.removeAll();
54046 for(var i = 0; i < colCount; i++){
54047 this.colMenu.add(new Roo.menu.CheckItem({
54048 id: "col-"+cm.getColumnId(i),
54049 text: cm.getColumnHeader(i),
54050 checked: !cm.isHidden(i),
54056 handleHdCtx : function(g, index, e){
54058 var hd = this.getHeaderCell(index);
54059 this.hdCtxIndex = index;
54060 var ms = this.hmenu.items, cm = this.cm;
54061 ms.get("asc").setDisabled(!cm.isSortable(index));
54062 ms.get("desc").setDisabled(!cm.isSortable(index));
54063 if(this.grid.enableColLock !== false){
54064 ms.get("lock").setDisabled(cm.isLocked(index));
54065 ms.get("unlock").setDisabled(!cm.isLocked(index));
54067 this.hmenu.show(hd, "tl-bl");
54070 handleHdOver : function(e){
54071 var hd = this.findHeaderCell(e.getTarget());
54072 if(hd && !this.headersDisabled){
54073 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54074 this.fly(hd).addClass("x-grid-hd-over");
54079 handleHdOut : function(e){
54080 var hd = this.findHeaderCell(e.getTarget());
54082 this.fly(hd).removeClass("x-grid-hd-over");
54086 handleSplitDblClick : function(e, t){
54087 var i = this.getCellIndex(t);
54088 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54089 this.autoSizeColumn(i, true);
54094 render : function(){
54097 var colCount = cm.getColumnCount();
54099 if(this.grid.monitorWindowResize === true){
54100 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54102 var header = this.renderHeaders();
54103 var body = this.templates.body.apply({rows:""});
54104 var html = this.templates.master.apply({
54107 lockedHeader: header[0],
54111 //this.updateColumns();
54113 this.grid.getGridEl().dom.innerHTML = html;
54115 this.initElements();
54117 // a kludge to fix the random scolling effect in webkit
54118 this.el.on("scroll", function() {
54119 this.el.dom.scrollTop=0; // hopefully not recursive..
54122 this.scroller.on("scroll", this.handleScroll, this);
54123 this.lockedBody.on("mousewheel", this.handleWheel, this);
54124 this.mainBody.on("mousewheel", this.handleWheel, this);
54126 this.mainHd.on("mouseover", this.handleHdOver, this);
54127 this.mainHd.on("mouseout", this.handleHdOut, this);
54128 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54129 {delegate: "."+this.splitClass});
54131 this.lockedHd.on("mouseover", this.handleHdOver, this);
54132 this.lockedHd.on("mouseout", this.handleHdOut, this);
54133 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54134 {delegate: "."+this.splitClass});
54136 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54137 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54140 this.updateSplitters();
54142 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54143 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54144 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54147 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54148 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54150 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54151 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54153 if(this.grid.enableColLock !== false){
54154 this.hmenu.add('-',
54155 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54156 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54160 this.hmenu.add('-',
54161 {id:"wider", text: this.columnsWiderText},
54162 {id:"narrow", text: this.columnsNarrowText }
54168 if(this.grid.enableColumnHide !== false){
54170 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54171 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54172 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54174 this.hmenu.add('-',
54175 {id:"columns", text: this.columnsText, menu: this.colMenu}
54178 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54180 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54183 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54184 this.dd = new Roo.grid.GridDragZone(this.grid, {
54185 ddGroup : this.grid.ddGroup || 'GridDD'
54191 for(var i = 0; i < colCount; i++){
54192 if(cm.isHidden(i)){
54193 this.hideColumn(i);
54195 if(cm.config[i].align){
54196 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54197 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54201 this.updateHeaderSortState();
54203 this.beforeInitialResize();
54206 // two part rendering gives faster view to the user
54207 this.renderPhase2.defer(1, this);
54210 renderPhase2 : function(){
54211 // render the rows now
54213 if(this.grid.autoSizeColumns){
54214 this.autoSizeColumns();
54218 beforeInitialResize : function(){
54222 onColumnSplitterMoved : function(i, w){
54223 this.userResized = true;
54224 var cm = this.grid.colModel;
54225 cm.setColumnWidth(i, w, true);
54226 var cid = cm.getColumnId(i);
54227 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54228 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54229 this.updateSplitters();
54231 this.grid.fireEvent("columnresize", i, w);
54234 syncRowHeights : function(startIndex, endIndex){
54235 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54236 startIndex = startIndex || 0;
54237 var mrows = this.getBodyTable().rows;
54238 var lrows = this.getLockedTable().rows;
54239 var len = mrows.length-1;
54240 endIndex = Math.min(endIndex || len, len);
54241 for(var i = startIndex; i <= endIndex; i++){
54242 var m = mrows[i], l = lrows[i];
54243 var h = Math.max(m.offsetHeight, l.offsetHeight);
54244 m.style.height = l.style.height = h + "px";
54249 layout : function(initialRender, is2ndPass){
54251 var auto = g.autoHeight;
54252 var scrollOffset = 16;
54253 var c = g.getGridEl(), cm = this.cm,
54254 expandCol = g.autoExpandColumn,
54256 //c.beginMeasure();
54258 if(!c.dom.offsetWidth){ // display:none?
54260 this.lockedWrap.show();
54261 this.mainWrap.show();
54266 var hasLock = this.cm.isLocked(0);
54268 var tbh = this.headerPanel.getHeight();
54269 var bbh = this.footerPanel.getHeight();
54272 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54273 var newHeight = ch + c.getBorderWidth("tb");
54275 newHeight = Math.min(g.maxHeight, newHeight);
54277 c.setHeight(newHeight);
54281 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54284 var s = this.scroller;
54286 var csize = c.getSize(true);
54288 this.el.setSize(csize.width, csize.height);
54290 this.headerPanel.setWidth(csize.width);
54291 this.footerPanel.setWidth(csize.width);
54293 var hdHeight = this.mainHd.getHeight();
54294 var vw = csize.width;
54295 var vh = csize.height - (tbh + bbh);
54299 var bt = this.getBodyTable();
54300 var ltWidth = hasLock ?
54301 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54303 var scrollHeight = bt.offsetHeight;
54304 var scrollWidth = ltWidth + bt.offsetWidth;
54305 var vscroll = false, hscroll = false;
54307 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54309 var lw = this.lockedWrap, mw = this.mainWrap;
54310 var lb = this.lockedBody, mb = this.mainBody;
54312 setTimeout(function(){
54313 var t = s.dom.offsetTop;
54314 var w = s.dom.clientWidth,
54315 h = s.dom.clientHeight;
54318 lw.setSize(ltWidth, h);
54320 mw.setLeftTop(ltWidth, t);
54321 mw.setSize(w-ltWidth, h);
54323 lb.setHeight(h-hdHeight);
54324 mb.setHeight(h-hdHeight);
54326 if(is2ndPass !== true && !gv.userResized && expandCol){
54327 // high speed resize without full column calculation
54329 var ci = cm.getIndexById(expandCol);
54331 ci = cm.findColumnIndex(expandCol);
54333 ci = Math.max(0, ci); // make sure it's got at least the first col.
54334 var expandId = cm.getColumnId(ci);
54335 var tw = cm.getTotalWidth(false);
54336 var currentWidth = cm.getColumnWidth(ci);
54337 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54338 if(currentWidth != cw){
54339 cm.setColumnWidth(ci, cw, true);
54340 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54341 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54342 gv.updateSplitters();
54343 gv.layout(false, true);
54355 onWindowResize : function(){
54356 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54362 appendFooter : function(parentEl){
54366 sortAscText : "Sort Ascending",
54367 sortDescText : "Sort Descending",
54368 lockText : "Lock Column",
54369 unlockText : "Unlock Column",
54370 columnsText : "Columns",
54372 columnsWiderText : "Wider",
54373 columnsNarrowText : "Thinner"
54377 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54378 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54379 this.proxy.el.addClass('x-grid3-col-dd');
54382 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54383 handleMouseDown : function(e){
54387 callHandleMouseDown : function(e){
54388 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54393 * Ext JS Library 1.1.1
54394 * Copyright(c) 2006-2007, Ext JS, LLC.
54396 * Originally Released Under LGPL - original licence link has changed is not relivant.
54399 * <script type="text/javascript">
54403 // This is a support class used internally by the Grid components
54404 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54406 this.view = grid.getView();
54407 this.proxy = this.view.resizeProxy;
54408 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54409 "gridSplitters" + this.grid.getGridEl().id, {
54410 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54412 this.setHandleElId(Roo.id(hd));
54413 this.setOuterHandleElId(Roo.id(hd2));
54414 this.scroll = false;
54416 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54417 fly: Roo.Element.fly,
54419 b4StartDrag : function(x, y){
54420 this.view.headersDisabled = true;
54421 this.proxy.setHeight(this.view.mainWrap.getHeight());
54422 var w = this.cm.getColumnWidth(this.cellIndex);
54423 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54424 this.resetConstraints();
54425 this.setXConstraint(minw, 1000);
54426 this.setYConstraint(0, 0);
54427 this.minX = x - minw;
54428 this.maxX = x + 1000;
54430 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54434 handleMouseDown : function(e){
54435 ev = Roo.EventObject.setEvent(e);
54436 var t = this.fly(ev.getTarget());
54437 if(t.hasClass("x-grid-split")){
54438 this.cellIndex = this.view.getCellIndex(t.dom);
54439 this.split = t.dom;
54440 this.cm = this.grid.colModel;
54441 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54442 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54447 endDrag : function(e){
54448 this.view.headersDisabled = false;
54449 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54450 var diff = endX - this.startPos;
54451 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54454 autoOffset : function(){
54455 this.setDelta(0,0);
54459 * Ext JS Library 1.1.1
54460 * Copyright(c) 2006-2007, Ext JS, LLC.
54462 * Originally Released Under LGPL - original licence link has changed is not relivant.
54465 * <script type="text/javascript">
54469 // This is a support class used internally by the Grid components
54470 Roo.grid.GridDragZone = function(grid, config){
54471 this.view = grid.getView();
54472 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54473 if(this.view.lockedBody){
54474 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54475 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54477 this.scroll = false;
54479 this.ddel = document.createElement('div');
54480 this.ddel.className = 'x-grid-dd-wrap';
54483 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54484 ddGroup : "GridDD",
54486 getDragData : function(e){
54487 var t = Roo.lib.Event.getTarget(e);
54488 var rowIndex = this.view.findRowIndex(t);
54489 var sm = this.grid.selModel;
54491 //Roo.log(rowIndex);
54493 if (sm.getSelectedCell) {
54494 // cell selection..
54495 if (!sm.getSelectedCell()) {
54498 if (rowIndex != sm.getSelectedCell()[0]) {
54504 if(rowIndex !== false){
54509 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54511 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54514 if (e.hasModifier()){
54515 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54518 Roo.log("getDragData");
54523 rowIndex: rowIndex,
54524 selections:sm.getSelections ? sm.getSelections() : (
54525 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54532 onInitDrag : function(e){
54533 var data = this.dragData;
54534 this.ddel.innerHTML = this.grid.getDragDropText();
54535 this.proxy.update(this.ddel);
54536 // fire start drag?
54539 afterRepair : function(){
54540 this.dragging = false;
54543 getRepairXY : function(e, data){
54547 onEndDrag : function(data, e){
54551 onValidDrop : function(dd, e, id){
54556 beforeInvalidDrop : function(e, id){
54561 * Ext JS Library 1.1.1
54562 * Copyright(c) 2006-2007, Ext JS, LLC.
54564 * Originally Released Under LGPL - original licence link has changed is not relivant.
54567 * <script type="text/javascript">
54572 * @class Roo.grid.ColumnModel
54573 * @extends Roo.util.Observable
54574 * This is the default implementation of a ColumnModel used by the Grid. It defines
54575 * the columns in the grid.
54578 var colModel = new Roo.grid.ColumnModel([
54579 {header: "Ticker", width: 60, sortable: true, locked: true},
54580 {header: "Company Name", width: 150, sortable: true},
54581 {header: "Market Cap.", width: 100, sortable: true},
54582 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54583 {header: "Employees", width: 100, sortable: true, resizable: false}
54588 * The config options listed for this class are options which may appear in each
54589 * individual column definition.
54590 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54592 * @param {Object} config An Array of column config objects. See this class's
54593 * config objects for details.
54595 Roo.grid.ColumnModel = function(config){
54597 * The config passed into the constructor
54599 this.config = config;
54602 // if no id, create one
54603 // if the column does not have a dataIndex mapping,
54604 // map it to the order it is in the config
54605 for(var i = 0, len = config.length; i < len; i++){
54607 if(typeof c.dataIndex == "undefined"){
54610 if(typeof c.renderer == "string"){
54611 c.renderer = Roo.util.Format[c.renderer];
54613 if(typeof c.id == "undefined"){
54616 if(c.editor && c.editor.xtype){
54617 c.editor = Roo.factory(c.editor, Roo.grid);
54619 if(c.editor && c.editor.isFormField){
54620 c.editor = new Roo.grid.GridEditor(c.editor);
54622 this.lookup[c.id] = c;
54626 * The width of columns which have no width specified (defaults to 100)
54629 this.defaultWidth = 100;
54632 * Default sortable of columns which have no sortable specified (defaults to false)
54635 this.defaultSortable = false;
54639 * @event widthchange
54640 * Fires when the width of a column changes.
54641 * @param {ColumnModel} this
54642 * @param {Number} columnIndex The column index
54643 * @param {Number} newWidth The new width
54645 "widthchange": true,
54647 * @event headerchange
54648 * Fires when the text of a header changes.
54649 * @param {ColumnModel} this
54650 * @param {Number} columnIndex The column index
54651 * @param {Number} newText The new header text
54653 "headerchange": true,
54655 * @event hiddenchange
54656 * Fires when a column is hidden or "unhidden".
54657 * @param {ColumnModel} this
54658 * @param {Number} columnIndex The column index
54659 * @param {Boolean} hidden true if hidden, false otherwise
54661 "hiddenchange": true,
54663 * @event columnmoved
54664 * Fires when a column is moved.
54665 * @param {ColumnModel} this
54666 * @param {Number} oldIndex
54667 * @param {Number} newIndex
54669 "columnmoved" : true,
54671 * @event columlockchange
54672 * Fires when a column's locked state is changed
54673 * @param {ColumnModel} this
54674 * @param {Number} colIndex
54675 * @param {Boolean} locked true if locked
54677 "columnlockchange" : true
54679 Roo.grid.ColumnModel.superclass.constructor.call(this);
54681 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54683 * @cfg {String} header The header text to display in the Grid view.
54686 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54687 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54688 * specified, the column's index is used as an index into the Record's data Array.
54691 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54692 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54695 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54696 * Defaults to the value of the {@link #defaultSortable} property.
54697 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54700 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54703 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54706 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54709 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54712 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54713 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54714 * default renderer uses the raw data value.
54717 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54720 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54724 * Returns the id of the column at the specified index.
54725 * @param {Number} index The column index
54726 * @return {String} the id
54728 getColumnId : function(index){
54729 return this.config[index].id;
54733 * Returns the column for a specified id.
54734 * @param {String} id The column id
54735 * @return {Object} the column
54737 getColumnById : function(id){
54738 return this.lookup[id];
54743 * Returns the column for a specified dataIndex.
54744 * @param {String} dataIndex The column dataIndex
54745 * @return {Object|Boolean} the column or false if not found
54747 getColumnByDataIndex: function(dataIndex){
54748 var index = this.findColumnIndex(dataIndex);
54749 return index > -1 ? this.config[index] : false;
54753 * Returns the index for a specified column id.
54754 * @param {String} id The column id
54755 * @return {Number} the index, or -1 if not found
54757 getIndexById : function(id){
54758 for(var i = 0, len = this.config.length; i < len; i++){
54759 if(this.config[i].id == id){
54767 * Returns the index for a specified column dataIndex.
54768 * @param {String} dataIndex The column dataIndex
54769 * @return {Number} the index, or -1 if not found
54772 findColumnIndex : function(dataIndex){
54773 for(var i = 0, len = this.config.length; i < len; i++){
54774 if(this.config[i].dataIndex == dataIndex){
54782 moveColumn : function(oldIndex, newIndex){
54783 var c = this.config[oldIndex];
54784 this.config.splice(oldIndex, 1);
54785 this.config.splice(newIndex, 0, c);
54786 this.dataMap = null;
54787 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54790 isLocked : function(colIndex){
54791 return this.config[colIndex].locked === true;
54794 setLocked : function(colIndex, value, suppressEvent){
54795 if(this.isLocked(colIndex) == value){
54798 this.config[colIndex].locked = value;
54799 if(!suppressEvent){
54800 this.fireEvent("columnlockchange", this, colIndex, value);
54804 getTotalLockedWidth : function(){
54805 var totalWidth = 0;
54806 for(var i = 0; i < this.config.length; i++){
54807 if(this.isLocked(i) && !this.isHidden(i)){
54808 this.totalWidth += this.getColumnWidth(i);
54814 getLockedCount : function(){
54815 for(var i = 0, len = this.config.length; i < len; i++){
54816 if(!this.isLocked(i)){
54823 * Returns the number of columns.
54826 getColumnCount : function(visibleOnly){
54827 if(visibleOnly === true){
54829 for(var i = 0, len = this.config.length; i < len; i++){
54830 if(!this.isHidden(i)){
54836 return this.config.length;
54840 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54841 * @param {Function} fn
54842 * @param {Object} scope (optional)
54843 * @return {Array} result
54845 getColumnsBy : function(fn, scope){
54847 for(var i = 0, len = this.config.length; i < len; i++){
54848 var c = this.config[i];
54849 if(fn.call(scope||this, c, i) === true){
54857 * Returns true if the specified column is sortable.
54858 * @param {Number} col The column index
54859 * @return {Boolean}
54861 isSortable : function(col){
54862 if(typeof this.config[col].sortable == "undefined"){
54863 return this.defaultSortable;
54865 return this.config[col].sortable;
54869 * Returns the rendering (formatting) function defined for the column.
54870 * @param {Number} col The column index.
54871 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54873 getRenderer : function(col){
54874 if(!this.config[col].renderer){
54875 return Roo.grid.ColumnModel.defaultRenderer;
54877 return this.config[col].renderer;
54881 * Sets the rendering (formatting) function for a column.
54882 * @param {Number} col The column index
54883 * @param {Function} fn The function to use to process the cell's raw data
54884 * to return HTML markup for the grid view. The render function is called with
54885 * the following parameters:<ul>
54886 * <li>Data value.</li>
54887 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54888 * <li>css A CSS style string to apply to the table cell.</li>
54889 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54890 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54891 * <li>Row index</li>
54892 * <li>Column index</li>
54893 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54895 setRenderer : function(col, fn){
54896 this.config[col].renderer = fn;
54900 * Returns the width for the specified column.
54901 * @param {Number} col The column index
54904 getColumnWidth : function(col){
54905 return this.config[col].width * 1 || this.defaultWidth;
54909 * Sets the width for a column.
54910 * @param {Number} col The column index
54911 * @param {Number} width The new width
54913 setColumnWidth : function(col, width, suppressEvent){
54914 this.config[col].width = width;
54915 this.totalWidth = null;
54916 if(!suppressEvent){
54917 this.fireEvent("widthchange", this, col, width);
54922 * Returns the total width of all columns.
54923 * @param {Boolean} includeHidden True to include hidden column widths
54926 getTotalWidth : function(includeHidden){
54927 if(!this.totalWidth){
54928 this.totalWidth = 0;
54929 for(var i = 0, len = this.config.length; i < len; i++){
54930 if(includeHidden || !this.isHidden(i)){
54931 this.totalWidth += this.getColumnWidth(i);
54935 return this.totalWidth;
54939 * Returns the header for the specified column.
54940 * @param {Number} col The column index
54943 getColumnHeader : function(col){
54944 return this.config[col].header;
54948 * Sets the header for a column.
54949 * @param {Number} col The column index
54950 * @param {String} header The new header
54952 setColumnHeader : function(col, header){
54953 this.config[col].header = header;
54954 this.fireEvent("headerchange", this, col, header);
54958 * Returns the tooltip for the specified column.
54959 * @param {Number} col The column index
54962 getColumnTooltip : function(col){
54963 return this.config[col].tooltip;
54966 * Sets the tooltip for a column.
54967 * @param {Number} col The column index
54968 * @param {String} tooltip The new tooltip
54970 setColumnTooltip : function(col, tooltip){
54971 this.config[col].tooltip = tooltip;
54975 * Returns the dataIndex for the specified column.
54976 * @param {Number} col The column index
54979 getDataIndex : function(col){
54980 return this.config[col].dataIndex;
54984 * Sets the dataIndex for a column.
54985 * @param {Number} col The column index
54986 * @param {Number} dataIndex The new dataIndex
54988 setDataIndex : function(col, dataIndex){
54989 this.config[col].dataIndex = dataIndex;
54995 * Returns true if the cell is editable.
54996 * @param {Number} colIndex The column index
54997 * @param {Number} rowIndex The row index
54998 * @return {Boolean}
55000 isCellEditable : function(colIndex, rowIndex){
55001 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55005 * Returns the editor defined for the cell/column.
55006 * return false or null to disable editing.
55007 * @param {Number} colIndex The column index
55008 * @param {Number} rowIndex The row index
55011 getCellEditor : function(colIndex, rowIndex){
55012 return this.config[colIndex].editor;
55016 * Sets if a column is editable.
55017 * @param {Number} col The column index
55018 * @param {Boolean} editable True if the column is editable
55020 setEditable : function(col, editable){
55021 this.config[col].editable = editable;
55026 * Returns true if the column is hidden.
55027 * @param {Number} colIndex The column index
55028 * @return {Boolean}
55030 isHidden : function(colIndex){
55031 return this.config[colIndex].hidden;
55036 * Returns true if the column width cannot be changed
55038 isFixed : function(colIndex){
55039 return this.config[colIndex].fixed;
55043 * Returns true if the column can be resized
55044 * @return {Boolean}
55046 isResizable : function(colIndex){
55047 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55050 * Sets if a column is hidden.
55051 * @param {Number} colIndex The column index
55052 * @param {Boolean} hidden True if the column is hidden
55054 setHidden : function(colIndex, hidden){
55055 this.config[colIndex].hidden = hidden;
55056 this.totalWidth = null;
55057 this.fireEvent("hiddenchange", this, colIndex, hidden);
55061 * Sets the editor for a column.
55062 * @param {Number} col The column index
55063 * @param {Object} editor The editor object
55065 setEditor : function(col, editor){
55066 this.config[col].editor = editor;
55070 Roo.grid.ColumnModel.defaultRenderer = function(value){
55071 if(typeof value == "string" && value.length < 1){
55077 // Alias for backwards compatibility
55078 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55081 * Ext JS Library 1.1.1
55082 * Copyright(c) 2006-2007, Ext JS, LLC.
55084 * Originally Released Under LGPL - original licence link has changed is not relivant.
55087 * <script type="text/javascript">
55091 * @class Roo.grid.AbstractSelectionModel
55092 * @extends Roo.util.Observable
55093 * Abstract base class for grid SelectionModels. It provides the interface that should be
55094 * implemented by descendant classes. This class should not be directly instantiated.
55097 Roo.grid.AbstractSelectionModel = function(){
55098 this.locked = false;
55099 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55102 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55103 /** @ignore Called by the grid automatically. Do not call directly. */
55104 init : function(grid){
55110 * Locks the selections.
55113 this.locked = true;
55117 * Unlocks the selections.
55119 unlock : function(){
55120 this.locked = false;
55124 * Returns true if the selections are locked.
55125 * @return {Boolean}
55127 isLocked : function(){
55128 return this.locked;
55132 * Ext JS Library 1.1.1
55133 * Copyright(c) 2006-2007, Ext JS, LLC.
55135 * Originally Released Under LGPL - original licence link has changed is not relivant.
55138 * <script type="text/javascript">
55141 * @extends Roo.grid.AbstractSelectionModel
55142 * @class Roo.grid.RowSelectionModel
55143 * The default SelectionModel used by {@link Roo.grid.Grid}.
55144 * It supports multiple selections and keyboard selection/navigation.
55146 * @param {Object} config
55148 Roo.grid.RowSelectionModel = function(config){
55149 Roo.apply(this, config);
55150 this.selections = new Roo.util.MixedCollection(false, function(o){
55155 this.lastActive = false;
55159 * @event selectionchange
55160 * Fires when the selection changes
55161 * @param {SelectionModel} this
55163 "selectionchange" : true,
55165 * @event afterselectionchange
55166 * Fires after the selection changes (eg. by key press or clicking)
55167 * @param {SelectionModel} this
55169 "afterselectionchange" : true,
55171 * @event beforerowselect
55172 * Fires when a row is selected being selected, return false to cancel.
55173 * @param {SelectionModel} this
55174 * @param {Number} rowIndex The selected index
55175 * @param {Boolean} keepExisting False if other selections will be cleared
55177 "beforerowselect" : true,
55180 * Fires when a row is selected.
55181 * @param {SelectionModel} this
55182 * @param {Number} rowIndex The selected index
55183 * @param {Roo.data.Record} r The record
55185 "rowselect" : true,
55187 * @event rowdeselect
55188 * Fires when a row is deselected.
55189 * @param {SelectionModel} this
55190 * @param {Number} rowIndex The selected index
55192 "rowdeselect" : true
55194 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55195 this.locked = false;
55198 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55200 * @cfg {Boolean} singleSelect
55201 * True to allow selection of only one row at a time (defaults to false)
55203 singleSelect : false,
55206 initEvents : function(){
55208 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55209 this.grid.on("mousedown", this.handleMouseDown, this);
55210 }else{ // allow click to work like normal
55211 this.grid.on("rowclick", this.handleDragableRowClick, this);
55214 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55215 "up" : function(e){
55217 this.selectPrevious(e.shiftKey);
55218 }else if(this.last !== false && this.lastActive !== false){
55219 var last = this.last;
55220 this.selectRange(this.last, this.lastActive-1);
55221 this.grid.getView().focusRow(this.lastActive);
55222 if(last !== false){
55226 this.selectFirstRow();
55228 this.fireEvent("afterselectionchange", this);
55230 "down" : function(e){
55232 this.selectNext(e.shiftKey);
55233 }else if(this.last !== false && this.lastActive !== false){
55234 var last = this.last;
55235 this.selectRange(this.last, this.lastActive+1);
55236 this.grid.getView().focusRow(this.lastActive);
55237 if(last !== false){
55241 this.selectFirstRow();
55243 this.fireEvent("afterselectionchange", this);
55248 var view = this.grid.view;
55249 view.on("refresh", this.onRefresh, this);
55250 view.on("rowupdated", this.onRowUpdated, this);
55251 view.on("rowremoved", this.onRemove, this);
55255 onRefresh : function(){
55256 var ds = this.grid.dataSource, i, v = this.grid.view;
55257 var s = this.selections;
55258 s.each(function(r){
55259 if((i = ds.indexOfId(r.id)) != -1){
55268 onRemove : function(v, index, r){
55269 this.selections.remove(r);
55273 onRowUpdated : function(v, index, r){
55274 if(this.isSelected(r)){
55275 v.onRowSelect(index);
55281 * @param {Array} records The records to select
55282 * @param {Boolean} keepExisting (optional) True to keep existing selections
55284 selectRecords : function(records, keepExisting){
55286 this.clearSelections();
55288 var ds = this.grid.dataSource;
55289 for(var i = 0, len = records.length; i < len; i++){
55290 this.selectRow(ds.indexOf(records[i]), true);
55295 * Gets the number of selected rows.
55298 getCount : function(){
55299 return this.selections.length;
55303 * Selects the first row in the grid.
55305 selectFirstRow : function(){
55310 * Select the last row.
55311 * @param {Boolean} keepExisting (optional) True to keep existing selections
55313 selectLastRow : function(keepExisting){
55314 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55318 * Selects the row immediately following the last selected row.
55319 * @param {Boolean} keepExisting (optional) True to keep existing selections
55321 selectNext : function(keepExisting){
55322 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55323 this.selectRow(this.last+1, keepExisting);
55324 this.grid.getView().focusRow(this.last);
55329 * Selects the row that precedes the last selected row.
55330 * @param {Boolean} keepExisting (optional) True to keep existing selections
55332 selectPrevious : function(keepExisting){
55334 this.selectRow(this.last-1, keepExisting);
55335 this.grid.getView().focusRow(this.last);
55340 * Returns the selected records
55341 * @return {Array} Array of selected records
55343 getSelections : function(){
55344 return [].concat(this.selections.items);
55348 * Returns the first selected record.
55351 getSelected : function(){
55352 return this.selections.itemAt(0);
55357 * Clears all selections.
55359 clearSelections : function(fast){
55360 if(this.locked) return;
55362 var ds = this.grid.dataSource;
55363 var s = this.selections;
55364 s.each(function(r){
55365 this.deselectRow(ds.indexOfId(r.id));
55369 this.selections.clear();
55376 * Selects all rows.
55378 selectAll : function(){
55379 if(this.locked) return;
55380 this.selections.clear();
55381 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55382 this.selectRow(i, true);
55387 * Returns True if there is a selection.
55388 * @return {Boolean}
55390 hasSelection : function(){
55391 return this.selections.length > 0;
55395 * Returns True if the specified row is selected.
55396 * @param {Number/Record} record The record or index of the record to check
55397 * @return {Boolean}
55399 isSelected : function(index){
55400 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55401 return (r && this.selections.key(r.id) ? true : false);
55405 * Returns True if the specified record id is selected.
55406 * @param {String} id The id of record to check
55407 * @return {Boolean}
55409 isIdSelected : function(id){
55410 return (this.selections.key(id) ? true : false);
55414 handleMouseDown : function(e, t){
55415 var view = this.grid.getView(), rowIndex;
55416 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55419 if(e.shiftKey && this.last !== false){
55420 var last = this.last;
55421 this.selectRange(last, rowIndex, e.ctrlKey);
55422 this.last = last; // reset the last
55423 view.focusRow(rowIndex);
55425 var isSelected = this.isSelected(rowIndex);
55426 if(e.button !== 0 && isSelected){
55427 view.focusRow(rowIndex);
55428 }else if(e.ctrlKey && isSelected){
55429 this.deselectRow(rowIndex);
55430 }else if(!isSelected){
55431 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55432 view.focusRow(rowIndex);
55435 this.fireEvent("afterselectionchange", this);
55438 handleDragableRowClick : function(grid, rowIndex, e)
55440 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55441 this.selectRow(rowIndex, false);
55442 grid.view.focusRow(rowIndex);
55443 this.fireEvent("afterselectionchange", this);
55448 * Selects multiple rows.
55449 * @param {Array} rows Array of the indexes of the row to select
55450 * @param {Boolean} keepExisting (optional) True to keep existing selections
55452 selectRows : function(rows, keepExisting){
55454 this.clearSelections();
55456 for(var i = 0, len = rows.length; i < len; i++){
55457 this.selectRow(rows[i], true);
55462 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55463 * @param {Number} startRow The index of the first row in the range
55464 * @param {Number} endRow The index of the last row in the range
55465 * @param {Boolean} keepExisting (optional) True to retain existing selections
55467 selectRange : function(startRow, endRow, keepExisting){
55468 if(this.locked) return;
55470 this.clearSelections();
55472 if(startRow <= endRow){
55473 for(var i = startRow; i <= endRow; i++){
55474 this.selectRow(i, true);
55477 for(var i = startRow; i >= endRow; i--){
55478 this.selectRow(i, true);
55484 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55485 * @param {Number} startRow The index of the first row in the range
55486 * @param {Number} endRow The index of the last row in the range
55488 deselectRange : function(startRow, endRow, preventViewNotify){
55489 if(this.locked) return;
55490 for(var i = startRow; i <= endRow; i++){
55491 this.deselectRow(i, preventViewNotify);
55497 * @param {Number} row The index of the row to select
55498 * @param {Boolean} keepExisting (optional) True to keep existing selections
55500 selectRow : function(index, keepExisting, preventViewNotify){
55501 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55502 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55503 if(!keepExisting || this.singleSelect){
55504 this.clearSelections();
55506 var r = this.grid.dataSource.getAt(index);
55507 this.selections.add(r);
55508 this.last = this.lastActive = index;
55509 if(!preventViewNotify){
55510 this.grid.getView().onRowSelect(index);
55512 this.fireEvent("rowselect", this, index, r);
55513 this.fireEvent("selectionchange", this);
55519 * @param {Number} row The index of the row to deselect
55521 deselectRow : function(index, preventViewNotify){
55522 if(this.locked) return;
55523 if(this.last == index){
55526 if(this.lastActive == index){
55527 this.lastActive = false;
55529 var r = this.grid.dataSource.getAt(index);
55530 this.selections.remove(r);
55531 if(!preventViewNotify){
55532 this.grid.getView().onRowDeselect(index);
55534 this.fireEvent("rowdeselect", this, index);
55535 this.fireEvent("selectionchange", this);
55539 restoreLast : function(){
55541 this.last = this._last;
55546 acceptsNav : function(row, col, cm){
55547 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55551 onEditorKey : function(field, e){
55552 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55557 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55559 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55561 }else if(k == e.ENTER && !e.ctrlKey){
55565 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55567 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55569 }else if(k == e.ESC){
55573 g.startEditing(newCell[0], newCell[1]);
55578 * Ext JS Library 1.1.1
55579 * Copyright(c) 2006-2007, Ext JS, LLC.
55581 * Originally Released Under LGPL - original licence link has changed is not relivant.
55584 * <script type="text/javascript">
55587 * @class Roo.grid.CellSelectionModel
55588 * @extends Roo.grid.AbstractSelectionModel
55589 * This class provides the basic implementation for cell selection in a grid.
55591 * @param {Object} config The object containing the configuration of this model.
55592 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55594 Roo.grid.CellSelectionModel = function(config){
55595 Roo.apply(this, config);
55597 this.selection = null;
55601 * @event beforerowselect
55602 * Fires before a cell is selected.
55603 * @param {SelectionModel} this
55604 * @param {Number} rowIndex The selected row index
55605 * @param {Number} colIndex The selected cell index
55607 "beforecellselect" : true,
55609 * @event cellselect
55610 * Fires when a cell is selected.
55611 * @param {SelectionModel} this
55612 * @param {Number} rowIndex The selected row index
55613 * @param {Number} colIndex The selected cell index
55615 "cellselect" : true,
55617 * @event selectionchange
55618 * Fires when the active selection changes.
55619 * @param {SelectionModel} this
55620 * @param {Object} selection null for no selection or an object (o) with two properties
55622 <li>o.record: the record object for the row the selection is in</li>
55623 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55626 "selectionchange" : true,
55629 * Fires when the tab (or enter) was pressed on the last editable cell
55630 * You can use this to trigger add new row.
55631 * @param {SelectionModel} this
55635 * @event beforeeditnext
55636 * Fires before the next editable sell is made active
55637 * You can use this to skip to another cell or fire the tabend
55638 * if you set cell to false
55639 * @param {Object} eventdata object : { cell : [ row, col ] }
55641 "beforeeditnext" : true
55643 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55646 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55648 enter_is_tab: false,
55651 initEvents : function(){
55652 this.grid.on("mousedown", this.handleMouseDown, this);
55653 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55654 var view = this.grid.view;
55655 view.on("refresh", this.onViewChange, this);
55656 view.on("rowupdated", this.onRowUpdated, this);
55657 view.on("beforerowremoved", this.clearSelections, this);
55658 view.on("beforerowsinserted", this.clearSelections, this);
55659 if(this.grid.isEditor){
55660 this.grid.on("beforeedit", this.beforeEdit, this);
55665 beforeEdit : function(e){
55666 this.select(e.row, e.column, false, true, e.record);
55670 onRowUpdated : function(v, index, r){
55671 if(this.selection && this.selection.record == r){
55672 v.onCellSelect(index, this.selection.cell[1]);
55677 onViewChange : function(){
55678 this.clearSelections(true);
55682 * Returns the currently selected cell,.
55683 * @return {Array} The selected cell (row, column) or null if none selected.
55685 getSelectedCell : function(){
55686 return this.selection ? this.selection.cell : null;
55690 * Clears all selections.
55691 * @param {Boolean} true to prevent the gridview from being notified about the change.
55693 clearSelections : function(preventNotify){
55694 var s = this.selection;
55696 if(preventNotify !== true){
55697 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55699 this.selection = null;
55700 this.fireEvent("selectionchange", this, null);
55705 * Returns true if there is a selection.
55706 * @return {Boolean}
55708 hasSelection : function(){
55709 return this.selection ? true : false;
55713 handleMouseDown : function(e, t){
55714 var v = this.grid.getView();
55715 if(this.isLocked()){
55718 var row = v.findRowIndex(t);
55719 var cell = v.findCellIndex(t);
55720 if(row !== false && cell !== false){
55721 this.select(row, cell);
55727 * @param {Number} rowIndex
55728 * @param {Number} collIndex
55730 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55731 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55732 this.clearSelections();
55733 r = r || this.grid.dataSource.getAt(rowIndex);
55736 cell : [rowIndex, colIndex]
55738 if(!preventViewNotify){
55739 var v = this.grid.getView();
55740 v.onCellSelect(rowIndex, colIndex);
55741 if(preventFocus !== true){
55742 v.focusCell(rowIndex, colIndex);
55745 this.fireEvent("cellselect", this, rowIndex, colIndex);
55746 this.fireEvent("selectionchange", this, this.selection);
55751 isSelectable : function(rowIndex, colIndex, cm){
55752 return !cm.isHidden(colIndex);
55756 handleKeyDown : function(e){
55757 //Roo.log('Cell Sel Model handleKeyDown');
55758 if(!e.isNavKeyPress()){
55761 var g = this.grid, s = this.selection;
55764 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55766 this.select(cell[0], cell[1]);
55771 var walk = function(row, col, step){
55772 return g.walkCells(row, col, step, sm.isSelectable, sm);
55774 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55781 // handled by onEditorKey
55782 if (g.isEditor && g.editing) {
55786 newCell = walk(r, c-1, -1);
55788 newCell = walk(r, c+1, 1);
55793 newCell = walk(r+1, c, 1);
55797 newCell = walk(r-1, c, -1);
55801 newCell = walk(r, c+1, 1);
55805 newCell = walk(r, c-1, -1);
55810 if(g.isEditor && !g.editing){
55811 g.startEditing(r, c);
55820 this.select(newCell[0], newCell[1]);
55826 acceptsNav : function(row, col, cm){
55827 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55831 * @param {Number} field (not used) - as it's normally used as a listener
55832 * @param {Number} e - event - fake it by using
55834 * var e = Roo.EventObjectImpl.prototype;
55835 * e.keyCode = e.TAB
55839 onEditorKey : function(field, e){
55841 var k = e.getKey(),
55844 ed = g.activeEditor,
55846 ///Roo.log('onEditorKey' + k);
55849 if (this.enter_is_tab && k == e.ENTER) {
55855 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55857 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55863 } else if(k == e.ENTER && !e.ctrlKey){
55866 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55868 } else if(k == e.ESC){
55873 var ecall = { cell : newCell, forward : forward };
55874 this.fireEvent('beforeeditnext', ecall );
55875 newCell = ecall.cell;
55876 forward = ecall.forward;
55880 //Roo.log('next cell after edit');
55881 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55882 } else if (forward) {
55883 // tabbed past last
55884 this.fireEvent.defer(100, this, ['tabend',this]);
55889 * Ext JS Library 1.1.1
55890 * Copyright(c) 2006-2007, Ext JS, LLC.
55892 * Originally Released Under LGPL - original licence link has changed is not relivant.
55895 * <script type="text/javascript">
55899 * @class Roo.grid.EditorGrid
55900 * @extends Roo.grid.Grid
55901 * Class for creating and editable grid.
55902 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55903 * The container MUST have some type of size defined for the grid to fill. The container will be
55904 * automatically set to position relative if it isn't already.
55905 * @param {Object} dataSource The data model to bind to
55906 * @param {Object} colModel The column model with info about this grid's columns
55908 Roo.grid.EditorGrid = function(container, config){
55909 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55910 this.getGridEl().addClass("xedit-grid");
55912 if(!this.selModel){
55913 this.selModel = new Roo.grid.CellSelectionModel();
55916 this.activeEditor = null;
55920 * @event beforeedit
55921 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55922 * <ul style="padding:5px;padding-left:16px;">
55923 * <li>grid - This grid</li>
55924 * <li>record - The record being edited</li>
55925 * <li>field - The field name being edited</li>
55926 * <li>value - The value for the field being edited.</li>
55927 * <li>row - The grid row index</li>
55928 * <li>column - The grid column index</li>
55929 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55931 * @param {Object} e An edit event (see above for description)
55933 "beforeedit" : true,
55936 * Fires after a cell is edited. <br />
55937 * <ul style="padding:5px;padding-left:16px;">
55938 * <li>grid - This grid</li>
55939 * <li>record - The record being edited</li>
55940 * <li>field - The field name being edited</li>
55941 * <li>value - The value being set</li>
55942 * <li>originalValue - The original value for the field, before the edit.</li>
55943 * <li>row - The grid row index</li>
55944 * <li>column - The grid column index</li>
55946 * @param {Object} e An edit event (see above for description)
55948 "afteredit" : true,
55950 * @event validateedit
55951 * Fires after a cell is edited, but before the value is set in the record.
55952 * You can use this to modify the value being set in the field, Return false
55953 * to cancel the change. The edit event object has the following properties <br />
55954 * <ul style="padding:5px;padding-left:16px;">
55955 * <li>editor - This editor</li>
55956 * <li>grid - This grid</li>
55957 * <li>record - The record being edited</li>
55958 * <li>field - The field name being edited</li>
55959 * <li>value - The value being set</li>
55960 * <li>originalValue - The original value for the field, before the edit.</li>
55961 * <li>row - The grid row index</li>
55962 * <li>column - The grid column index</li>
55963 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55965 * @param {Object} e An edit event (see above for description)
55967 "validateedit" : true
55969 this.on("bodyscroll", this.stopEditing, this);
55970 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
55973 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
55975 * @cfg {Number} clicksToEdit
55976 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
55983 trackMouseOver: false, // causes very odd FF errors
55985 onCellDblClick : function(g, row, col){
55986 this.startEditing(row, col);
55989 onEditComplete : function(ed, value, startValue){
55990 this.editing = false;
55991 this.activeEditor = null;
55992 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
55994 var field = this.colModel.getDataIndex(ed.col);
55999 originalValue: startValue,
56006 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56009 if(String(value) !== String(startValue)){
56011 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56012 r.set(field, e.value);
56013 // if we are dealing with a combo box..
56014 // then we also set the 'name' colum to be the displayField
56015 if (ed.field.displayField && ed.field.name) {
56016 r.set(ed.field.name, ed.field.el.dom.value);
56019 delete e.cancel; //?? why!!!
56020 this.fireEvent("afteredit", e);
56023 this.fireEvent("afteredit", e); // always fire it!
56025 this.view.focusCell(ed.row, ed.col);
56029 * Starts editing the specified for the specified row/column
56030 * @param {Number} rowIndex
56031 * @param {Number} colIndex
56033 startEditing : function(row, col){
56034 this.stopEditing();
56035 if(this.colModel.isCellEditable(col, row)){
56036 this.view.ensureVisible(row, col, true);
56038 var r = this.dataSource.getAt(row);
56039 var field = this.colModel.getDataIndex(col);
56040 var cell = Roo.get(this.view.getCell(row,col));
56045 value: r.data[field],
56050 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56051 this.editing = true;
56052 var ed = this.colModel.getCellEditor(col, row);
56058 ed.render(ed.parentEl || document.body);
56064 (function(){ // complex but required for focus issues in safari, ie and opera
56068 ed.on("complete", this.onEditComplete, this, {single: true});
56069 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56070 this.activeEditor = ed;
56071 var v = r.data[field];
56072 ed.startEdit(this.view.getCell(row, col), v);
56073 // combo's with 'displayField and name set
56074 if (ed.field.displayField && ed.field.name) {
56075 ed.field.el.dom.value = r.data[ed.field.name];
56079 }).defer(50, this);
56085 * Stops any active editing
56087 stopEditing : function(){
56088 if(this.activeEditor){
56089 this.activeEditor.completeEdit();
56091 this.activeEditor = null;
56095 * Called to get grid's drag proxy text, by default returns this.ddText.
56098 getDragDropText : function(){
56099 var count = this.selModel.getSelectedCell() ? 1 : 0;
56100 return String.format(this.ddText, count, count == 1 ? '' : 's');
56105 * Ext JS Library 1.1.1
56106 * Copyright(c) 2006-2007, Ext JS, LLC.
56108 * Originally Released Under LGPL - original licence link has changed is not relivant.
56111 * <script type="text/javascript">
56114 // private - not really -- you end up using it !
56115 // This is a support class used internally by the Grid components
56118 * @class Roo.grid.GridEditor
56119 * @extends Roo.Editor
56120 * Class for creating and editable grid elements.
56121 * @param {Object} config any settings (must include field)
56123 Roo.grid.GridEditor = function(field, config){
56124 if (!config && field.field) {
56126 field = Roo.factory(config.field, Roo.form);
56128 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56129 field.monitorTab = false;
56132 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56135 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56138 alignment: "tl-tl",
56141 cls: "x-small-editor x-grid-editor",
56146 * Ext JS Library 1.1.1
56147 * Copyright(c) 2006-2007, Ext JS, LLC.
56149 * Originally Released Under LGPL - original licence link has changed is not relivant.
56152 * <script type="text/javascript">
56157 Roo.grid.PropertyRecord = Roo.data.Record.create([
56158 {name:'name',type:'string'}, 'value'
56162 Roo.grid.PropertyStore = function(grid, source){
56164 this.store = new Roo.data.Store({
56165 recordType : Roo.grid.PropertyRecord
56167 this.store.on('update', this.onUpdate, this);
56169 this.setSource(source);
56171 Roo.grid.PropertyStore.superclass.constructor.call(this);
56176 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56177 setSource : function(o){
56179 this.store.removeAll();
56182 if(this.isEditableValue(o[k])){
56183 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56186 this.store.loadRecords({records: data}, {}, true);
56189 onUpdate : function(ds, record, type){
56190 if(type == Roo.data.Record.EDIT){
56191 var v = record.data['value'];
56192 var oldValue = record.modified['value'];
56193 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56194 this.source[record.id] = v;
56196 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56203 getProperty : function(row){
56204 return this.store.getAt(row);
56207 isEditableValue: function(val){
56208 if(val && val instanceof Date){
56210 }else if(typeof val == 'object' || typeof val == 'function'){
56216 setValue : function(prop, value){
56217 this.source[prop] = value;
56218 this.store.getById(prop).set('value', value);
56221 getSource : function(){
56222 return this.source;
56226 Roo.grid.PropertyColumnModel = function(grid, store){
56229 g.PropertyColumnModel.superclass.constructor.call(this, [
56230 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56231 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56233 this.store = store;
56234 this.bselect = Roo.DomHelper.append(document.body, {
56235 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56236 {tag: 'option', value: 'true', html: 'true'},
56237 {tag: 'option', value: 'false', html: 'false'}
56240 Roo.id(this.bselect);
56243 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56244 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56245 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56246 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56247 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56249 this.renderCellDelegate = this.renderCell.createDelegate(this);
56250 this.renderPropDelegate = this.renderProp.createDelegate(this);
56253 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56257 valueText : 'Value',
56259 dateFormat : 'm/j/Y',
56262 renderDate : function(dateVal){
56263 return dateVal.dateFormat(this.dateFormat);
56266 renderBool : function(bVal){
56267 return bVal ? 'true' : 'false';
56270 isCellEditable : function(colIndex, rowIndex){
56271 return colIndex == 1;
56274 getRenderer : function(col){
56276 this.renderCellDelegate : this.renderPropDelegate;
56279 renderProp : function(v){
56280 return this.getPropertyName(v);
56283 renderCell : function(val){
56285 if(val instanceof Date){
56286 rv = this.renderDate(val);
56287 }else if(typeof val == 'boolean'){
56288 rv = this.renderBool(val);
56290 return Roo.util.Format.htmlEncode(rv);
56293 getPropertyName : function(name){
56294 var pn = this.grid.propertyNames;
56295 return pn && pn[name] ? pn[name] : name;
56298 getCellEditor : function(colIndex, rowIndex){
56299 var p = this.store.getProperty(rowIndex);
56300 var n = p.data['name'], val = p.data['value'];
56302 if(typeof(this.grid.customEditors[n]) == 'string'){
56303 return this.editors[this.grid.customEditors[n]];
56305 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56306 return this.grid.customEditors[n];
56308 if(val instanceof Date){
56309 return this.editors['date'];
56310 }else if(typeof val == 'number'){
56311 return this.editors['number'];
56312 }else if(typeof val == 'boolean'){
56313 return this.editors['boolean'];
56315 return this.editors['string'];
56321 * @class Roo.grid.PropertyGrid
56322 * @extends Roo.grid.EditorGrid
56323 * This class represents the interface of a component based property grid control.
56324 * <br><br>Usage:<pre><code>
56325 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56333 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56334 * The container MUST have some type of size defined for the grid to fill. The container will be
56335 * automatically set to position relative if it isn't already.
56336 * @param {Object} config A config object that sets properties on this grid.
56338 Roo.grid.PropertyGrid = function(container, config){
56339 config = config || {};
56340 var store = new Roo.grid.PropertyStore(this);
56341 this.store = store;
56342 var cm = new Roo.grid.PropertyColumnModel(this, store);
56343 store.store.sort('name', 'ASC');
56344 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56347 enableColLock:false,
56348 enableColumnMove:false,
56350 trackMouseOver: false,
56353 this.getGridEl().addClass('x-props-grid');
56354 this.lastEditRow = null;
56355 this.on('columnresize', this.onColumnResize, this);
56358 * @event beforepropertychange
56359 * Fires before a property changes (return false to stop?)
56360 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56361 * @param {String} id Record Id
56362 * @param {String} newval New Value
56363 * @param {String} oldval Old Value
56365 "beforepropertychange": true,
56367 * @event propertychange
56368 * Fires after a property changes
56369 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56370 * @param {String} id Record Id
56371 * @param {String} newval New Value
56372 * @param {String} oldval Old Value
56374 "propertychange": true
56376 this.customEditors = this.customEditors || {};
56378 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56381 * @cfg {Object} customEditors map of colnames=> custom editors.
56382 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56383 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56384 * false disables editing of the field.
56388 * @cfg {Object} propertyNames map of property Names to their displayed value
56391 render : function(){
56392 Roo.grid.PropertyGrid.superclass.render.call(this);
56393 this.autoSize.defer(100, this);
56396 autoSize : function(){
56397 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56399 this.view.fitColumns();
56403 onColumnResize : function(){
56404 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56408 * Sets the data for the Grid
56409 * accepts a Key => Value object of all the elements avaiable.
56410 * @param {Object} data to appear in grid.
56412 setSource : function(source){
56413 this.store.setSource(source);
56417 * Gets all the data from the grid.
56418 * @return {Object} data data stored in grid
56420 getSource : function(){
56421 return this.store.getSource();
56430 * @class Roo.grid.Calendar
56431 * @extends Roo.util.Grid
56432 * This class extends the Grid to provide a calendar widget
56433 * <br><br>Usage:<pre><code>
56434 var grid = new Roo.grid.Calendar("my-container-id", {
56437 selModel: mySelectionModel,
56438 autoSizeColumns: true,
56439 monitorWindowResize: false,
56440 trackMouseOver: true
56441 eventstore : real data store..
56447 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56448 * The container MUST have some type of size defined for the grid to fill. The container will be
56449 * automatically set to position relative if it isn't already.
56450 * @param {Object} config A config object that sets properties on this grid.
56452 Roo.grid.Calendar = function(container, config){
56453 // initialize the container
56454 this.container = Roo.get(container);
56455 this.container.update("");
56456 this.container.setStyle("overflow", "hidden");
56457 this.container.addClass('x-grid-container');
56459 this.id = this.container.id;
56461 Roo.apply(this, config);
56462 // check and correct shorthanded configs
56466 for (var r = 0;r < 6;r++) {
56469 for (var c =0;c < 7;c++) {
56473 if (this.eventStore) {
56474 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56475 this.eventStore.on('load',this.onLoad, this);
56476 this.eventStore.on('beforeload',this.clearEvents, this);
56480 this.dataSource = new Roo.data.Store({
56481 proxy: new Roo.data.MemoryProxy(rows),
56482 reader: new Roo.data.ArrayReader({}, [
56483 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56486 this.dataSource.load();
56487 this.ds = this.dataSource;
56488 this.ds.xmodule = this.xmodule || false;
56491 var cellRender = function(v,x,r)
56493 return String.format(
56494 '<div class="fc-day fc-widget-content"><div>' +
56495 '<div class="fc-event-container"></div>' +
56496 '<div class="fc-day-number">{0}</div>'+
56498 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56499 '</div></div>', v);
56504 this.colModel = new Roo.grid.ColumnModel( [
56506 xtype: 'ColumnModel',
56508 dataIndex : 'weekday0',
56510 renderer : cellRender
56513 xtype: 'ColumnModel',
56515 dataIndex : 'weekday1',
56517 renderer : cellRender
56520 xtype: 'ColumnModel',
56522 dataIndex : 'weekday2',
56523 header : 'Tuesday',
56524 renderer : cellRender
56527 xtype: 'ColumnModel',
56529 dataIndex : 'weekday3',
56530 header : 'Wednesday',
56531 renderer : cellRender
56534 xtype: 'ColumnModel',
56536 dataIndex : 'weekday4',
56537 header : 'Thursday',
56538 renderer : cellRender
56541 xtype: 'ColumnModel',
56543 dataIndex : 'weekday5',
56545 renderer : cellRender
56548 xtype: 'ColumnModel',
56550 dataIndex : 'weekday6',
56551 header : 'Saturday',
56552 renderer : cellRender
56555 this.cm = this.colModel;
56556 this.cm.xmodule = this.xmodule || false;
56560 //this.selModel = new Roo.grid.CellSelectionModel();
56561 //this.sm = this.selModel;
56562 //this.selModel.init(this);
56566 this.container.setWidth(this.width);
56570 this.container.setHeight(this.height);
56577 * The raw click event for the entire grid.
56578 * @param {Roo.EventObject} e
56583 * The raw dblclick event for the entire grid.
56584 * @param {Roo.EventObject} e
56588 * @event contextmenu
56589 * The raw contextmenu event for the entire grid.
56590 * @param {Roo.EventObject} e
56592 "contextmenu" : true,
56595 * The raw mousedown event for the entire grid.
56596 * @param {Roo.EventObject} e
56598 "mousedown" : true,
56601 * The raw mouseup event for the entire grid.
56602 * @param {Roo.EventObject} e
56607 * The raw mouseover event for the entire grid.
56608 * @param {Roo.EventObject} e
56610 "mouseover" : true,
56613 * The raw mouseout event for the entire grid.
56614 * @param {Roo.EventObject} e
56619 * The raw keypress event for the entire grid.
56620 * @param {Roo.EventObject} e
56625 * The raw keydown event for the entire grid.
56626 * @param {Roo.EventObject} e
56634 * Fires when a cell is clicked
56635 * @param {Grid} this
56636 * @param {Number} rowIndex
56637 * @param {Number} columnIndex
56638 * @param {Roo.EventObject} e
56640 "cellclick" : true,
56642 * @event celldblclick
56643 * Fires when a cell is double clicked
56644 * @param {Grid} this
56645 * @param {Number} rowIndex
56646 * @param {Number} columnIndex
56647 * @param {Roo.EventObject} e
56649 "celldblclick" : true,
56652 * Fires when a row is clicked
56653 * @param {Grid} this
56654 * @param {Number} rowIndex
56655 * @param {Roo.EventObject} e
56659 * @event rowdblclick
56660 * Fires when a row is double clicked
56661 * @param {Grid} this
56662 * @param {Number} rowIndex
56663 * @param {Roo.EventObject} e
56665 "rowdblclick" : true,
56667 * @event headerclick
56668 * Fires when a header is clicked
56669 * @param {Grid} this
56670 * @param {Number} columnIndex
56671 * @param {Roo.EventObject} e
56673 "headerclick" : true,
56675 * @event headerdblclick
56676 * Fires when a header cell is double clicked
56677 * @param {Grid} this
56678 * @param {Number} columnIndex
56679 * @param {Roo.EventObject} e
56681 "headerdblclick" : true,
56683 * @event rowcontextmenu
56684 * Fires when a row is right clicked
56685 * @param {Grid} this
56686 * @param {Number} rowIndex
56687 * @param {Roo.EventObject} e
56689 "rowcontextmenu" : true,
56691 * @event cellcontextmenu
56692 * Fires when a cell is right clicked
56693 * @param {Grid} this
56694 * @param {Number} rowIndex
56695 * @param {Number} cellIndex
56696 * @param {Roo.EventObject} e
56698 "cellcontextmenu" : true,
56700 * @event headercontextmenu
56701 * Fires when a header is right clicked
56702 * @param {Grid} this
56703 * @param {Number} columnIndex
56704 * @param {Roo.EventObject} e
56706 "headercontextmenu" : true,
56708 * @event bodyscroll
56709 * Fires when the body element is scrolled
56710 * @param {Number} scrollLeft
56711 * @param {Number} scrollTop
56713 "bodyscroll" : true,
56715 * @event columnresize
56716 * Fires when the user resizes a column
56717 * @param {Number} columnIndex
56718 * @param {Number} newSize
56720 "columnresize" : true,
56722 * @event columnmove
56723 * Fires when the user moves a column
56724 * @param {Number} oldIndex
56725 * @param {Number} newIndex
56727 "columnmove" : true,
56730 * Fires when row(s) start being dragged
56731 * @param {Grid} this
56732 * @param {Roo.GridDD} dd The drag drop object
56733 * @param {event} e The raw browser event
56735 "startdrag" : true,
56738 * Fires when a drag operation is complete
56739 * @param {Grid} this
56740 * @param {Roo.GridDD} dd The drag drop object
56741 * @param {event} e The raw browser event
56746 * Fires when dragged row(s) are dropped on a valid DD target
56747 * @param {Grid} this
56748 * @param {Roo.GridDD} dd The drag drop object
56749 * @param {String} targetId The target drag drop object
56750 * @param {event} e The raw browser event
56755 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56756 * @param {Grid} this
56757 * @param {Roo.GridDD} dd The drag drop object
56758 * @param {String} targetId The target drag drop object
56759 * @param {event} e The raw browser event
56764 * Fires when the dragged row(s) first cross another DD target while being dragged
56765 * @param {Grid} this
56766 * @param {Roo.GridDD} dd The drag drop object
56767 * @param {String} targetId The target drag drop object
56768 * @param {event} e The raw browser event
56770 "dragenter" : true,
56773 * Fires when the dragged row(s) leave another DD target while being dragged
56774 * @param {Grid} this
56775 * @param {Roo.GridDD} dd The drag drop object
56776 * @param {String} targetId The target drag drop object
56777 * @param {event} e The raw browser event
56782 * Fires when a row is rendered, so you can change add a style to it.
56783 * @param {GridView} gridview The grid view
56784 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56790 * Fires when the grid is rendered
56791 * @param {Grid} grid
56796 * Fires when a date is selected
56797 * @param {DatePicker} this
56798 * @param {Date} date The selected date
56802 * @event monthchange
56803 * Fires when the displayed month changes
56804 * @param {DatePicker} this
56805 * @param {Date} date The selected month
56807 'monthchange': true,
56809 * @event evententer
56810 * Fires when mouse over an event
56811 * @param {Calendar} this
56812 * @param {event} Event
56814 'evententer': true,
56816 * @event eventleave
56817 * Fires when the mouse leaves an
56818 * @param {Calendar} this
56821 'eventleave': true,
56823 * @event eventclick
56824 * Fires when the mouse click an
56825 * @param {Calendar} this
56828 'eventclick': true,
56830 * @event eventrender
56831 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
56832 * @param {Calendar} this
56833 * @param {data} data to be modified
56835 'eventrender': true
56839 Roo.grid.Grid.superclass.constructor.call(this);
56840 this.on('render', function() {
56841 this.view.el.addClass('x-grid-cal');
56843 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
56847 if (!Roo.grid.Calendar.style) {
56848 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
56851 '.x-grid-cal .x-grid-col' : {
56852 height: 'auto !important',
56853 'vertical-align': 'top'
56855 '.x-grid-cal .fc-event-hori' : {
56866 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
56868 * @cfg {Store} eventStore The store that loads events.
56873 activeDate : false,
56876 monitorWindowResize : false,
56879 resizeColumns : function() {
56880 var col = (this.view.el.getWidth() / 7) - 3;
56881 // loop through cols, and setWidth
56882 for(var i =0 ; i < 7 ; i++){
56883 this.cm.setColumnWidth(i, col);
56886 setDate :function(date) {
56888 Roo.log('setDate?');
56890 this.resizeColumns();
56891 var vd = this.activeDate;
56892 this.activeDate = date;
56893 // if(vd && this.el){
56894 // var t = date.getTime();
56895 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
56896 // Roo.log('using add remove');
56898 // this.fireEvent('monthchange', this, date);
56900 // this.cells.removeClass("fc-state-highlight");
56901 // this.cells.each(function(c){
56902 // if(c.dateValue == t){
56903 // c.addClass("fc-state-highlight");
56904 // setTimeout(function(){
56905 // try{c.dom.firstChild.focus();}catch(e){}
56915 var days = date.getDaysInMonth();
56917 var firstOfMonth = date.getFirstDateOfMonth();
56918 var startingPos = firstOfMonth.getDay()-this.startDay;
56920 if(startingPos < this.startDay){
56924 var pm = date.add(Date.MONTH, -1);
56925 var prevStart = pm.getDaysInMonth()-startingPos;
56929 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
56931 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
56932 //this.cells.addClassOnOver('fc-state-hover');
56934 var cells = this.cells.elements;
56935 var textEls = this.textNodes;
56937 //Roo.each(cells, function(cell){
56938 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
56941 days += startingPos;
56943 // convert everything to numbers so it's fast
56944 var day = 86400000;
56945 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
56948 //Roo.log(prevStart);
56950 var today = new Date().clearTime().getTime();
56951 var sel = date.clearTime().getTime();
56952 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
56953 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
56954 var ddMatch = this.disabledDatesRE;
56955 var ddText = this.disabledDatesText;
56956 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
56957 var ddaysText = this.disabledDaysText;
56958 var format = this.format;
56960 var setCellClass = function(cal, cell){
56962 //Roo.log('set Cell Class');
56964 var t = d.getTime();
56969 cell.dateValue = t;
56971 cell.className += " fc-today";
56972 cell.className += " fc-state-highlight";
56973 cell.title = cal.todayText;
56976 // disable highlight in other month..
56977 cell.className += " fc-state-highlight";
56982 //cell.className = " fc-state-disabled";
56983 cell.title = cal.minText;
56987 //cell.className = " fc-state-disabled";
56988 cell.title = cal.maxText;
56992 if(ddays.indexOf(d.getDay()) != -1){
56993 // cell.title = ddaysText;
56994 // cell.className = " fc-state-disabled";
56997 if(ddMatch && format){
56998 var fvalue = d.dateFormat(format);
56999 if(ddMatch.test(fvalue)){
57000 cell.title = ddText.replace("%0", fvalue);
57001 cell.className = " fc-state-disabled";
57005 if (!cell.initialClassName) {
57006 cell.initialClassName = cell.dom.className;
57009 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57014 for(; i < startingPos; i++) {
57015 cells[i].dayName = (++prevStart);
57016 Roo.log(textEls[i]);
57017 d.setDate(d.getDate()+1);
57019 //cells[i].className = "fc-past fc-other-month";
57020 setCellClass(this, cells[i]);
57025 for(; i < days; i++){
57026 intDay = i - startingPos + 1;
57027 cells[i].dayName = (intDay);
57028 d.setDate(d.getDate()+1);
57030 cells[i].className = ''; // "x-date-active";
57031 setCellClass(this, cells[i]);
57035 for(; i < 42; i++) {
57036 //textEls[i].innerHTML = (++extraDays);
57038 d.setDate(d.getDate()+1);
57039 cells[i].dayName = (++extraDays);
57040 cells[i].className = "fc-future fc-other-month";
57041 setCellClass(this, cells[i]);
57044 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57046 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57048 // this will cause all the cells to mis
57051 for (var r = 0;r < 6;r++) {
57052 for (var c =0;c < 7;c++) {
57053 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57057 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57058 for(i=0;i<cells.length;i++) {
57060 this.cells.elements[i].dayName = cells[i].dayName ;
57061 this.cells.elements[i].className = cells[i].className;
57062 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57063 this.cells.elements[i].title = cells[i].title ;
57064 this.cells.elements[i].dateValue = cells[i].dateValue ;
57070 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57071 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57073 ////if(totalRows != 6){
57074 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57075 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57078 this.fireEvent('monthchange', this, date);
57083 * Returns the grid's SelectionModel.
57084 * @return {SelectionModel}
57086 getSelectionModel : function(){
57087 if(!this.selModel){
57088 this.selModel = new Roo.grid.CellSelectionModel();
57090 return this.selModel;
57094 this.eventStore.load()
57100 findCell : function(dt) {
57101 dt = dt.clearTime().getTime();
57103 this.cells.each(function(c){
57104 //Roo.log("check " +c.dateValue + '?=' + dt);
57105 if(c.dateValue == dt){
57115 findCells : function(rec) {
57116 var s = rec.data.start_dt.clone().clearTime().getTime();
57118 var e= rec.data.end_dt.clone().clearTime().getTime();
57121 this.cells.each(function(c){
57122 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57124 if(c.dateValue > e){
57127 if(c.dateValue < s){
57136 findBestRow: function(cells)
57140 for (var i =0 ; i < cells.length;i++) {
57141 ret = Math.max(cells[i].rows || 0,ret);
57148 addItem : function(rec)
57150 // look for vertical location slot in
57151 var cells = this.findCells(rec);
57153 rec.row = this.findBestRow(cells);
57155 // work out the location.
57159 for(var i =0; i < cells.length; i++) {
57167 if (crow.start.getY() == cells[i].getY()) {
57169 crow.end = cells[i];
57185 for (var i = 0; i < cells.length;i++) {
57186 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57193 clearEvents: function() {
57195 if (!this.eventStore.getCount()) {
57198 // reset number of rows in cells.
57199 Roo.each(this.cells.elements, function(c){
57203 this.eventStore.each(function(e) {
57204 this.clearEvent(e);
57209 clearEvent : function(ev)
57212 Roo.each(ev.els, function(el) {
57213 el.un('mouseenter' ,this.onEventEnter, this);
57214 el.un('mouseleave' ,this.onEventLeave, this);
57222 renderEvent : function(ev,ctr) {
57224 ctr = this.view.el.select('.fc-event-container',true).first();
57228 this.clearEvent(ev);
57234 var cells = ev.cells;
57235 var rows = ev.rows;
57236 this.fireEvent('eventrender', this, ev);
57238 for(var i =0; i < rows.length; i++) {
57242 cls += ' fc-event-start';
57244 if ((i+1) == rows.length) {
57245 cls += ' fc-event-end';
57248 //Roo.log(ev.data);
57249 // how many rows should it span..
57250 var cg = this.eventTmpl.append(ctr,Roo.apply({
57253 }, ev.data) , true);
57256 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57257 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57258 cg.on('click', this.onEventClick, this, ev);
57262 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57263 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57266 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57267 cg.setWidth(ebox.right - sbox.x -2);
57271 renderEvents: function()
57273 // first make sure there is enough space..
57275 if (!this.eventTmpl) {
57276 this.eventTmpl = new Roo.Template(
57277 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57278 '<div class="fc-event-inner">' +
57279 '<span class="fc-event-time">{time}</span>' +
57280 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57282 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57290 this.cells.each(function(c) {
57291 //Roo.log(c.select('.fc-day-content div',true).first());
57292 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57295 var ctr = this.view.el.select('.fc-event-container',true).first();
57298 this.eventStore.each(function(ev){
57300 this.renderEvent(ev);
57304 this.view.layout();
57308 onEventEnter: function (e, el,event,d) {
57309 this.fireEvent('evententer', this, el, event);
57312 onEventLeave: function (e, el,event,d) {
57313 this.fireEvent('eventleave', this, el, event);
57316 onEventClick: function (e, el,event,d) {
57317 this.fireEvent('eventclick', this, el, event);
57320 onMonthChange: function () {
57324 onLoad: function () {
57326 //Roo.log('calendar onload');
57328 if(this.eventStore.getCount() > 0){
57332 this.eventStore.each(function(d){
57337 if (typeof(add.end_dt) == 'undefined') {
57338 Roo.log("Missing End time in calendar data: ");
57342 if (typeof(add.start_dt) == 'undefined') {
57343 Roo.log("Missing Start time in calendar data: ");
57347 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57348 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57349 add.id = add.id || d.id;
57350 add.title = add.title || '??';
57358 this.renderEvents();
57368 render : function ()
57372 if (!this.view.el.hasClass('course-timesheet')) {
57373 this.view.el.addClass('course-timesheet');
57375 if (this.tsStyle) {
57380 Roo.log(_this.grid.view.el.getWidth());
57383 this.tsStyle = Roo.util.CSS.createStyleSheet({
57384 '.course-timesheet .x-grid-row' : {
57387 '.x-grid-row td' : {
57388 'vertical-align' : 0
57390 '.course-edit-link' : {
57392 'text-overflow' : 'ellipsis',
57393 'overflow' : 'hidden',
57394 'white-space' : 'nowrap',
57395 'cursor' : 'pointer'
57400 '.de-act-sup-link' : {
57401 'color' : 'purple',
57402 'text-decoration' : 'line-through'
57406 'text-decoration' : 'line-through'
57408 '.course-timesheet .course-highlight' : {
57409 'border-top-style': 'dashed !important',
57410 'border-bottom-bottom': 'dashed !important'
57412 '.course-timesheet .course-item' : {
57413 'font-family' : 'tahoma, arial, helvetica',
57414 'font-size' : '11px',
57415 'overflow' : 'hidden',
57416 'padding-left' : '10px',
57417 'padding-right' : '10px',
57418 'padding-top' : '10px'
57426 monitorWindowResize : false,
57427 cellrenderer : function(v,x,r)
57432 xtype: 'CellSelectionModel',
57439 beforeload : function (_self, options)
57441 options.params = options.params || {};
57442 options.params._month = _this.monthField.getValue();
57443 options.params.limit = 9999;
57444 options.params['sort'] = 'when_dt';
57445 options.params['dir'] = 'ASC';
57446 this.proxy.loadResponse = this.loadResponse;
57448 //this.addColumns();
57450 load : function (_self, records, options)
57452 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57453 // if you click on the translation.. you can edit it...
57454 var el = Roo.get(this);
57455 var id = el.dom.getAttribute('data-id');
57456 var d = el.dom.getAttribute('data-date');
57457 var t = el.dom.getAttribute('data-time');
57458 //var id = this.child('span').dom.textContent;
57461 Pman.Dialog.CourseCalendar.show({
57465 productitem_active : id ? 1 : 0
57467 _this.grid.ds.load({});
57472 _this.panel.fireEvent('resize', [ '', '' ]);
57475 loadResponse : function(o, success, response){
57476 // this is overridden on before load..
57478 Roo.log("our code?");
57479 //Roo.log(success);
57480 //Roo.log(response)
57481 delete this.activeRequest;
57483 this.fireEvent("loadexception", this, o, response);
57484 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57489 result = o.reader.read(response);
57491 Roo.log("load exception?");
57492 this.fireEvent("loadexception", this, o, response, e);
57493 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57496 Roo.log("ready...");
57497 // loop through result.records;
57498 // and set this.tdate[date] = [] << array of records..
57500 Roo.each(result.records, function(r){
57502 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57503 _this.tdata[r.data.when_dt.format('j')] = [];
57505 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57508 //Roo.log(_this.tdata);
57510 result.records = [];
57511 result.totalRecords = 6;
57513 // let's generate some duumy records for the rows.
57514 //var st = _this.dateField.getValue();
57516 // work out monday..
57517 //st = st.add(Date.DAY, -1 * st.format('w'));
57519 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57521 var firstOfMonth = date.getFirstDayOfMonth();
57522 var days = date.getDaysInMonth();
57524 var firstAdded = false;
57525 for (var i = 0; i < result.totalRecords ; i++) {
57526 //var d= st.add(Date.DAY, i);
57529 for(var w = 0 ; w < 7 ; w++){
57530 if(!firstAdded && firstOfMonth != w){
57537 var dd = (d > 0 && d < 10) ? "0"+d : d;
57538 row['weekday'+w] = String.format(
57539 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57540 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57542 date.format('Y-m-')+dd
57545 if(typeof(_this.tdata[d]) != 'undefined'){
57546 Roo.each(_this.tdata[d], function(r){
57550 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57551 if(r.parent_id*1>0){
57552 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57555 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57556 deactive = 'de-act-link';
57559 row['weekday'+w] += String.format(
57560 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57562 r.product_id_name, //1
57563 r.when_dt.format('h:ia'), //2
57573 // only do this if something added..
57575 result.records.push(_this.grid.dataSource.reader.newRow(row));
57579 // push it twice. (second one with an hour..
57583 this.fireEvent("load", this, o, o.request.arg);
57584 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57586 sortInfo : {field: 'when_dt', direction : 'ASC' },
57588 xtype: 'HttpProxy',
57591 url : baseURL + '/Roo/Shop_course.php'
57594 xtype: 'JsonReader',
57611 'name': 'parent_id',
57615 'name': 'product_id',
57619 'name': 'productitem_id',
57637 click : function (_self, e)
57639 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57640 sd.setMonth(sd.getMonth()-1);
57641 _this.monthField.setValue(sd.format('Y-m-d'));
57642 _this.grid.ds.load({});
57648 xtype: 'Separator',
57652 xtype: 'MonthField',
57655 render : function (_self)
57657 _this.monthField = _self;
57658 // _this.monthField.set today
57660 select : function (combo, date)
57662 _this.grid.ds.load({});
57665 value : (function() { return new Date(); })()
57668 xtype: 'Separator',
57674 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57684 click : function (_self, e)
57686 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57687 sd.setMonth(sd.getMonth()+1);
57688 _this.monthField.setValue(sd.format('Y-m-d'));
57689 _this.grid.ds.load({});
57702 * Ext JS Library 1.1.1
57703 * Copyright(c) 2006-2007, Ext JS, LLC.
57705 * Originally Released Under LGPL - original licence link has changed is not relivant.
57708 * <script type="text/javascript">
57712 * @class Roo.LoadMask
57713 * A simple utility class for generically masking elements while loading data. If the element being masked has
57714 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57715 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57716 * element's UpdateManager load indicator and will be destroyed after the initial load.
57718 * Create a new LoadMask
57719 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57720 * @param {Object} config The config object
57722 Roo.LoadMask = function(el, config){
57723 this.el = Roo.get(el);
57724 Roo.apply(this, config);
57726 this.store.on('beforeload', this.onBeforeLoad, this);
57727 this.store.on('load', this.onLoad, this);
57728 this.store.on('loadexception', this.onLoadException, this);
57729 this.removeMask = false;
57731 var um = this.el.getUpdateManager();
57732 um.showLoadIndicator = false; // disable the default indicator
57733 um.on('beforeupdate', this.onBeforeLoad, this);
57734 um.on('update', this.onLoad, this);
57735 um.on('failure', this.onLoad, this);
57736 this.removeMask = true;
57740 Roo.LoadMask.prototype = {
57742 * @cfg {Boolean} removeMask
57743 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
57744 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
57747 * @cfg {String} msg
57748 * The text to display in a centered loading message box (defaults to 'Loading...')
57750 msg : 'Loading...',
57752 * @cfg {String} msgCls
57753 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
57755 msgCls : 'x-mask-loading',
57758 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
57764 * Disables the mask to prevent it from being displayed
57766 disable : function(){
57767 this.disabled = true;
57771 * Enables the mask so that it can be displayed
57773 enable : function(){
57774 this.disabled = false;
57777 onLoadException : function()
57779 Roo.log(arguments);
57781 if (typeof(arguments[3]) != 'undefined') {
57782 Roo.MessageBox.alert("Error loading",arguments[3]);
57786 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
57787 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
57796 this.el.unmask(this.removeMask);
57799 onLoad : function()
57801 this.el.unmask(this.removeMask);
57805 onBeforeLoad : function(){
57806 if(!this.disabled){
57807 this.el.mask(this.msg, this.msgCls);
57812 destroy : function(){
57814 this.store.un('beforeload', this.onBeforeLoad, this);
57815 this.store.un('load', this.onLoad, this);
57816 this.store.un('loadexception', this.onLoadException, this);
57818 var um = this.el.getUpdateManager();
57819 um.un('beforeupdate', this.onBeforeLoad, this);
57820 um.un('update', this.onLoad, this);
57821 um.un('failure', this.onLoad, this);
57826 * Ext JS Library 1.1.1
57827 * Copyright(c) 2006-2007, Ext JS, LLC.
57829 * Originally Released Under LGPL - original licence link has changed is not relivant.
57832 * <script type="text/javascript">
57837 * @class Roo.XTemplate
57838 * @extends Roo.Template
57839 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
57841 var t = new Roo.XTemplate(
57842 '<select name="{name}">',
57843 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
57847 // then append, applying the master template values
57850 * Supported features:
57855 {a_variable} - output encoded.
57856 {a_variable.format:("Y-m-d")} - call a method on the variable
57857 {a_variable:raw} - unencoded output
57858 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
57859 {a_variable:this.method_on_template(...)} - call a method on the template object.
57864 <tpl for="a_variable or condition.."></tpl>
57865 <tpl if="a_variable or condition"></tpl>
57866 <tpl exec="some javascript"></tpl>
57867 <tpl name="named_template"></tpl> (experimental)
57869 <tpl for="."></tpl> - just iterate the property..
57870 <tpl for=".."></tpl> - iterates with the parent (probably the template)
57874 Roo.XTemplate = function()
57876 Roo.XTemplate.superclass.constructor.apply(this, arguments);
57883 Roo.extend(Roo.XTemplate, Roo.Template, {
57886 * The various sub templates
57891 * basic tag replacing syntax
57894 * // you can fake an object call by doing this
57898 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
57901 * compile the template
57903 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
57906 compile: function()
57910 s = ['<tpl>', s, '</tpl>'].join('');
57912 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
57913 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
57914 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
57915 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
57916 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
57921 while(true == !!(m = s.match(re))){
57922 var forMatch = m[0].match(nameRe),
57923 ifMatch = m[0].match(ifRe),
57924 execMatch = m[0].match(execRe),
57925 namedMatch = m[0].match(namedRe),
57930 name = forMatch && forMatch[1] ? forMatch[1] : '';
57933 // if - puts fn into test..
57934 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
57936 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
57941 // exec - calls a function... returns empty if true is returned.
57942 exp = execMatch && execMatch[1] ? execMatch[1] : null;
57944 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
57952 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
57953 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
57954 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
57957 var uid = namedMatch ? namedMatch[1] : id;
57961 id: namedMatch ? namedMatch[1] : id,
57968 s = s.replace(m[0], '');
57970 s = s.replace(m[0], '{xtpl'+ id + '}');
57975 for(var i = tpls.length-1; i >= 0; --i){
57976 this.compileTpl(tpls[i]);
57977 this.tpls[tpls[i].id] = tpls[i];
57979 this.master = tpls[tpls.length-1];
57983 * same as applyTemplate, except it's done to one of the subTemplates
57984 * when using named templates, you can do:
57986 * var str = pl.applySubTemplate('your-name', values);
57989 * @param {Number} id of the template
57990 * @param {Object} values to apply to template
57991 * @param {Object} parent (normaly the instance of this object)
57993 applySubTemplate : function(id, values, parent)
57997 var t = this.tpls[id];
58001 if(t.test && !t.test.call(this, values, parent)){
58005 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58006 Roo.log(e.toString());
58012 if(t.exec && t.exec.call(this, values, parent)){
58016 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58017 Roo.log(e.toString());
58022 var vs = t.target ? t.target.call(this, values, parent) : values;
58023 parent = t.target ? values : parent;
58024 if(t.target && vs instanceof Array){
58026 for(var i = 0, len = vs.length; i < len; i++){
58027 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58029 return buf.join('');
58031 return t.compiled.call(this, vs, parent);
58033 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58034 Roo.log(e.toString());
58035 Roo.log(t.compiled);
58040 compileTpl : function(tpl)
58042 var fm = Roo.util.Format;
58043 var useF = this.disableFormats !== true;
58044 var sep = Roo.isGecko ? "+" : ",";
58045 var undef = function(str) {
58046 Roo.log("Property not found :" + str);
58050 var fn = function(m, name, format, args)
58052 //Roo.log(arguments);
58053 args = args ? args.replace(/\\'/g,"'") : args;
58054 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58055 if (typeof(format) == 'undefined') {
58056 format= 'htmlEncode';
58058 if (format == 'raw' ) {
58062 if(name.substr(0, 4) == 'xtpl'){
58063 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58066 // build an array of options to determine if value is undefined..
58068 // basically get 'xxxx.yyyy' then do
58069 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58070 // (function () { Roo.log("Property not found"); return ''; })() :
58075 Roo.each(name.split('.'), function(st) {
58076 lookfor += (lookfor.length ? '.': '') + st;
58077 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58080 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58083 if(format && useF){
58085 args = args ? ',' + args : "";
58087 if(format.substr(0, 5) != "this."){
58088 format = "fm." + format + '(';
58090 format = 'this.call("'+ format.substr(5) + '", ';
58094 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58098 // called with xxyx.yuu:(test,test)
58100 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58102 // raw.. - :raw modifier..
58103 return "'"+ sep + udef_st + name + ")"+sep+"'";
58107 // branched to use + in gecko and [].join() in others
58109 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58110 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58113 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58114 body.push(tpl.body.replace(/(\r\n|\n)/g,
58115 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58116 body.push("'].join('');};};");
58117 body = body.join('');
58120 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58122 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58128 applyTemplate : function(values){
58129 return this.master.compiled.call(this, values, {});
58130 //var s = this.subs;
58133 apply : function(){
58134 return this.applyTemplate.apply(this, arguments);
58139 Roo.XTemplate.from = function(el){
58140 el = Roo.getDom(el);
58141 return new Roo.XTemplate(el.value || el.innerHTML);