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",
652 "Roo.bootstrap.dash");
655 * Ext JS Library 1.1.1
656 * Copyright(c) 2006-2007, Ext JS, LLC.
658 * Originally Released Under LGPL - original licence link has changed is not relivant.
661 * <script type="text/javascript">
665 // wrappedn so fnCleanup is not in global scope...
667 function fnCleanUp() {
668 var p = Function.prototype;
669 delete p.createSequence;
671 delete p.createDelegate;
672 delete p.createCallback;
673 delete p.createInterceptor;
675 window.detachEvent("onunload", fnCleanUp);
677 window.attachEvent("onunload", fnCleanUp);
684 * These functions are available on every Function object (any JavaScript function).
686 Roo.apply(Function.prototype, {
688 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
689 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
690 * Will create a function that is bound to those 2 args.
691 * @return {Function} The new function
693 createCallback : function(/*args...*/){
694 // make args available, in function below
695 var args = arguments;
698 return method.apply(window, args);
703 * Creates a delegate (callback) that sets the scope to obj.
704 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
705 * Will create a function that is automatically scoped to this.
706 * @param {Object} obj (optional) The object for which the scope is set
707 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
708 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
709 * if a number the args are inserted at the specified position
710 * @return {Function} The new function
712 createDelegate : function(obj, args, appendArgs){
715 var callArgs = args || arguments;
716 if(appendArgs === true){
717 callArgs = Array.prototype.slice.call(arguments, 0);
718 callArgs = callArgs.concat(args);
719 }else if(typeof appendArgs == "number"){
720 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
721 var applyArgs = [appendArgs, 0].concat(args); // create method call params
722 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
724 return method.apply(obj || window, callArgs);
729 * Calls this function after the number of millseconds specified.
730 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
731 * @param {Object} obj (optional) The object for which the scope is set
732 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
733 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
734 * if a number the args are inserted at the specified position
735 * @return {Number} The timeout id that can be used with clearTimeout
737 defer : function(millis, obj, args, appendArgs){
738 var fn = this.createDelegate(obj, args, appendArgs);
740 return setTimeout(fn, millis);
746 * Create a combined function call sequence of the original function + the passed function.
747 * The resulting function returns the results of the original function.
748 * The passed fcn is called with the parameters of the original function
749 * @param {Function} fcn The function to sequence
750 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
751 * @return {Function} The new function
753 createSequence : function(fcn, scope){
754 if(typeof fcn != "function"){
759 var retval = method.apply(this || window, arguments);
760 fcn.apply(scope || this || window, arguments);
766 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
767 * The resulting function returns the results of the original function.
768 * The passed fcn is called with the parameters of the original function.
770 * @param {Function} fcn The function to call before the original
771 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
772 * @return {Function} The new function
774 createInterceptor : function(fcn, scope){
775 if(typeof fcn != "function"){
782 if(fcn.apply(scope || this || window, arguments) === false){
785 return method.apply(this || window, arguments);
791 * Ext JS Library 1.1.1
792 * Copyright(c) 2006-2007, Ext JS, LLC.
794 * Originally Released Under LGPL - original licence link has changed is not relivant.
797 * <script type="text/javascript">
800 Roo.applyIf(String, {
805 * Escapes the passed string for ' and \
806 * @param {String} string The string to escape
807 * @return {String} The escaped string
810 escape : function(string) {
811 return string.replace(/('|\\)/g, "\\$1");
815 * Pads the left side of a string with a specified character. This is especially useful
816 * for normalizing number and date strings. Example usage:
818 var s = String.leftPad('123', 5, '0');
819 // s now contains the string: '00123'
821 * @param {String} string The original string
822 * @param {Number} size The total length of the output string
823 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
824 * @return {String} The padded string
827 leftPad : function (val, size, ch) {
828 var result = new String(val);
829 if(ch === null || ch === undefined || ch === '') {
832 while (result.length < size) {
833 result = ch + result;
839 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
840 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
842 var cls = 'my-class', text = 'Some text';
843 var s = String.format('<div class="{0}">{1}</div>', cls, text);
844 // s now contains the string: '<div class="my-class">Some text</div>'
846 * @param {String} string The tokenized string to be formatted
847 * @param {String} value1 The value to replace token {0}
848 * @param {String} value2 Etc...
849 * @return {String} The formatted string
852 format : function(format){
853 var args = Array.prototype.slice.call(arguments, 1);
854 return format.replace(/\{(\d+)\}/g, function(m, i){
855 return Roo.util.Format.htmlEncode(args[i]);
861 * Utility function that allows you to easily switch a string between two alternating values. The passed value
862 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
863 * they are already different, the first value passed in is returned. Note that this method returns the new value
864 * but does not change the current string.
866 // alternate sort directions
867 sort = sort.toggle('ASC', 'DESC');
869 // instead of conditional logic:
870 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
872 * @param {String} value The value to compare to the current string
873 * @param {String} other The new value to use if the string already equals the first value passed in
874 * @return {String} The new value
877 String.prototype.toggle = function(value, other){
878 return this == value ? other : value;
881 * Ext JS Library 1.1.1
882 * Copyright(c) 2006-2007, Ext JS, LLC.
884 * Originally Released Under LGPL - original licence link has changed is not relivant.
887 * <script type="text/javascript">
893 Roo.applyIf(Number.prototype, {
895 * Checks whether or not the current number is within a desired range. If the number is already within the
896 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
897 * exceeded. Note that this method returns the constrained value but does not change the current number.
898 * @param {Number} min The minimum number in the range
899 * @param {Number} max The maximum number in the range
900 * @return {Number} The constrained value if outside the range, otherwise the current value
902 constrain : function(min, max){
903 return Math.min(Math.max(this, min), max);
907 * Ext JS Library 1.1.1
908 * Copyright(c) 2006-2007, Ext JS, LLC.
910 * Originally Released Under LGPL - original licence link has changed is not relivant.
913 * <script type="text/javascript">
918 Roo.applyIf(Array.prototype, {
920 * Checks whether or not the specified object exists in the array.
921 * @param {Object} o The object to check for
922 * @return {Number} The index of o in the array (or -1 if it is not found)
924 indexOf : function(o){
925 for (var i = 0, len = this.length; i < len; i++){
926 if(this[i] == o) return i;
932 * Removes the specified object from the array. If the object is not found nothing happens.
933 * @param {Object} o The object to remove
935 remove : function(o){
936 var index = this.indexOf(o);
938 this.splice(index, 1);
942 * Map (JS 1.6 compatibility)
943 * @param {Function} function to call
947 var len = this.length >>> 0;
948 if (typeof fun != "function")
949 throw new TypeError();
951 var res = new Array(len);
952 var thisp = arguments[1];
953 for (var i = 0; i < len; i++)
956 res[i] = fun.call(thisp, this[i], i, this);
967 * Ext JS Library 1.1.1
968 * Copyright(c) 2006-2007, Ext JS, LLC.
970 * Originally Released Under LGPL - original licence link has changed is not relivant.
973 * <script type="text/javascript">
979 * The date parsing and format syntax is a subset of
980 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
981 * supported will provide results equivalent to their PHP versions.
983 * Following is the list of all currently supported formats:
986 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
988 Format Output Description
989 ------ ---------- --------------------------------------------------------------
990 d 10 Day of the month, 2 digits with leading zeros
991 D Wed A textual representation of a day, three letters
992 j 10 Day of the month without leading zeros
993 l Wednesday A full textual representation of the day of the week
994 S th English ordinal day of month suffix, 2 chars (use with j)
995 w 3 Numeric representation of the day of the week
996 z 9 The julian date, or day of the year (0-365)
997 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
998 F January A full textual representation of the month
999 m 01 Numeric representation of a month, with leading zeros
1000 M Jan Month name abbreviation, three letters
1001 n 1 Numeric representation of a month, without leading zeros
1002 t 31 Number of days in the given month
1003 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1004 Y 2007 A full numeric representation of a year, 4 digits
1005 y 07 A two digit representation of a year
1006 a pm Lowercase Ante meridiem and Post meridiem
1007 A PM Uppercase Ante meridiem and Post meridiem
1008 g 3 12-hour format of an hour without leading zeros
1009 G 15 24-hour format of an hour without leading zeros
1010 h 03 12-hour format of an hour with leading zeros
1011 H 15 24-hour format of an hour with leading zeros
1012 i 05 Minutes with leading zeros
1013 s 01 Seconds, with leading zeros
1014 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1015 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1016 T CST Timezone setting of the machine running the code
1017 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1020 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1022 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1023 document.write(dt.format('Y-m-d')); //2007-01-10
1024 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1025 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
1028 * Here are some standard date/time patterns that you might find helpful. They
1029 * are not part of the source of Date.js, but to use them you can simply copy this
1030 * block of code into any script that is included after Date.js and they will also become
1031 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1034 ISO8601Long:"Y-m-d H:i:s",
1035 ISO8601Short:"Y-m-d",
1037 LongDate: "l, F d, Y",
1038 FullDateTime: "l, F d, Y g:i:s A",
1041 LongTime: "g:i:s A",
1042 SortableDateTime: "Y-m-d\\TH:i:s",
1043 UniversalSortableDateTime: "Y-m-d H:i:sO",
1050 var dt = new Date();
1051 document.write(dt.format(Date.patterns.ShortDate));
1056 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1057 * They generate precompiled functions from date formats instead of parsing and
1058 * processing the pattern every time you format a date. These functions are available
1059 * on every Date object (any javascript function).
1061 * The original article and download are here:
1062 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1069 Returns the number of milliseconds between this date and date
1070 @param {Date} date (optional) Defaults to now
1071 @return {Number} The diff in milliseconds
1072 @member Date getElapsed
1074 Date.prototype.getElapsed = function(date) {
1075 return Math.abs((date || new Date()).getTime()-this.getTime());
1077 // was in date file..
1081 Date.parseFunctions = {count:0};
1083 Date.parseRegexes = [];
1085 Date.formatFunctions = {count:0};
1088 Date.prototype.dateFormat = function(format) {
1089 if (Date.formatFunctions[format] == null) {
1090 Date.createNewFormat(format);
1092 var func = Date.formatFunctions[format];
1093 return this[func]();
1098 * Formats a date given the supplied format string
1099 * @param {String} format The format string
1100 * @return {String} The formatted date
1103 Date.prototype.format = Date.prototype.dateFormat;
1106 Date.createNewFormat = function(format) {
1107 var funcName = "format" + Date.formatFunctions.count++;
1108 Date.formatFunctions[format] = funcName;
1109 var code = "Date.prototype." + funcName + " = function(){return ";
1110 var special = false;
1112 for (var i = 0; i < format.length; ++i) {
1113 ch = format.charAt(i);
1114 if (!special && ch == "\\") {
1119 code += "'" + String.escape(ch) + "' + ";
1122 code += Date.getFormatCode(ch);
1125 /** eval:var:zzzzzzzzzzzzz */
1126 eval(code.substring(0, code.length - 3) + ";}");
1130 Date.getFormatCode = function(character) {
1131 switch (character) {
1133 return "String.leftPad(this.getDate(), 2, '0') + ";
1135 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1137 return "this.getDate() + ";
1139 return "Date.dayNames[this.getDay()] + ";
1141 return "this.getSuffix() + ";
1143 return "this.getDay() + ";
1145 return "this.getDayOfYear() + ";
1147 return "this.getWeekOfYear() + ";
1149 return "Date.monthNames[this.getMonth()] + ";
1151 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1153 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1155 return "(this.getMonth() + 1) + ";
1157 return "this.getDaysInMonth() + ";
1159 return "(this.isLeapYear() ? 1 : 0) + ";
1161 return "this.getFullYear() + ";
1163 return "('' + this.getFullYear()).substring(2, 4) + ";
1165 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1167 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1169 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1171 return "this.getHours() + ";
1173 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1175 return "String.leftPad(this.getHours(), 2, '0') + ";
1177 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1179 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1181 return "this.getGMTOffset() + ";
1183 return "this.getGMTColonOffset() + ";
1185 return "this.getTimezone() + ";
1187 return "(this.getTimezoneOffset() * -60) + ";
1189 return "'" + String.escape(character) + "' + ";
1194 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1195 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1196 * the date format that is not specified will default to the current date value for that part. Time parts can also
1197 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1198 * string or the parse operation will fail.
1201 //dt = Fri May 25 2007 (current date)
1202 var dt = new Date();
1204 //dt = Thu May 25 2006 (today's month/day in 2006)
1205 dt = Date.parseDate("2006", "Y");
1207 //dt = Sun Jan 15 2006 (all date parts specified)
1208 dt = Date.parseDate("2006-1-15", "Y-m-d");
1210 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1211 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1213 * @param {String} input The unparsed date as a string
1214 * @param {String} format The format the date is in
1215 * @return {Date} The parsed date
1218 Date.parseDate = function(input, format) {
1219 if (Date.parseFunctions[format] == null) {
1220 Date.createParser(format);
1222 var func = Date.parseFunctions[format];
1223 return Date[func](input);
1228 Date.createParser = function(format) {
1229 var funcName = "parse" + Date.parseFunctions.count++;
1230 var regexNum = Date.parseRegexes.length;
1231 var currentGroup = 1;
1232 Date.parseFunctions[format] = funcName;
1234 var code = "Date." + funcName + " = function(input){\n"
1235 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1236 + "var d = new Date();\n"
1237 + "y = d.getFullYear();\n"
1238 + "m = d.getMonth();\n"
1239 + "d = d.getDate();\n"
1240 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1241 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1242 + "if (results && results.length > 0) {";
1245 var special = false;
1247 for (var i = 0; i < format.length; ++i) {
1248 ch = format.charAt(i);
1249 if (!special && ch == "\\") {
1254 regex += String.escape(ch);
1257 var obj = Date.formatCodeToRegex(ch, currentGroup);
1258 currentGroup += obj.g;
1260 if (obj.g && obj.c) {
1266 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1267 + "{v = new Date(y, m, d, h, i, s);}\n"
1268 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1269 + "{v = new Date(y, m, d, h, i);}\n"
1270 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1271 + "{v = new Date(y, m, d, h);}\n"
1272 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1273 + "{v = new Date(y, m, d);}\n"
1274 + "else if (y >= 0 && m >= 0)\n"
1275 + "{v = new Date(y, m);}\n"
1276 + "else if (y >= 0)\n"
1277 + "{v = new Date(y);}\n"
1278 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1279 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1280 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1283 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1284 /** eval:var:zzzzzzzzzzzzz */
1289 Date.formatCodeToRegex = function(character, currentGroup) {
1290 switch (character) {
1294 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1297 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298 s:"(\\d{1,2})"}; // day of month without leading zeroes
1301 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1302 s:"(\\d{2})"}; // day of month with leading zeroes
1306 s:"(?:" + Date.dayNames.join("|") + ")"};
1310 s:"(?:st|nd|rd|th)"};
1325 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1326 s:"(" + Date.monthNames.join("|") + ")"};
1329 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1330 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1333 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1337 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1338 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1349 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1353 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1354 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1358 c:"if (results[" + currentGroup + "] == 'am') {\n"
1359 + "if (h == 12) { h = 0; }\n"
1360 + "} else { if (h < 12) { h += 12; }}",
1364 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1365 + "if (h == 12) { h = 0; }\n"
1366 + "} else { if (h < 12) { h += 12; }}",
1371 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1372 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1376 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1377 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1380 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1384 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1389 "o = results[", currentGroup, "];\n",
1390 "var sn = o.substring(0,1);\n", // get + / - sign
1391 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1392 "var mn = o.substring(3,5) % 60;\n", // get minutes
1393 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1394 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1396 s:"([+\-]\\d{2,4})"};
1402 "o = results[", currentGroup, "];\n",
1403 "var sn = o.substring(0,1);\n",
1404 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1405 "var mn = o.substring(4,6) % 60;\n",
1406 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1407 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1413 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1416 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1417 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1418 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1422 s:String.escape(character)};
1427 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1428 * @return {String} The abbreviated timezone name (e.g. 'CST')
1430 Date.prototype.getTimezone = function() {
1431 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1435 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1436 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1438 Date.prototype.getGMTOffset = function() {
1439 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1440 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1441 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1445 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1446 * @return {String} 2-characters representing hours and 2-characters representing minutes
1447 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1449 Date.prototype.getGMTColonOffset = function() {
1450 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1451 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1453 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1457 * Get the numeric day number of the year, adjusted for leap year.
1458 * @return {Number} 0 through 364 (365 in leap years)
1460 Date.prototype.getDayOfYear = function() {
1462 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1463 for (var i = 0; i < this.getMonth(); ++i) {
1464 num += Date.daysInMonth[i];
1466 return num + this.getDate() - 1;
1470 * Get the string representation of the numeric week number of the year
1471 * (equivalent to the format specifier 'W').
1472 * @return {String} '00' through '52'
1474 Date.prototype.getWeekOfYear = function() {
1475 // Skip to Thursday of this week
1476 var now = this.getDayOfYear() + (4 - this.getDay());
1477 // Find the first Thursday of the year
1478 var jan1 = new Date(this.getFullYear(), 0, 1);
1479 var then = (7 - jan1.getDay() + 4);
1480 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1484 * Whether or not the current date is in a leap year.
1485 * @return {Boolean} True if the current date is in a leap year, else false
1487 Date.prototype.isLeapYear = function() {
1488 var year = this.getFullYear();
1489 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1493 * Get the first day of the current month, adjusted for leap year. The returned value
1494 * is the numeric day index within the week (0-6) which can be used in conjunction with
1495 * the {@link #monthNames} array to retrieve the textual day name.
1498 var dt = new Date('1/10/2007');
1499 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1501 * @return {Number} The day number (0-6)
1503 Date.prototype.getFirstDayOfMonth = function() {
1504 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1505 return (day < 0) ? (day + 7) : day;
1509 * Get the last day of the current month, adjusted for leap year. The returned value
1510 * is the numeric day index within the week (0-6) which can be used in conjunction with
1511 * the {@link #monthNames} array to retrieve the textual day name.
1514 var dt = new Date('1/10/2007');
1515 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1517 * @return {Number} The day number (0-6)
1519 Date.prototype.getLastDayOfMonth = function() {
1520 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1521 return (day < 0) ? (day + 7) : day;
1526 * Get the first date of this date's month
1529 Date.prototype.getFirstDateOfMonth = function() {
1530 return new Date(this.getFullYear(), this.getMonth(), 1);
1534 * Get the last date of this date's month
1537 Date.prototype.getLastDateOfMonth = function() {
1538 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1541 * Get the number of days in the current month, adjusted for leap year.
1542 * @return {Number} The number of days in the month
1544 Date.prototype.getDaysInMonth = function() {
1545 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1546 return Date.daysInMonth[this.getMonth()];
1550 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1551 * @return {String} 'st, 'nd', 'rd' or 'th'
1553 Date.prototype.getSuffix = function() {
1554 switch (this.getDate()) {
1571 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1574 * An array of textual month names.
1575 * Override these values for international dates, for example...
1576 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1595 * An array of textual day names.
1596 * Override these values for international dates, for example...
1597 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1613 Date.monthNumbers = {
1628 * Creates and returns a new Date instance with the exact same date value as the called instance.
1629 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1630 * variable will also be changed. When the intention is to create a new variable that will not
1631 * modify the original instance, you should create a clone.
1633 * Example of correctly cloning a date:
1636 var orig = new Date('10/1/2006');
1639 document.write(orig); //returns 'Thu Oct 05 2006'!
1642 var orig = new Date('10/1/2006');
1643 var copy = orig.clone();
1645 document.write(orig); //returns 'Thu Oct 01 2006'
1647 * @return {Date} The new Date instance
1649 Date.prototype.clone = function() {
1650 return new Date(this.getTime());
1654 * Clears any time information from this date
1655 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1656 @return {Date} this or the clone
1658 Date.prototype.clearTime = function(clone){
1660 return this.clone().clearTime();
1665 this.setMilliseconds(0);
1670 // safari setMonth is broken
1672 Date.brokenSetMonth = Date.prototype.setMonth;
1673 Date.prototype.setMonth = function(num){
1675 var n = Math.ceil(-num);
1676 var back_year = Math.ceil(n/12);
1677 var month = (n % 12) ? 12 - n % 12 : 0 ;
1678 this.setFullYear(this.getFullYear() - back_year);
1679 return Date.brokenSetMonth.call(this, month);
1681 return Date.brokenSetMonth.apply(this, arguments);
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1706 /** Date interval constant
1710 /** Date interval constant
1716 * Provides a convenient method of performing basic date arithmetic. This method
1717 * does not modify the Date instance being called - it creates and returns
1718 * a new Date instance containing the resulting date value.
1723 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1724 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1726 //Negative values will subtract correctly:
1727 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1728 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1730 //You can even chain several calls together in one line!
1731 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1732 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1735 * @param {String} interval A valid date interval enum value
1736 * @param {Number} value The amount to add to the current date
1737 * @return {Date} The new Date instance
1739 Date.prototype.add = function(interval, value){
1740 var d = this.clone();
1741 if (!interval || value === 0) return d;
1742 switch(interval.toLowerCase()){
1744 d.setMilliseconds(this.getMilliseconds() + value);
1747 d.setSeconds(this.getSeconds() + value);
1750 d.setMinutes(this.getMinutes() + value);
1753 d.setHours(this.getHours() + value);
1756 d.setDate(this.getDate() + value);
1759 var day = this.getDate();
1761 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1764 d.setMonth(this.getMonth() + value);
1767 d.setFullYear(this.getFullYear() + value);
1774 * Ext JS Library 1.1.1
1775 * Copyright(c) 2006-2007, Ext JS, LLC.
1777 * Originally Released Under LGPL - original licence link has changed is not relivant.
1780 * <script type="text/javascript">
1784 * @class Roo.lib.Dom
1787 * Dom utils (from YIU afaik)
1792 * Get the view width
1793 * @param {Boolean} full True will get the full document, otherwise it's the view width
1794 * @return {Number} The width
1797 getViewWidth : function(full) {
1798 return full ? this.getDocumentWidth() : this.getViewportWidth();
1801 * Get the view height
1802 * @param {Boolean} full True will get the full document, otherwise it's the view height
1803 * @return {Number} The height
1805 getViewHeight : function(full) {
1806 return full ? this.getDocumentHeight() : this.getViewportHeight();
1809 getDocumentHeight: function() {
1810 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1811 return Math.max(scrollHeight, this.getViewportHeight());
1814 getDocumentWidth: function() {
1815 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1816 return Math.max(scrollWidth, this.getViewportWidth());
1819 getViewportHeight: function() {
1820 var height = self.innerHeight;
1821 var mode = document.compatMode;
1823 if ((mode || Roo.isIE) && !Roo.isOpera) {
1824 height = (mode == "CSS1Compat") ?
1825 document.documentElement.clientHeight :
1826 document.body.clientHeight;
1832 getViewportWidth: function() {
1833 var width = self.innerWidth;
1834 var mode = document.compatMode;
1836 if (mode || Roo.isIE) {
1837 width = (mode == "CSS1Compat") ?
1838 document.documentElement.clientWidth :
1839 document.body.clientWidth;
1844 isAncestor : function(p, c) {
1851 if (p.contains && !Roo.isSafari) {
1852 return p.contains(c);
1853 } else if (p.compareDocumentPosition) {
1854 return !!(p.compareDocumentPosition(c) & 16);
1856 var parent = c.parentNode;
1861 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1864 parent = parent.parentNode;
1870 getRegion : function(el) {
1871 return Roo.lib.Region.getRegion(el);
1874 getY : function(el) {
1875 return this.getXY(el)[1];
1878 getX : function(el) {
1879 return this.getXY(el)[0];
1882 getXY : function(el) {
1883 var p, pe, b, scroll, bd = document.body;
1884 el = Roo.getDom(el);
1885 var fly = Roo.lib.AnimBase.fly;
1886 if (el.getBoundingClientRect) {
1887 b = el.getBoundingClientRect();
1888 scroll = fly(document).getScroll();
1889 return [b.left + scroll.left, b.top + scroll.top];
1895 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1902 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1909 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1910 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1917 if (p != el && pe.getStyle('overflow') != 'visible') {
1925 if (Roo.isSafari && hasAbsolute) {
1930 if (Roo.isGecko && !hasAbsolute) {
1932 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1933 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1937 while (p && p != bd) {
1938 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1950 setXY : function(el, xy) {
1951 el = Roo.fly(el, '_setXY');
1953 var pts = el.translatePoints(xy);
1954 if (xy[0] !== false) {
1955 el.dom.style.left = pts.left + "px";
1957 if (xy[1] !== false) {
1958 el.dom.style.top = pts.top + "px";
1962 setX : function(el, x) {
1963 this.setXY(el, [x, false]);
1966 setY : function(el, y) {
1967 this.setXY(el, [false, y]);
1971 * Portions of this file are based on pieces of Yahoo User Interface Library
1972 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1973 * YUI licensed under the BSD License:
1974 * http://developer.yahoo.net/yui/license.txt
1975 * <script type="text/javascript">
1979 Roo.lib.Event = function() {
1980 var loadComplete = false;
1982 var unloadListeners = [];
1984 var onAvailStack = [];
1986 var lastError = null;
1999 startInterval: function() {
2000 if (!this._interval) {
2002 var callback = function() {
2003 self._tryPreloadAttach();
2005 this._interval = setInterval(callback, this.POLL_INTERVAL);
2010 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2011 onAvailStack.push({ id: p_id,
2014 override: p_override,
2015 checkReady: false });
2017 retryCount = this.POLL_RETRYS;
2018 this.startInterval();
2022 addListener: function(el, eventName, fn) {
2023 el = Roo.getDom(el);
2028 if ("unload" == eventName) {
2029 unloadListeners[unloadListeners.length] =
2030 [el, eventName, fn];
2034 var wrappedFn = function(e) {
2035 return fn(Roo.lib.Event.getEvent(e));
2038 var li = [el, eventName, fn, wrappedFn];
2040 var index = listeners.length;
2041 listeners[index] = li;
2043 this.doAdd(el, eventName, wrappedFn, false);
2049 removeListener: function(el, eventName, fn) {
2052 el = Roo.getDom(el);
2055 return this.purgeElement(el, false, eventName);
2059 if ("unload" == eventName) {
2061 for (i = 0,len = unloadListeners.length; i < len; i++) {
2062 var li = unloadListeners[i];
2065 li[1] == eventName &&
2067 unloadListeners.splice(i, 1);
2075 var cacheItem = null;
2078 var index = arguments[3];
2080 if ("undefined" == typeof index) {
2081 index = this._getCacheIndex(el, eventName, fn);
2085 cacheItem = listeners[index];
2088 if (!el || !cacheItem) {
2092 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2094 delete listeners[index][this.WFN];
2095 delete listeners[index][this.FN];
2096 listeners.splice(index, 1);
2103 getTarget: function(ev, resolveTextNode) {
2104 ev = ev.browserEvent || ev;
2105 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2106 var t = ev.target || ev.srcElement;
2107 return this.resolveTextNode(t);
2111 resolveTextNode: function(node) {
2112 if (Roo.isSafari && node && 3 == node.nodeType) {
2113 return node.parentNode;
2120 getPageX: function(ev) {
2121 ev = ev.browserEvent || ev;
2122 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2124 if (!x && 0 !== x) {
2125 x = ev.clientX || 0;
2128 x += this.getScroll()[1];
2136 getPageY: function(ev) {
2137 ev = ev.browserEvent || ev;
2138 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2140 if (!y && 0 !== y) {
2141 y = ev.clientY || 0;
2144 y += this.getScroll()[0];
2153 getXY: function(ev) {
2154 ev = ev.browserEvent || ev;
2155 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2156 return [this.getPageX(ev), this.getPageY(ev)];
2160 getRelatedTarget: function(ev) {
2161 ev = ev.browserEvent || ev;
2162 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2163 var t = ev.relatedTarget;
2165 if (ev.type == "mouseout") {
2167 } else if (ev.type == "mouseover") {
2172 return this.resolveTextNode(t);
2176 getTime: function(ev) {
2177 ev = ev.browserEvent || ev;
2178 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2180 var t = new Date().getTime();
2184 this.lastError = ex;
2193 stopEvent: function(ev) {
2194 this.stopPropagation(ev);
2195 this.preventDefault(ev);
2199 stopPropagation: function(ev) {
2200 ev = ev.browserEvent || ev;
2201 if (ev.stopPropagation) {
2202 ev.stopPropagation();
2204 ev.cancelBubble = true;
2209 preventDefault: function(ev) {
2210 ev = ev.browserEvent || ev;
2211 if(ev.preventDefault) {
2212 ev.preventDefault();
2214 ev.returnValue = false;
2219 getEvent: function(e) {
2220 var ev = e || window.event;
2222 var c = this.getEvent.caller;
2224 ev = c.arguments[0];
2225 if (ev && Event == ev.constructor) {
2235 getCharCode: function(ev) {
2236 ev = ev.browserEvent || ev;
2237 return ev.charCode || ev.keyCode || 0;
2241 _getCacheIndex: function(el, eventName, fn) {
2242 for (var i = 0,len = listeners.length; i < len; ++i) {
2243 var li = listeners[i];
2245 li[this.FN] == fn &&
2246 li[this.EL] == el &&
2247 li[this.TYPE] == eventName) {
2259 getEl: function(id) {
2260 return document.getElementById(id);
2264 clearCache: function() {
2268 _load: function(e) {
2269 loadComplete = true;
2270 var EU = Roo.lib.Event;
2274 EU.doRemove(window, "load", EU._load);
2279 _tryPreloadAttach: function() {
2288 var tryAgain = !loadComplete;
2290 tryAgain = (retryCount > 0);
2295 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2296 var item = onAvailStack[i];
2298 var el = this.getEl(item.id);
2301 if (!item.checkReady ||
2304 (document && document.body)) {
2307 if (item.override) {
2308 if (item.override === true) {
2311 scope = item.override;
2314 item.fn.call(scope, item.obj);
2315 onAvailStack[i] = null;
2318 notAvail.push(item);
2323 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2327 this.startInterval();
2329 clearInterval(this._interval);
2330 this._interval = null;
2333 this.locked = false;
2340 purgeElement: function(el, recurse, eventName) {
2341 var elListeners = this.getListeners(el, eventName);
2343 for (var i = 0,len = elListeners.length; i < len; ++i) {
2344 var l = elListeners[i];
2345 this.removeListener(el, l.type, l.fn);
2349 if (recurse && el && el.childNodes) {
2350 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2351 this.purgeElement(el.childNodes[i], recurse, eventName);
2357 getListeners: function(el, eventName) {
2358 var results = [], searchLists;
2360 searchLists = [listeners, unloadListeners];
2361 } else if (eventName == "unload") {
2362 searchLists = [unloadListeners];
2364 searchLists = [listeners];
2367 for (var j = 0; j < searchLists.length; ++j) {
2368 var searchList = searchLists[j];
2369 if (searchList && searchList.length > 0) {
2370 for (var i = 0,len = searchList.length; i < len; ++i) {
2371 var l = searchList[i];
2372 if (l && l[this.EL] === el &&
2373 (!eventName || eventName === l[this.TYPE])) {
2378 adjust: l[this.ADJ_SCOPE],
2386 return (results.length) ? results : null;
2390 _unload: function(e) {
2392 var EU = Roo.lib.Event, i, j, l, len, index;
2394 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2395 l = unloadListeners[i];
2398 if (l[EU.ADJ_SCOPE]) {
2399 if (l[EU.ADJ_SCOPE] === true) {
2402 scope = l[EU.ADJ_SCOPE];
2405 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2406 unloadListeners[i] = null;
2412 unloadListeners = null;
2414 if (listeners && listeners.length > 0) {
2415 j = listeners.length;
2418 l = listeners[index];
2420 EU.removeListener(l[EU.EL], l[EU.TYPE],
2430 EU.doRemove(window, "unload", EU._unload);
2435 getScroll: function() {
2436 var dd = document.documentElement, db = document.body;
2437 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2438 return [dd.scrollTop, dd.scrollLeft];
2440 return [db.scrollTop, db.scrollLeft];
2447 doAdd: function () {
2448 if (window.addEventListener) {
2449 return function(el, eventName, fn, capture) {
2450 el.addEventListener(eventName, fn, (capture));
2452 } else if (window.attachEvent) {
2453 return function(el, eventName, fn, capture) {
2454 el.attachEvent("on" + eventName, fn);
2463 doRemove: function() {
2464 if (window.removeEventListener) {
2465 return function (el, eventName, fn, capture) {
2466 el.removeEventListener(eventName, fn, (capture));
2468 } else if (window.detachEvent) {
2469 return function (el, eventName, fn) {
2470 el.detachEvent("on" + eventName, fn);
2482 var E = Roo.lib.Event;
2483 E.on = E.addListener;
2484 E.un = E.removeListener;
2486 if (document && document.body) {
2489 E.doAdd(window, "load", E._load);
2491 E.doAdd(window, "unload", E._unload);
2492 E._tryPreloadAttach();
2496 * Portions of this file are based on pieces of Yahoo User Interface Library
2497 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2498 * YUI licensed under the BSD License:
2499 * http://developer.yahoo.net/yui/license.txt
2500 * <script type="text/javascript">
2506 * @class Roo.lib.Ajax
2513 request : function(method, uri, cb, data, options) {
2515 var hs = options.headers;
2518 if(hs.hasOwnProperty(h)){
2519 this.initHeader(h, hs[h], false);
2523 if(options.xmlData){
2524 this.initHeader('Content-Type', 'text/xml', false);
2526 data = options.xmlData;
2530 return this.asyncRequest(method, uri, cb, data);
2533 serializeForm : function(form) {
2534 if(typeof form == 'string') {
2535 form = (document.getElementById(form) || document.forms[form]);
2538 var el, name, val, disabled, data = '', hasSubmit = false;
2539 for (var i = 0; i < form.elements.length; i++) {
2540 el = form.elements[i];
2541 disabled = form.elements[i].disabled;
2542 name = form.elements[i].name;
2543 val = form.elements[i].value;
2545 if (!disabled && name){
2549 case 'select-multiple':
2550 for (var j = 0; j < el.options.length; j++) {
2551 if (el.options[j].selected) {
2553 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2556 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2564 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2577 if(hasSubmit == false) {
2578 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2583 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2588 data = data.substr(0, data.length - 1);
2596 useDefaultHeader:true,
2598 defaultPostHeader:'application/x-www-form-urlencoded',
2600 useDefaultXhrHeader:true,
2602 defaultXhrHeader:'XMLHttpRequest',
2604 hasDefaultHeaders:true,
2616 setProgId:function(id)
2618 this.activeX.unshift(id);
2621 setDefaultPostHeader:function(b)
2623 this.useDefaultHeader = b;
2626 setDefaultXhrHeader:function(b)
2628 this.useDefaultXhrHeader = b;
2631 setPollingInterval:function(i)
2633 if (typeof i == 'number' && isFinite(i)) {
2634 this.pollInterval = i;
2638 createXhrObject:function(transactionId)
2644 http = new XMLHttpRequest();
2646 obj = { conn:http, tId:transactionId };
2650 for (var i = 0; i < this.activeX.length; ++i) {
2654 http = new ActiveXObject(this.activeX[i]);
2656 obj = { conn:http, tId:transactionId };
2669 getConnectionObject:function()
2672 var tId = this.transactionId;
2676 o = this.createXhrObject(tId);
2678 this.transactionId++;
2689 asyncRequest:function(method, uri, callback, postData)
2691 var o = this.getConnectionObject();
2697 o.conn.open(method, uri, true);
2699 if (this.useDefaultXhrHeader) {
2700 if (!this.defaultHeaders['X-Requested-With']) {
2701 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2705 if(postData && this.useDefaultHeader){
2706 this.initHeader('Content-Type', this.defaultPostHeader);
2709 if (this.hasDefaultHeaders || this.hasHeaders) {
2713 this.handleReadyState(o, callback);
2714 o.conn.send(postData || null);
2720 handleReadyState:function(o, callback)
2724 if (callback && callback.timeout) {
2726 this.timeout[o.tId] = window.setTimeout(function() {
2727 oConn.abort(o, callback, true);
2728 }, callback.timeout);
2731 this.poll[o.tId] = window.setInterval(
2733 if (o.conn && o.conn.readyState == 4) {
2734 window.clearInterval(oConn.poll[o.tId]);
2735 delete oConn.poll[o.tId];
2737 if(callback && callback.timeout) {
2738 window.clearTimeout(oConn.timeout[o.tId]);
2739 delete oConn.timeout[o.tId];
2742 oConn.handleTransactionResponse(o, callback);
2745 , this.pollInterval);
2748 handleTransactionResponse:function(o, callback, isAbort)
2752 this.releaseObject(o);
2756 var httpStatus, responseObject;
2760 if (o.conn.status !== undefined && o.conn.status != 0) {
2761 httpStatus = o.conn.status;
2773 if (httpStatus >= 200 && httpStatus < 300) {
2774 responseObject = this.createResponseObject(o, callback.argument);
2775 if (callback.success) {
2776 if (!callback.scope) {
2777 callback.success(responseObject);
2782 callback.success.apply(callback.scope, [responseObject]);
2787 switch (httpStatus) {
2795 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2796 if (callback.failure) {
2797 if (!callback.scope) {
2798 callback.failure(responseObject);
2801 callback.failure.apply(callback.scope, [responseObject]);
2806 responseObject = this.createResponseObject(o, callback.argument);
2807 if (callback.failure) {
2808 if (!callback.scope) {
2809 callback.failure(responseObject);
2812 callback.failure.apply(callback.scope, [responseObject]);
2818 this.releaseObject(o);
2819 responseObject = null;
2822 createResponseObject:function(o, callbackArg)
2829 var headerStr = o.conn.getAllResponseHeaders();
2830 var header = headerStr.split('\n');
2831 for (var i = 0; i < header.length; i++) {
2832 var delimitPos = header[i].indexOf(':');
2833 if (delimitPos != -1) {
2834 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2842 obj.status = o.conn.status;
2843 obj.statusText = o.conn.statusText;
2844 obj.getResponseHeader = headerObj;
2845 obj.getAllResponseHeaders = headerStr;
2846 obj.responseText = o.conn.responseText;
2847 obj.responseXML = o.conn.responseXML;
2849 if (typeof callbackArg !== undefined) {
2850 obj.argument = callbackArg;
2856 createExceptionObject:function(tId, callbackArg, isAbort)
2859 var COMM_ERROR = 'communication failure';
2860 var ABORT_CODE = -1;
2861 var ABORT_ERROR = 'transaction aborted';
2867 obj.status = ABORT_CODE;
2868 obj.statusText = ABORT_ERROR;
2871 obj.status = COMM_CODE;
2872 obj.statusText = COMM_ERROR;
2876 obj.argument = callbackArg;
2882 initHeader:function(label, value, isDefault)
2884 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2886 if (headerObj[label] === undefined) {
2887 headerObj[label] = value;
2892 headerObj[label] = value + "," + headerObj[label];
2896 this.hasDefaultHeaders = true;
2899 this.hasHeaders = true;
2904 setHeader:function(o)
2906 if (this.hasDefaultHeaders) {
2907 for (var prop in this.defaultHeaders) {
2908 if (this.defaultHeaders.hasOwnProperty(prop)) {
2909 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2914 if (this.hasHeaders) {
2915 for (var prop in this.headers) {
2916 if (this.headers.hasOwnProperty(prop)) {
2917 o.conn.setRequestHeader(prop, this.headers[prop]);
2921 this.hasHeaders = false;
2925 resetDefaultHeaders:function() {
2926 delete this.defaultHeaders;
2927 this.defaultHeaders = {};
2928 this.hasDefaultHeaders = false;
2931 abort:function(o, callback, isTimeout)
2933 if(this.isCallInProgress(o)) {
2935 window.clearInterval(this.poll[o.tId]);
2936 delete this.poll[o.tId];
2938 delete this.timeout[o.tId];
2941 this.handleTransactionResponse(o, callback, true);
2951 isCallInProgress:function(o)
2954 return o.conn.readyState != 4 && o.conn.readyState != 0;
2963 releaseObject:function(o)
2972 'MSXML2.XMLHTTP.3.0',
2980 * Portions of this file are based on pieces of Yahoo User Interface Library
2981 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2982 * YUI licensed under the BSD License:
2983 * http://developer.yahoo.net/yui/license.txt
2984 * <script type="text/javascript">
2988 Roo.lib.Region = function(t, r, b, l) {
2998 Roo.lib.Region.prototype = {
2999 contains : function(region) {
3000 return ( region.left >= this.left &&
3001 region.right <= this.right &&
3002 region.top >= this.top &&
3003 region.bottom <= this.bottom );
3007 getArea : function() {
3008 return ( (this.bottom - this.top) * (this.right - this.left) );
3011 intersect : function(region) {
3012 var t = Math.max(this.top, region.top);
3013 var r = Math.min(this.right, region.right);
3014 var b = Math.min(this.bottom, region.bottom);
3015 var l = Math.max(this.left, region.left);
3017 if (b >= t && r >= l) {
3018 return new Roo.lib.Region(t, r, b, l);
3023 union : function(region) {
3024 var t = Math.min(this.top, region.top);
3025 var r = Math.max(this.right, region.right);
3026 var b = Math.max(this.bottom, region.bottom);
3027 var l = Math.min(this.left, region.left);
3029 return new Roo.lib.Region(t, r, b, l);
3032 adjust : function(t, l, b, r) {
3041 Roo.lib.Region.getRegion = function(el) {
3042 var p = Roo.lib.Dom.getXY(el);
3045 var r = p[0] + el.offsetWidth;
3046 var b = p[1] + el.offsetHeight;
3049 return new Roo.lib.Region(t, r, b, l);
3052 * Portions of this file are based on pieces of Yahoo User Interface Library
3053 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3054 * YUI licensed under the BSD License:
3055 * http://developer.yahoo.net/yui/license.txt
3056 * <script type="text/javascript">
3059 //@@dep Roo.lib.Region
3062 Roo.lib.Point = function(x, y) {
3063 if (x instanceof Array) {
3067 this.x = this.right = this.left = this[0] = x;
3068 this.y = this.top = this.bottom = this[1] = y;
3071 Roo.lib.Point.prototype = new Roo.lib.Region();
3073 * Portions of this file are based on pieces of Yahoo User Interface Library
3074 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3075 * YUI licensed under the BSD License:
3076 * http://developer.yahoo.net/yui/license.txt
3077 * <script type="text/javascript">
3084 scroll : function(el, args, duration, easing, cb, scope) {
3085 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3088 motion : function(el, args, duration, easing, cb, scope) {
3089 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3092 color : function(el, args, duration, easing, cb, scope) {
3093 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3096 run : function(el, args, duration, easing, cb, scope, type) {
3097 type = type || Roo.lib.AnimBase;
3098 if (typeof easing == "string") {
3099 easing = Roo.lib.Easing[easing];
3101 var anim = new type(el, args, duration, easing);
3102 anim.animateX(function() {
3103 Roo.callback(cb, scope);
3109 * Portions of this file are based on pieces of Yahoo User Interface Library
3110 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3111 * YUI licensed under the BSD License:
3112 * http://developer.yahoo.net/yui/license.txt
3113 * <script type="text/javascript">
3121 if (!libFlyweight) {
3122 libFlyweight = new Roo.Element.Flyweight();
3124 libFlyweight.dom = el;
3125 return libFlyweight;
3128 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3132 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3134 this.init(el, attributes, duration, method);
3138 Roo.lib.AnimBase.fly = fly;
3142 Roo.lib.AnimBase.prototype = {
3144 toString: function() {
3145 var el = this.getEl();
3146 var id = el.id || el.tagName;
3147 return ("Anim " + id);
3151 noNegatives: /width|height|opacity|padding/i,
3152 offsetAttribute: /^((width|height)|(top|left))$/,
3153 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3154 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3158 doMethod: function(attr, start, end) {
3159 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3163 setAttribute: function(attr, val, unit) {
3164 if (this.patterns.noNegatives.test(attr)) {
3165 val = (val > 0) ? val : 0;
3168 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3172 getAttribute: function(attr) {
3173 var el = this.getEl();
3174 var val = fly(el).getStyle(attr);
3176 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3177 return parseFloat(val);
3180 var a = this.patterns.offsetAttribute.exec(attr) || [];
3181 var pos = !!( a[3] );
3182 var box = !!( a[2] );
3185 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3186 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3195 getDefaultUnit: function(attr) {
3196 if (this.patterns.defaultUnit.test(attr)) {
3203 animateX : function(callback, scope) {
3204 var f = function() {
3205 this.onComplete.removeListener(f);
3206 if (typeof callback == "function") {
3207 callback.call(scope || this, this);
3210 this.onComplete.addListener(f, this);
3215 setRuntimeAttribute: function(attr) {
3218 var attributes = this.attributes;
3220 this.runtimeAttributes[attr] = {};
3222 var isset = function(prop) {
3223 return (typeof prop !== 'undefined');
3226 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3230 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3233 if (isset(attributes[attr]['to'])) {
3234 end = attributes[attr]['to'];
3235 } else if (isset(attributes[attr]['by'])) {
3236 if (start.constructor == Array) {
3238 for (var i = 0, len = start.length; i < len; ++i) {
3239 end[i] = start[i] + attributes[attr]['by'][i];
3242 end = start + attributes[attr]['by'];
3246 this.runtimeAttributes[attr].start = start;
3247 this.runtimeAttributes[attr].end = end;
3250 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3254 init: function(el, attributes, duration, method) {
3256 var isAnimated = false;
3259 var startTime = null;
3262 var actualFrames = 0;
3265 el = Roo.getDom(el);
3268 this.attributes = attributes || {};
3271 this.duration = duration || 1;
3274 this.method = method || Roo.lib.Easing.easeNone;
3277 this.useSeconds = true;
3280 this.currentFrame = 0;
3283 this.totalFrames = Roo.lib.AnimMgr.fps;
3286 this.getEl = function() {
3291 this.isAnimated = function() {
3296 this.getStartTime = function() {
3300 this.runtimeAttributes = {};
3303 this.animate = function() {
3304 if (this.isAnimated()) {
3308 this.currentFrame = 0;
3310 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3312 Roo.lib.AnimMgr.registerElement(this);
3316 this.stop = function(finish) {
3318 this.currentFrame = this.totalFrames;
3319 this._onTween.fire();
3321 Roo.lib.AnimMgr.stop(this);
3324 var onStart = function() {
3325 this.onStart.fire();
3327 this.runtimeAttributes = {};
3328 for (var attr in this.attributes) {
3329 this.setRuntimeAttribute(attr);
3334 startTime = new Date();
3338 var onTween = function() {
3340 duration: new Date() - this.getStartTime(),
3341 currentFrame: this.currentFrame
3344 data.toString = function() {
3346 'duration: ' + data.duration +
3347 ', currentFrame: ' + data.currentFrame
3351 this.onTween.fire(data);
3353 var runtimeAttributes = this.runtimeAttributes;
3355 for (var attr in runtimeAttributes) {
3356 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3362 var onComplete = function() {
3363 var actual_duration = (new Date() - startTime) / 1000 ;
3366 duration: actual_duration,
3367 frames: actualFrames,
3368 fps: actualFrames / actual_duration
3371 data.toString = function() {
3373 'duration: ' + data.duration +
3374 ', frames: ' + data.frames +
3375 ', fps: ' + data.fps
3381 this.onComplete.fire(data);
3385 this._onStart = new Roo.util.Event(this);
3386 this.onStart = new Roo.util.Event(this);
3387 this.onTween = new Roo.util.Event(this);
3388 this._onTween = new Roo.util.Event(this);
3389 this.onComplete = new Roo.util.Event(this);
3390 this._onComplete = new Roo.util.Event(this);
3391 this._onStart.addListener(onStart);
3392 this._onTween.addListener(onTween);
3393 this._onComplete.addListener(onComplete);
3398 * Portions of this file are based on pieces of Yahoo User Interface Library
3399 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3400 * YUI licensed under the BSD License:
3401 * http://developer.yahoo.net/yui/license.txt
3402 * <script type="text/javascript">
3406 Roo.lib.AnimMgr = new function() {
3423 this.registerElement = function(tween) {
3424 queue[queue.length] = tween;
3426 tween._onStart.fire();
3431 this.unRegister = function(tween, index) {
3432 tween._onComplete.fire();
3433 index = index || getIndex(tween);
3435 queue.splice(index, 1);
3439 if (tweenCount <= 0) {
3445 this.start = function() {
3446 if (thread === null) {
3447 thread = setInterval(this.run, this.delay);
3452 this.stop = function(tween) {
3454 clearInterval(thread);
3456 for (var i = 0, len = queue.length; i < len; ++i) {
3457 if (queue[0].isAnimated()) {
3458 this.unRegister(queue[0], 0);
3467 this.unRegister(tween);
3472 this.run = function() {
3473 for (var i = 0, len = queue.length; i < len; ++i) {
3474 var tween = queue[i];
3475 if (!tween || !tween.isAnimated()) {
3479 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3481 tween.currentFrame += 1;
3483 if (tween.useSeconds) {
3484 correctFrame(tween);
3486 tween._onTween.fire();
3489 Roo.lib.AnimMgr.stop(tween, i);
3494 var getIndex = function(anim) {
3495 for (var i = 0, len = queue.length; i < len; ++i) {
3496 if (queue[i] == anim) {
3504 var correctFrame = function(tween) {
3505 var frames = tween.totalFrames;
3506 var frame = tween.currentFrame;
3507 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3508 var elapsed = (new Date() - tween.getStartTime());
3511 if (elapsed < tween.duration * 1000) {
3512 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3514 tweak = frames - (frame + 1);
3516 if (tweak > 0 && isFinite(tweak)) {
3517 if (tween.currentFrame + tweak >= frames) {
3518 tweak = frames - (frame + 1);
3521 tween.currentFrame += tweak;
3527 * Portions of this file are based on pieces of Yahoo User Interface Library
3528 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3529 * YUI licensed under the BSD License:
3530 * http://developer.yahoo.net/yui/license.txt
3531 * <script type="text/javascript">
3534 Roo.lib.Bezier = new function() {
3536 this.getPosition = function(points, t) {
3537 var n = points.length;
3540 for (var i = 0; i < n; ++i) {
3541 tmp[i] = [points[i][0], points[i][1]];
3544 for (var j = 1; j < n; ++j) {
3545 for (i = 0; i < n - j; ++i) {
3546 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3547 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3551 return [ tmp[0][0], tmp[0][1] ];
3555 * Portions of this file are based on pieces of Yahoo User Interface Library
3556 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557 * YUI licensed under the BSD License:
3558 * http://developer.yahoo.net/yui/license.txt
3559 * <script type="text/javascript">
3564 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3565 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3568 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3570 var fly = Roo.lib.AnimBase.fly;
3572 var superclass = Y.ColorAnim.superclass;
3573 var proto = Y.ColorAnim.prototype;
3575 proto.toString = function() {
3576 var el = this.getEl();
3577 var id = el.id || el.tagName;
3578 return ("ColorAnim " + id);
3581 proto.patterns.color = /color$/i;
3582 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3583 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3584 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3585 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3588 proto.parseColor = function(s) {
3589 if (s.length == 3) {
3593 var c = this.patterns.hex.exec(s);
3594 if (c && c.length == 4) {
3595 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3598 c = this.patterns.rgb.exec(s);
3599 if (c && c.length == 4) {
3600 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3603 c = this.patterns.hex3.exec(s);
3604 if (c && c.length == 4) {
3605 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3610 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3611 proto.getAttribute = function(attr) {
3612 var el = this.getEl();
3613 if (this.patterns.color.test(attr)) {
3614 var val = fly(el).getStyle(attr);
3616 if (this.patterns.transparent.test(val)) {
3617 var parent = el.parentNode;
3618 val = fly(parent).getStyle(attr);
3620 while (parent && this.patterns.transparent.test(val)) {
3621 parent = parent.parentNode;
3622 val = fly(parent).getStyle(attr);
3623 if (parent.tagName.toUpperCase() == 'HTML') {
3629 val = superclass.getAttribute.call(this, attr);
3634 proto.getAttribute = function(attr) {
3635 var el = this.getEl();
3636 if (this.patterns.color.test(attr)) {
3637 var val = fly(el).getStyle(attr);
3639 if (this.patterns.transparent.test(val)) {
3640 var parent = el.parentNode;
3641 val = fly(parent).getStyle(attr);
3643 while (parent && this.patterns.transparent.test(val)) {
3644 parent = parent.parentNode;
3645 val = fly(parent).getStyle(attr);
3646 if (parent.tagName.toUpperCase() == 'HTML') {
3652 val = superclass.getAttribute.call(this, attr);
3658 proto.doMethod = function(attr, start, end) {
3661 if (this.patterns.color.test(attr)) {
3663 for (var i = 0, len = start.length; i < len; ++i) {
3664 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3667 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3670 val = superclass.doMethod.call(this, attr, start, end);
3676 proto.setRuntimeAttribute = function(attr) {
3677 superclass.setRuntimeAttribute.call(this, attr);
3679 if (this.patterns.color.test(attr)) {
3680 var attributes = this.attributes;
3681 var start = this.parseColor(this.runtimeAttributes[attr].start);
3682 var end = this.parseColor(this.runtimeAttributes[attr].end);
3684 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3685 end = this.parseColor(attributes[attr].by);
3687 for (var i = 0, len = start.length; i < len; ++i) {
3688 end[i] = start[i] + end[i];
3692 this.runtimeAttributes[attr].start = start;
3693 this.runtimeAttributes[attr].end = end;
3699 * Portions of this file are based on pieces of Yahoo User Interface Library
3700 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3701 * YUI licensed under the BSD License:
3702 * http://developer.yahoo.net/yui/license.txt
3703 * <script type="text/javascript">
3709 easeNone: function (t, b, c, d) {
3710 return c * t / d + b;
3714 easeIn: function (t, b, c, d) {
3715 return c * (t /= d) * t + b;
3719 easeOut: function (t, b, c, d) {
3720 return -c * (t /= d) * (t - 2) + b;
3724 easeBoth: function (t, b, c, d) {
3725 if ((t /= d / 2) < 1) {
3726 return c / 2 * t * t + b;
3729 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3733 easeInStrong: function (t, b, c, d) {
3734 return c * (t /= d) * t * t * t + b;
3738 easeOutStrong: function (t, b, c, d) {
3739 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3743 easeBothStrong: function (t, b, c, d) {
3744 if ((t /= d / 2) < 1) {
3745 return c / 2 * t * t * t * t + b;
3748 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3753 elasticIn: function (t, b, c, d, a, p) {
3757 if ((t /= d) == 1) {
3764 if (!a || a < Math.abs(c)) {
3769 var s = p / (2 * Math.PI) * Math.asin(c / a);
3772 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3776 elasticOut: function (t, b, c, d, a, p) {
3780 if ((t /= d) == 1) {
3787 if (!a || a < Math.abs(c)) {
3792 var s = p / (2 * Math.PI) * Math.asin(c / a);
3795 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3799 elasticBoth: function (t, b, c, d, a, p) {
3804 if ((t /= d / 2) == 2) {
3812 if (!a || a < Math.abs(c)) {
3817 var s = p / (2 * Math.PI) * Math.asin(c / a);
3821 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3822 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3824 return a * Math.pow(2, -10 * (t -= 1)) *
3825 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3830 backIn: function (t, b, c, d, s) {
3831 if (typeof s == 'undefined') {
3834 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3838 backOut: function (t, b, c, d, s) {
3839 if (typeof s == 'undefined') {
3842 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3846 backBoth: function (t, b, c, d, s) {
3847 if (typeof s == 'undefined') {
3851 if ((t /= d / 2 ) < 1) {
3852 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3854 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3858 bounceIn: function (t, b, c, d) {
3859 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3863 bounceOut: function (t, b, c, d) {
3864 if ((t /= d) < (1 / 2.75)) {
3865 return c * (7.5625 * t * t) + b;
3866 } else if (t < (2 / 2.75)) {
3867 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3868 } else if (t < (2.5 / 2.75)) {
3869 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3871 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3875 bounceBoth: function (t, b, c, d) {
3877 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3879 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3882 * Portions of this file are based on pieces of Yahoo User Interface Library
3883 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3884 * YUI licensed under the BSD License:
3885 * http://developer.yahoo.net/yui/license.txt
3886 * <script type="text/javascript">
3890 Roo.lib.Motion = function(el, attributes, duration, method) {
3892 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3896 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3900 var superclass = Y.Motion.superclass;
3901 var proto = Y.Motion.prototype;
3903 proto.toString = function() {
3904 var el = this.getEl();
3905 var id = el.id || el.tagName;
3906 return ("Motion " + id);
3909 proto.patterns.points = /^points$/i;
3911 proto.setAttribute = function(attr, val, unit) {
3912 if (this.patterns.points.test(attr)) {
3913 unit = unit || 'px';
3914 superclass.setAttribute.call(this, 'left', val[0], unit);
3915 superclass.setAttribute.call(this, 'top', val[1], unit);
3917 superclass.setAttribute.call(this, attr, val, unit);
3921 proto.getAttribute = function(attr) {
3922 if (this.patterns.points.test(attr)) {
3924 superclass.getAttribute.call(this, 'left'),
3925 superclass.getAttribute.call(this, 'top')
3928 val = superclass.getAttribute.call(this, attr);
3934 proto.doMethod = function(attr, start, end) {
3937 if (this.patterns.points.test(attr)) {
3938 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3939 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3941 val = superclass.doMethod.call(this, attr, start, end);
3946 proto.setRuntimeAttribute = function(attr) {
3947 if (this.patterns.points.test(attr)) {
3948 var el = this.getEl();
3949 var attributes = this.attributes;
3951 var control = attributes['points']['control'] || [];
3955 if (control.length > 0 && !(control[0] instanceof Array)) {
3956 control = [control];
3959 for (i = 0,len = control.length; i < len; ++i) {
3960 tmp[i] = control[i];
3965 Roo.fly(el).position();
3967 if (isset(attributes['points']['from'])) {
3968 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3971 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3974 start = this.getAttribute('points');
3977 if (isset(attributes['points']['to'])) {
3978 end = translateValues.call(this, attributes['points']['to'], start);
3980 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3981 for (i = 0,len = control.length; i < len; ++i) {
3982 control[i] = translateValues.call(this, control[i], start);
3986 } else if (isset(attributes['points']['by'])) {
3987 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3989 for (i = 0,len = control.length; i < len; ++i) {
3990 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3994 this.runtimeAttributes[attr] = [start];
3996 if (control.length > 0) {
3997 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4000 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4003 superclass.setRuntimeAttribute.call(this, attr);
4007 var translateValues = function(val, start) {
4008 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4014 var isset = function(prop) {
4015 return (typeof prop !== 'undefined');
4019 * Portions of this file are based on pieces of Yahoo User Interface Library
4020 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4021 * YUI licensed under the BSD License:
4022 * http://developer.yahoo.net/yui/license.txt
4023 * <script type="text/javascript">
4027 Roo.lib.Scroll = function(el, attributes, duration, method) {
4029 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4033 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4037 var superclass = Y.Scroll.superclass;
4038 var proto = Y.Scroll.prototype;
4040 proto.toString = function() {
4041 var el = this.getEl();
4042 var id = el.id || el.tagName;
4043 return ("Scroll " + id);
4046 proto.doMethod = function(attr, start, end) {
4049 if (attr == 'scroll') {
4051 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4052 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4056 val = superclass.doMethod.call(this, attr, start, end);
4061 proto.getAttribute = function(attr) {
4063 var el = this.getEl();
4065 if (attr == 'scroll') {
4066 val = [ el.scrollLeft, el.scrollTop ];
4068 val = superclass.getAttribute.call(this, attr);
4074 proto.setAttribute = function(attr, val, unit) {
4075 var el = this.getEl();
4077 if (attr == 'scroll') {
4078 el.scrollLeft = val[0];
4079 el.scrollTop = val[1];
4081 superclass.setAttribute.call(this, attr, val, unit);
4087 * Ext JS Library 1.1.1
4088 * Copyright(c) 2006-2007, Ext JS, LLC.
4090 * Originally Released Under LGPL - original licence link has changed is not relivant.
4093 * <script type="text/javascript">
4097 // nasty IE9 hack - what a pile of crap that is..
4099 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4100 Range.prototype.createContextualFragment = function (html) {
4101 var doc = window.document;
4102 var container = doc.createElement("div");
4103 container.innerHTML = html;
4104 var frag = doc.createDocumentFragment(), n;
4105 while ((n = container.firstChild)) {
4106 frag.appendChild(n);
4113 * @class Roo.DomHelper
4114 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4115 * 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>.
4118 Roo.DomHelper = function(){
4119 var tempTableEl = null;
4120 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4121 var tableRe = /^table|tbody|tr|td$/i;
4123 // build as innerHTML where available
4125 var createHtml = function(o){
4126 if(typeof o == 'string'){
4135 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4136 if(attr == "style"){
4138 if(typeof s == "function"){
4141 if(typeof s == "string"){
4142 b += ' style="' + s + '"';
4143 }else if(typeof s == "object"){
4146 if(typeof s[key] != "function"){
4147 b += key + ":" + s[key] + ";";
4154 b += ' class="' + o["cls"] + '"';
4155 }else if(attr == "htmlFor"){
4156 b += ' for="' + o["htmlFor"] + '"';
4158 b += " " + attr + '="' + o[attr] + '"';
4162 if(emptyTags.test(o.tag)){
4166 var cn = o.children || o.cn;
4168 //http://bugs.kde.org/show_bug.cgi?id=71506
4169 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4170 for(var i = 0, len = cn.length; i < len; i++) {
4171 b += createHtml(cn[i], b);
4174 b += createHtml(cn, b);
4180 b += "</" + o.tag + ">";
4187 var createDom = function(o, parentNode){
4189 // defininition craeted..
4191 if (o.ns && o.ns != 'html') {
4193 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4194 xmlns[o.ns] = o.xmlns;
4197 if (typeof(xmlns[o.ns]) == 'undefined') {
4198 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4204 if (typeof(o) == 'string') {
4205 return parentNode.appendChild(document.createTextNode(o));
4207 o.tag = o.tag || div;
4208 if (o.ns && Roo.isIE) {
4210 o.tag = o.ns + ':' + o.tag;
4213 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4214 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4217 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4218 attr == "style" || typeof o[attr] == "function") continue;
4220 if(attr=="cls" && Roo.isIE){
4221 el.className = o["cls"];
4223 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4224 else el[attr] = o[attr];
4227 Roo.DomHelper.applyStyles(el, o.style);
4228 var cn = o.children || o.cn;
4230 //http://bugs.kde.org/show_bug.cgi?id=71506
4231 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4232 for(var i = 0, len = cn.length; i < len; i++) {
4233 createDom(cn[i], el);
4240 el.innerHTML = o.html;
4243 parentNode.appendChild(el);
4248 var ieTable = function(depth, s, h, e){
4249 tempTableEl.innerHTML = [s, h, e].join('');
4250 var i = -1, el = tempTableEl;
4257 // kill repeat to save bytes
4261 tbe = '</tbody>'+te,
4267 * Nasty code for IE's broken table implementation
4269 var insertIntoTable = function(tag, where, el, html){
4271 tempTableEl = document.createElement('div');
4276 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4279 if(where == 'beforebegin'){
4283 before = el.nextSibling;
4286 node = ieTable(4, trs, html, tre);
4288 else if(tag == 'tr'){
4289 if(where == 'beforebegin'){
4292 node = ieTable(3, tbs, html, tbe);
4293 } else if(where == 'afterend'){
4294 before = el.nextSibling;
4296 node = ieTable(3, tbs, html, tbe);
4297 } else{ // INTO a TR
4298 if(where == 'afterbegin'){
4299 before = el.firstChild;
4301 node = ieTable(4, trs, html, tre);
4303 } else if(tag == 'tbody'){
4304 if(where == 'beforebegin'){
4307 node = ieTable(2, ts, html, te);
4308 } else if(where == 'afterend'){
4309 before = el.nextSibling;
4311 node = ieTable(2, ts, html, te);
4313 if(where == 'afterbegin'){
4314 before = el.firstChild;
4316 node = ieTable(3, tbs, html, tbe);
4319 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4322 if(where == 'afterbegin'){
4323 before = el.firstChild;
4325 node = ieTable(2, ts, html, te);
4327 el.insertBefore(node, before);
4332 /** True to force the use of DOM instead of html fragments @type Boolean */
4336 * Returns the markup for the passed Element(s) config
4337 * @param {Object} o The Dom object spec (and children)
4340 markup : function(o){
4341 return createHtml(o);
4345 * Applies a style specification to an element
4346 * @param {String/HTMLElement} el The element to apply styles to
4347 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4348 * a function which returns such a specification.
4350 applyStyles : function(el, styles){
4353 if(typeof styles == "string"){
4354 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4356 while ((matches = re.exec(styles)) != null){
4357 el.setStyle(matches[1], matches[2]);
4359 }else if (typeof styles == "object"){
4360 for (var style in styles){
4361 el.setStyle(style, styles[style]);
4363 }else if (typeof styles == "function"){
4364 Roo.DomHelper.applyStyles(el, styles.call());
4370 * Inserts an HTML fragment into the Dom
4371 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4372 * @param {HTMLElement} el The context element
4373 * @param {String} html The HTML fragmenet
4374 * @return {HTMLElement} The new node
4376 insertHtml : function(where, el, html){
4377 where = where.toLowerCase();
4378 if(el.insertAdjacentHTML){
4379 if(tableRe.test(el.tagName)){
4381 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4387 el.insertAdjacentHTML('BeforeBegin', html);
4388 return el.previousSibling;
4390 el.insertAdjacentHTML('AfterBegin', html);
4391 return el.firstChild;
4393 el.insertAdjacentHTML('BeforeEnd', html);
4394 return el.lastChild;
4396 el.insertAdjacentHTML('AfterEnd', html);
4397 return el.nextSibling;
4399 throw 'Illegal insertion point -> "' + where + '"';
4401 var range = el.ownerDocument.createRange();
4405 range.setStartBefore(el);
4406 frag = range.createContextualFragment(html);
4407 el.parentNode.insertBefore(frag, el);
4408 return el.previousSibling;
4411 range.setStartBefore(el.firstChild);
4412 frag = range.createContextualFragment(html);
4413 el.insertBefore(frag, el.firstChild);
4414 return el.firstChild;
4416 el.innerHTML = html;
4417 return el.firstChild;
4421 range.setStartAfter(el.lastChild);
4422 frag = range.createContextualFragment(html);
4423 el.appendChild(frag);
4424 return el.lastChild;
4426 el.innerHTML = html;
4427 return el.lastChild;
4430 range.setStartAfter(el);
4431 frag = range.createContextualFragment(html);
4432 el.parentNode.insertBefore(frag, el.nextSibling);
4433 return el.nextSibling;
4435 throw 'Illegal insertion point -> "' + where + '"';
4439 * Creates new Dom element(s) and inserts them before el
4440 * @param {String/HTMLElement/Element} el The context element
4441 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4442 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4443 * @return {HTMLElement/Roo.Element} The new node
4445 insertBefore : function(el, o, returnElement){
4446 return this.doInsert(el, o, returnElement, "beforeBegin");
4450 * Creates new Dom element(s) and inserts them after el
4451 * @param {String/HTMLElement/Element} el The context element
4452 * @param {Object} o The Dom object spec (and children)
4453 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4454 * @return {HTMLElement/Roo.Element} The new node
4456 insertAfter : function(el, o, returnElement){
4457 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4461 * Creates new Dom element(s) and inserts them as the first child of el
4462 * @param {String/HTMLElement/Element} el The context element
4463 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4464 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4465 * @return {HTMLElement/Roo.Element} The new node
4467 insertFirst : function(el, o, returnElement){
4468 return this.doInsert(el, o, returnElement, "afterBegin");
4472 doInsert : function(el, o, returnElement, pos, sibling){
4473 el = Roo.getDom(el);
4475 if(this.useDom || o.ns){
4476 newNode = createDom(o, null);
4477 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4479 var html = createHtml(o);
4480 newNode = this.insertHtml(pos, el, html);
4482 return returnElement ? Roo.get(newNode, true) : newNode;
4486 * Creates new Dom element(s) and appends them to el
4487 * @param {String/HTMLElement/Element} el The context element
4488 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4489 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4490 * @return {HTMLElement/Roo.Element} The new node
4492 append : function(el, o, returnElement){
4493 el = Roo.getDom(el);
4495 if(this.useDom || o.ns){
4496 newNode = createDom(o, null);
4497 el.appendChild(newNode);
4499 var html = createHtml(o);
4500 newNode = this.insertHtml("beforeEnd", el, html);
4502 return returnElement ? Roo.get(newNode, true) : newNode;
4506 * Creates new Dom element(s) and overwrites the contents of el with them
4507 * @param {String/HTMLElement/Element} el The context element
4508 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4509 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4510 * @return {HTMLElement/Roo.Element} The new node
4512 overwrite : function(el, o, returnElement){
4513 el = Roo.getDom(el);
4516 while (el.childNodes.length) {
4517 el.removeChild(el.firstChild);
4521 el.innerHTML = createHtml(o);
4524 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4528 * Creates a new Roo.DomHelper.Template from the Dom object spec
4529 * @param {Object} o The Dom object spec (and children)
4530 * @return {Roo.DomHelper.Template} The new template
4532 createTemplate : function(o){
4533 var html = createHtml(o);
4534 return new Roo.Template(html);
4540 * Ext JS Library 1.1.1
4541 * Copyright(c) 2006-2007, Ext JS, LLC.
4543 * Originally Released Under LGPL - original licence link has changed is not relivant.
4546 * <script type="text/javascript">
4550 * @class Roo.Template
4551 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4552 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4555 var t = new Roo.Template({
4556 html : '<div name="{id}">' +
4557 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4559 myformat: function (value, allValues) {
4560 return 'XX' + value;
4563 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4565 * For more information see this blog post with examples:
4566 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4567 - Create Elements using DOM, HTML fragments and Templates</a>.
4569 * @param {Object} cfg - Configuration object.
4571 Roo.Template = function(cfg){
4573 if(cfg instanceof Array){
4575 }else if(arguments.length > 1){
4576 cfg = Array.prototype.join.call(arguments, "");
4580 if (typeof(cfg) == 'object') {
4591 Roo.Template.prototype = {
4594 * @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..
4595 * it should be fixed so that template is observable...
4599 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4603 * Returns an HTML fragment of this template with the specified values applied.
4604 * @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'})
4605 * @return {String} The HTML fragment
4607 applyTemplate : function(values){
4611 return this.compiled(values);
4613 var useF = this.disableFormats !== true;
4614 var fm = Roo.util.Format, tpl = this;
4615 var fn = function(m, name, format, args){
4617 if(format.substr(0, 5) == "this."){
4618 return tpl.call(format.substr(5), values[name], values);
4621 // quoted values are required for strings in compiled templates,
4622 // but for non compiled we need to strip them
4623 // quoted reversed for jsmin
4624 var re = /^\s*['"](.*)["']\s*$/;
4625 args = args.split(',');
4626 for(var i = 0, len = args.length; i < len; i++){
4627 args[i] = args[i].replace(re, "$1");
4629 args = [values[name]].concat(args);
4631 args = [values[name]];
4633 return fm[format].apply(fm, args);
4636 return values[name] !== undefined ? values[name] : "";
4639 return this.html.replace(this.re, fn);
4657 this.loading = true;
4658 this.compiled = false;
4660 var cx = new Roo.data.Connection();
4664 success : function (response) {
4666 _t.html = response.responseText;
4670 failure : function(response) {
4671 Roo.log("Template failed to load from " + _t.url);
4678 * Sets the HTML used as the template and optionally compiles it.
4679 * @param {String} html
4680 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4681 * @return {Roo.Template} this
4683 set : function(html, compile){
4685 this.compiled = null;
4693 * True to disable format functions (defaults to false)
4696 disableFormats : false,
4699 * The regular expression used to match template variables
4703 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4706 * Compiles the template into an internal function, eliminating the RegEx overhead.
4707 * @return {Roo.Template} this
4709 compile : function(){
4710 var fm = Roo.util.Format;
4711 var useF = this.disableFormats !== true;
4712 var sep = Roo.isGecko ? "+" : ",";
4713 var fn = function(m, name, format, args){
4715 args = args ? ',' + args : "";
4716 if(format.substr(0, 5) != "this."){
4717 format = "fm." + format + '(';
4719 format = 'this.call("'+ format.substr(5) + '", ';
4723 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4725 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4728 // branched to use + in gecko and [].join() in others
4730 body = "this.compiled = function(values){ return '" +
4731 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4734 body = ["this.compiled = function(values){ return ['"];
4735 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4736 body.push("'].join('');};");
4737 body = body.join('');
4747 // private function used to call members
4748 call : function(fnName, value, allValues){
4749 return this[fnName](value, allValues);
4753 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4754 * @param {String/HTMLElement/Roo.Element} el The context element
4755 * @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'})
4756 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4757 * @return {HTMLElement/Roo.Element} The new node or Element
4759 insertFirst: function(el, values, returnElement){
4760 return this.doInsert('afterBegin', el, values, returnElement);
4764 * Applies the supplied values to the template and inserts the new node(s) before el.
4765 * @param {String/HTMLElement/Roo.Element} el The context element
4766 * @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'})
4767 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4768 * @return {HTMLElement/Roo.Element} The new node or Element
4770 insertBefore: function(el, values, returnElement){
4771 return this.doInsert('beforeBegin', el, values, returnElement);
4775 * Applies the supplied values to the template and inserts the new node(s) after el.
4776 * @param {String/HTMLElement/Roo.Element} el The context element
4777 * @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'})
4778 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4779 * @return {HTMLElement/Roo.Element} The new node or Element
4781 insertAfter : function(el, values, returnElement){
4782 return this.doInsert('afterEnd', el, values, returnElement);
4786 * Applies the supplied values to the template and appends the new node(s) to el.
4787 * @param {String/HTMLElement/Roo.Element} el The context element
4788 * @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'})
4789 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4790 * @return {HTMLElement/Roo.Element} The new node or Element
4792 append : function(el, values, returnElement){
4793 return this.doInsert('beforeEnd', el, values, returnElement);
4796 doInsert : function(where, el, values, returnEl){
4797 el = Roo.getDom(el);
4798 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4799 return returnEl ? Roo.get(newNode, true) : newNode;
4803 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4804 * @param {String/HTMLElement/Roo.Element} el The context element
4805 * @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'})
4806 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4807 * @return {HTMLElement/Roo.Element} The new node or Element
4809 overwrite : function(el, values, returnElement){
4810 el = Roo.getDom(el);
4811 el.innerHTML = this.applyTemplate(values);
4812 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4816 * Alias for {@link #applyTemplate}
4819 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4822 Roo.DomHelper.Template = Roo.Template;
4825 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4826 * @param {String/HTMLElement} el A DOM element or its id
4827 * @returns {Roo.Template} The created template
4830 Roo.Template.from = function(el){
4831 el = Roo.getDom(el);
4832 return new Roo.Template(el.value || el.innerHTML);
4835 * Ext JS Library 1.1.1
4836 * Copyright(c) 2006-2007, Ext JS, LLC.
4838 * Originally Released Under LGPL - original licence link has changed is not relivant.
4841 * <script type="text/javascript">
4846 * This is code is also distributed under MIT license for use
4847 * with jQuery and prototype JavaScript libraries.
4850 * @class Roo.DomQuery
4851 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).
4853 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>
4856 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.
4858 <h4>Element Selectors:</h4>
4860 <li> <b>*</b> any element</li>
4861 <li> <b>E</b> an element with the tag E</li>
4862 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4863 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4864 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4865 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4867 <h4>Attribute Selectors:</h4>
4868 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4870 <li> <b>E[foo]</b> has an attribute "foo"</li>
4871 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4872 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4873 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4874 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4875 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4876 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4878 <h4>Pseudo Classes:</h4>
4880 <li> <b>E:first-child</b> E is the first child of its parent</li>
4881 <li> <b>E:last-child</b> E is the last child of its parent</li>
4882 <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>
4883 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4884 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4885 <li> <b>E:only-child</b> E is the only child of its parent</li>
4886 <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>
4887 <li> <b>E:first</b> the first E in the resultset</li>
4888 <li> <b>E:last</b> the last E in the resultset</li>
4889 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4890 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4891 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4892 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4893 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4894 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4895 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4896 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4897 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4899 <h4>CSS Value Selectors:</h4>
4901 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4902 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4903 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4904 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4905 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4906 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4910 Roo.DomQuery = function(){
4911 var cache = {}, simpleCache = {}, valueCache = {};
4912 var nonSpace = /\S/;
4913 var trimRe = /^\s+|\s+$/g;
4914 var tplRe = /\{(\d+)\}/g;
4915 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4916 var tagTokenRe = /^(#)?([\w-\*]+)/;
4917 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4919 function child(p, index){
4921 var n = p.firstChild;
4923 if(n.nodeType == 1){
4934 while((n = n.nextSibling) && n.nodeType != 1);
4939 while((n = n.previousSibling) && n.nodeType != 1);
4943 function children(d){
4944 var n = d.firstChild, ni = -1;
4946 var nx = n.nextSibling;
4947 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4957 function byClassName(c, a, v){
4961 var r = [], ri = -1, cn;
4962 for(var i = 0, ci; ci = c[i]; i++){
4963 if((' '+ci.className+' ').indexOf(v) != -1){
4970 function attrValue(n, attr){
4971 if(!n.tagName && typeof n.length != "undefined"){
4980 if(attr == "class" || attr == "className"){
4983 return n.getAttribute(attr) || n[attr];
4987 function getNodes(ns, mode, tagName){
4988 var result = [], ri = -1, cs;
4992 tagName = tagName || "*";
4993 if(typeof ns.getElementsByTagName != "undefined"){
4997 for(var i = 0, ni; ni = ns[i]; i++){
4998 cs = ni.getElementsByTagName(tagName);
4999 for(var j = 0, ci; ci = cs[j]; j++){
5003 }else if(mode == "/" || mode == ">"){
5004 var utag = tagName.toUpperCase();
5005 for(var i = 0, ni, cn; ni = ns[i]; i++){
5006 cn = ni.children || ni.childNodes;
5007 for(var j = 0, cj; cj = cn[j]; j++){
5008 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5013 }else if(mode == "+"){
5014 var utag = tagName.toUpperCase();
5015 for(var i = 0, n; n = ns[i]; i++){
5016 while((n = n.nextSibling) && n.nodeType != 1);
5017 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5021 }else if(mode == "~"){
5022 for(var i = 0, n; n = ns[i]; i++){
5023 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5032 function concat(a, b){
5036 for(var i = 0, l = b.length; i < l; i++){
5042 function byTag(cs, tagName){
5043 if(cs.tagName || cs == document){
5049 var r = [], ri = -1;
5050 tagName = tagName.toLowerCase();
5051 for(var i = 0, ci; ci = cs[i]; i++){
5052 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5059 function byId(cs, attr, id){
5060 if(cs.tagName || cs == document){
5066 var r = [], ri = -1;
5067 for(var i = 0,ci; ci = cs[i]; i++){
5068 if(ci && ci.id == id){
5076 function byAttribute(cs, attr, value, op, custom){
5077 var r = [], ri = -1, st = custom=="{";
5078 var f = Roo.DomQuery.operators[op];
5079 for(var i = 0, ci; ci = cs[i]; i++){
5082 a = Roo.DomQuery.getStyle(ci, attr);
5084 else if(attr == "class" || attr == "className"){
5086 }else if(attr == "for"){
5088 }else if(attr == "href"){
5089 a = ci.getAttribute("href", 2);
5091 a = ci.getAttribute(attr);
5093 if((f && f(a, value)) || (!f && a)){
5100 function byPseudo(cs, name, value){
5101 return Roo.DomQuery.pseudos[name](cs, value);
5104 // This is for IE MSXML which does not support expandos.
5105 // IE runs the same speed using setAttribute, however FF slows way down
5106 // and Safari completely fails so they need to continue to use expandos.
5107 var isIE = window.ActiveXObject ? true : false;
5109 // this eval is stop the compressor from
5110 // renaming the variable to something shorter
5112 /** eval:var:batch */
5117 function nodupIEXml(cs){
5119 cs[0].setAttribute("_nodup", d);
5121 for(var i = 1, len = cs.length; i < len; i++){
5123 if(!c.getAttribute("_nodup") != d){
5124 c.setAttribute("_nodup", d);
5128 for(var i = 0, len = cs.length; i < len; i++){
5129 cs[i].removeAttribute("_nodup");
5138 var len = cs.length, c, i, r = cs, cj, ri = -1;
5139 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5142 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5143 return nodupIEXml(cs);
5147 for(i = 1; c = cs[i]; i++){
5152 for(var j = 0; j < i; j++){
5155 for(j = i+1; cj = cs[j]; j++){
5167 function quickDiffIEXml(c1, c2){
5169 for(var i = 0, len = c1.length; i < len; i++){
5170 c1[i].setAttribute("_qdiff", d);
5173 for(var i = 0, len = c2.length; i < len; i++){
5174 if(c2[i].getAttribute("_qdiff") != d){
5175 r[r.length] = c2[i];
5178 for(var i = 0, len = c1.length; i < len; i++){
5179 c1[i].removeAttribute("_qdiff");
5184 function quickDiff(c1, c2){
5185 var len1 = c1.length;
5189 if(isIE && c1[0].selectSingleNode){
5190 return quickDiffIEXml(c1, c2);
5193 for(var i = 0; i < len1; i++){
5197 for(var i = 0, len = c2.length; i < len; i++){
5198 if(c2[i]._qdiff != d){
5199 r[r.length] = c2[i];
5205 function quickId(ns, mode, root, id){
5207 var d = root.ownerDocument || root;
5208 return d.getElementById(id);
5210 ns = getNodes(ns, mode, "*");
5211 return byId(ns, null, id);
5215 getStyle : function(el, name){
5216 return Roo.fly(el).getStyle(name);
5219 * Compiles a selector/xpath query into a reusable function. The returned function
5220 * takes one parameter "root" (optional), which is the context node from where the query should start.
5221 * @param {String} selector The selector/xpath query
5222 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5223 * @return {Function}
5225 compile : function(path, type){
5226 type = type || "select";
5228 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5229 var q = path, mode, lq;
5230 var tk = Roo.DomQuery.matchers;
5231 var tklen = tk.length;
5234 // accept leading mode switch
5235 var lmode = q.match(modeRe);
5236 if(lmode && lmode[1]){
5237 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5238 q = q.replace(lmode[1], "");
5240 // strip leading slashes
5241 while(path.substr(0, 1)=="/"){
5242 path = path.substr(1);
5245 while(q && lq != q){
5247 var tm = q.match(tagTokenRe);
5248 if(type == "select"){
5251 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5253 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5255 q = q.replace(tm[0], "");
5256 }else if(q.substr(0, 1) != '@'){
5257 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5262 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5264 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5266 q = q.replace(tm[0], "");
5269 while(!(mm = q.match(modeRe))){
5270 var matched = false;
5271 for(var j = 0; j < tklen; j++){
5273 var m = q.match(t.re);
5275 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5278 q = q.replace(m[0], "");
5283 // prevent infinite loop on bad selector
5285 throw 'Error parsing selector, parsing failed at "' + q + '"';
5289 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5290 q = q.replace(mm[1], "");
5293 fn[fn.length] = "return nodup(n);\n}";
5296 * list of variables that need from compression as they are used by eval.
5306 * eval:var:byClassName
5308 * eval:var:byAttribute
5309 * eval:var:attrValue
5317 * Selects a group of elements.
5318 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5319 * @param {Node} root (optional) The start of the query (defaults to document).
5322 select : function(path, root, type){
5323 if(!root || root == document){
5326 if(typeof root == "string"){
5327 root = document.getElementById(root);
5329 var paths = path.split(",");
5331 for(var i = 0, len = paths.length; i < len; i++){
5332 var p = paths[i].replace(trimRe, "");
5334 cache[p] = Roo.DomQuery.compile(p);
5336 throw p + " is not a valid selector";
5339 var result = cache[p](root);
5340 if(result && result != document){
5341 results = results.concat(result);
5344 if(paths.length > 1){
5345 return nodup(results);
5351 * Selects a single element.
5352 * @param {String} selector The selector/xpath query
5353 * @param {Node} root (optional) The start of the query (defaults to document).
5356 selectNode : function(path, root){
5357 return Roo.DomQuery.select(path, root)[0];
5361 * Selects the value of a node, optionally replacing null with the defaultValue.
5362 * @param {String} selector The selector/xpath query
5363 * @param {Node} root (optional) The start of the query (defaults to document).
5364 * @param {String} defaultValue
5366 selectValue : function(path, root, defaultValue){
5367 path = path.replace(trimRe, "");
5368 if(!valueCache[path]){
5369 valueCache[path] = Roo.DomQuery.compile(path, "select");
5371 var n = valueCache[path](root);
5372 n = n[0] ? n[0] : n;
5373 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5374 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5378 * Selects the value of a node, parsing integers and floats.
5379 * @param {String} selector The selector/xpath query
5380 * @param {Node} root (optional) The start of the query (defaults to document).
5381 * @param {Number} defaultValue
5384 selectNumber : function(path, root, defaultValue){
5385 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5386 return parseFloat(v);
5390 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5391 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5392 * @param {String} selector The simple selector to test
5395 is : function(el, ss){
5396 if(typeof el == "string"){
5397 el = document.getElementById(el);
5399 var isArray = (el instanceof Array);
5400 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5401 return isArray ? (result.length == el.length) : (result.length > 0);
5405 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5406 * @param {Array} el An array of elements to filter
5407 * @param {String} selector The simple selector to test
5408 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5409 * the selector instead of the ones that match
5412 filter : function(els, ss, nonMatches){
5413 ss = ss.replace(trimRe, "");
5414 if(!simpleCache[ss]){
5415 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5417 var result = simpleCache[ss](els);
5418 return nonMatches ? quickDiff(result, els) : result;
5422 * Collection of matching regular expressions and code snippets.
5426 select: 'n = byClassName(n, null, " {1} ");'
5428 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5429 select: 'n = byPseudo(n, "{1}", "{2}");'
5431 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5432 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5435 select: 'n = byId(n, null, "{1}");'
5438 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5443 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5444 * 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, > <.
5447 "=" : function(a, v){
5450 "!=" : function(a, v){
5453 "^=" : function(a, v){
5454 return a && a.substr(0, v.length) == v;
5456 "$=" : function(a, v){
5457 return a && a.substr(a.length-v.length) == v;
5459 "*=" : function(a, v){
5460 return a && a.indexOf(v) !== -1;
5462 "%=" : function(a, v){
5463 return (a % v) == 0;
5465 "|=" : function(a, v){
5466 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5468 "~=" : function(a, v){
5469 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5474 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5475 * and the argument (if any) supplied in the selector.
5478 "first-child" : function(c){
5479 var r = [], ri = -1, n;
5480 for(var i = 0, ci; ci = n = c[i]; i++){
5481 while((n = n.previousSibling) && n.nodeType != 1);
5489 "last-child" : function(c){
5490 var r = [], ri = -1, n;
5491 for(var i = 0, ci; ci = n = c[i]; i++){
5492 while((n = n.nextSibling) && n.nodeType != 1);
5500 "nth-child" : function(c, a) {
5501 var r = [], ri = -1;
5502 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5503 var f = (m[1] || 1) - 0, l = m[2] - 0;
5504 for(var i = 0, n; n = c[i]; i++){
5505 var pn = n.parentNode;
5506 if (batch != pn._batch) {
5508 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5509 if(cn.nodeType == 1){
5516 if (l == 0 || n.nodeIndex == l){
5519 } else if ((n.nodeIndex + l) % f == 0){
5527 "only-child" : function(c){
5528 var r = [], ri = -1;;
5529 for(var i = 0, ci; ci = c[i]; i++){
5530 if(!prev(ci) && !next(ci)){
5537 "empty" : function(c){
5538 var r = [], ri = -1;
5539 for(var i = 0, ci; ci = c[i]; i++){
5540 var cns = ci.childNodes, j = 0, cn, empty = true;
5543 if(cn.nodeType == 1 || cn.nodeType == 3){
5555 "contains" : function(c, v){
5556 var r = [], ri = -1;
5557 for(var i = 0, ci; ci = c[i]; i++){
5558 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5565 "nodeValue" : function(c, v){
5566 var r = [], ri = -1;
5567 for(var i = 0, ci; ci = c[i]; i++){
5568 if(ci.firstChild && ci.firstChild.nodeValue == v){
5575 "checked" : function(c){
5576 var r = [], ri = -1;
5577 for(var i = 0, ci; ci = c[i]; i++){
5578 if(ci.checked == true){
5585 "not" : function(c, ss){
5586 return Roo.DomQuery.filter(c, ss, true);
5589 "odd" : function(c){
5590 return this["nth-child"](c, "odd");
5593 "even" : function(c){
5594 return this["nth-child"](c, "even");
5597 "nth" : function(c, a){
5598 return c[a-1] || [];
5601 "first" : function(c){
5605 "last" : function(c){
5606 return c[c.length-1] || [];
5609 "has" : function(c, ss){
5610 var s = Roo.DomQuery.select;
5611 var r = [], ri = -1;
5612 for(var i = 0, ci; ci = c[i]; i++){
5613 if(s(ss, ci).length > 0){
5620 "next" : function(c, ss){
5621 var is = Roo.DomQuery.is;
5622 var r = [], ri = -1;
5623 for(var i = 0, ci; ci = c[i]; i++){
5632 "prev" : function(c, ss){
5633 var is = Roo.DomQuery.is;
5634 var r = [], ri = -1;
5635 for(var i = 0, ci; ci = c[i]; i++){
5648 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5649 * @param {String} path The selector/xpath query
5650 * @param {Node} root (optional) The start of the query (defaults to document).
5655 Roo.query = Roo.DomQuery.select;
5658 * Ext JS Library 1.1.1
5659 * Copyright(c) 2006-2007, Ext JS, LLC.
5661 * Originally Released Under LGPL - original licence link has changed is not relivant.
5664 * <script type="text/javascript">
5668 * @class Roo.util.Observable
5669 * Base class that provides a common interface for publishing events. Subclasses are expected to
5670 * to have a property "events" with all the events defined.<br>
5673 Employee = function(name){
5680 Roo.extend(Employee, Roo.util.Observable);
5682 * @param {Object} config properties to use (incuding events / listeners)
5685 Roo.util.Observable = function(cfg){
5688 this.addEvents(cfg.events || {});
5690 delete cfg.events; // make sure
5693 Roo.apply(this, cfg);
5696 this.on(this.listeners);
5697 delete this.listeners;
5700 Roo.util.Observable.prototype = {
5702 * @cfg {Object} listeners list of events and functions to call for this object,
5706 'click' : function(e) {
5716 * Fires the specified event with the passed parameters (minus the event name).
5717 * @param {String} eventName
5718 * @param {Object...} args Variable number of parameters are passed to handlers
5719 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5721 fireEvent : function(){
5722 var ce = this.events[arguments[0].toLowerCase()];
5723 if(typeof ce == "object"){
5724 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5731 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5734 * Appends an event handler to this component
5735 * @param {String} eventName The type of event to listen for
5736 * @param {Function} handler The method the event invokes
5737 * @param {Object} scope (optional) The scope in which to execute the handler
5738 * function. The handler function's "this" context.
5739 * @param {Object} options (optional) An object containing handler configuration
5740 * properties. This may contain any of the following properties:<ul>
5741 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5742 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5743 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5744 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5745 * by the specified number of milliseconds. If the event fires again within that time, the original
5746 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5749 * <b>Combining Options</b><br>
5750 * Using the options argument, it is possible to combine different types of listeners:<br>
5752 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5754 el.on('click', this.onClick, this, {
5761 * <b>Attaching multiple handlers in 1 call</b><br>
5762 * The method also allows for a single argument to be passed which is a config object containing properties
5763 * which specify multiple handlers.
5772 fn: this.onMouseOver,
5776 fn: this.onMouseOut,
5782 * Or a shorthand syntax which passes the same scope object to all handlers:
5785 'click': this.onClick,
5786 'mouseover': this.onMouseOver,
5787 'mouseout': this.onMouseOut,
5792 addListener : function(eventName, fn, scope, o){
5793 if(typeof eventName == "object"){
5796 if(this.filterOptRe.test(e)){
5799 if(typeof o[e] == "function"){
5801 this.addListener(e, o[e], o.scope, o);
5803 // individual options
5804 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5809 o = (!o || typeof o == "boolean") ? {} : o;
5810 eventName = eventName.toLowerCase();
5811 var ce = this.events[eventName] || true;
5812 if(typeof ce == "boolean"){
5813 ce = new Roo.util.Event(this, eventName);
5814 this.events[eventName] = ce;
5816 ce.addListener(fn, scope, o);
5820 * Removes a listener
5821 * @param {String} eventName The type of event to listen for
5822 * @param {Function} handler The handler to remove
5823 * @param {Object} scope (optional) The scope (this object) for the handler
5825 removeListener : function(eventName, fn, scope){
5826 var ce = this.events[eventName.toLowerCase()];
5827 if(typeof ce == "object"){
5828 ce.removeListener(fn, scope);
5833 * Removes all listeners for this object
5835 purgeListeners : function(){
5836 for(var evt in this.events){
5837 if(typeof this.events[evt] == "object"){
5838 this.events[evt].clearListeners();
5843 relayEvents : function(o, events){
5844 var createHandler = function(ename){
5846 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5849 for(var i = 0, len = events.length; i < len; i++){
5850 var ename = events[i];
5851 if(!this.events[ename]){ this.events[ename] = true; };
5852 o.on(ename, createHandler(ename), this);
5857 * Used to define events on this Observable
5858 * @param {Object} object The object with the events defined
5860 addEvents : function(o){
5864 Roo.applyIf(this.events, o);
5868 * Checks to see if this object has any listeners for a specified event
5869 * @param {String} eventName The name of the event to check for
5870 * @return {Boolean} True if the event is being listened for, else false
5872 hasListener : function(eventName){
5873 var e = this.events[eventName];
5874 return typeof e == "object" && e.listeners.length > 0;
5878 * Appends an event handler to this element (shorthand for addListener)
5879 * @param {String} eventName The type of event to listen for
5880 * @param {Function} handler The method the event invokes
5881 * @param {Object} scope (optional) The scope in which to execute the handler
5882 * function. The handler function's "this" context.
5883 * @param {Object} options (optional)
5886 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5888 * Removes a listener (shorthand for removeListener)
5889 * @param {String} eventName The type of event to listen for
5890 * @param {Function} handler The handler to remove
5891 * @param {Object} scope (optional) The scope (this object) for the handler
5894 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5897 * Starts capture on the specified Observable. All events will be passed
5898 * to the supplied function with the event name + standard signature of the event
5899 * <b>before</b> the event is fired. If the supplied function returns false,
5900 * the event will not fire.
5901 * @param {Observable} o The Observable to capture
5902 * @param {Function} fn The function to call
5903 * @param {Object} scope (optional) The scope (this object) for the fn
5906 Roo.util.Observable.capture = function(o, fn, scope){
5907 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5911 * Removes <b>all</b> added captures from the Observable.
5912 * @param {Observable} o The Observable to release
5915 Roo.util.Observable.releaseCapture = function(o){
5916 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5921 var createBuffered = function(h, o, scope){
5922 var task = new Roo.util.DelayedTask();
5924 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5928 var createSingle = function(h, e, fn, scope){
5930 e.removeListener(fn, scope);
5931 return h.apply(scope, arguments);
5935 var createDelayed = function(h, o, scope){
5937 var args = Array.prototype.slice.call(arguments, 0);
5938 setTimeout(function(){
5939 h.apply(scope, args);
5944 Roo.util.Event = function(obj, name){
5947 this.listeners = [];
5950 Roo.util.Event.prototype = {
5951 addListener : function(fn, scope, options){
5952 var o = options || {};
5953 scope = scope || this.obj;
5954 if(!this.isListening(fn, scope)){
5955 var l = {fn: fn, scope: scope, options: o};
5958 h = createDelayed(h, o, scope);
5961 h = createSingle(h, this, fn, scope);
5964 h = createBuffered(h, o, scope);
5967 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5968 this.listeners.push(l);
5970 this.listeners = this.listeners.slice(0);
5971 this.listeners.push(l);
5976 findListener : function(fn, scope){
5977 scope = scope || this.obj;
5978 var ls = this.listeners;
5979 for(var i = 0, len = ls.length; i < len; i++){
5981 if(l.fn == fn && l.scope == scope){
5988 isListening : function(fn, scope){
5989 return this.findListener(fn, scope) != -1;
5992 removeListener : function(fn, scope){
5994 if((index = this.findListener(fn, scope)) != -1){
5996 this.listeners.splice(index, 1);
5998 this.listeners = this.listeners.slice(0);
5999 this.listeners.splice(index, 1);
6006 clearListeners : function(){
6007 this.listeners = [];
6011 var ls = this.listeners, scope, len = ls.length;
6014 var args = Array.prototype.slice.call(arguments, 0);
6015 for(var i = 0; i < len; i++){
6017 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6018 this.firing = false;
6022 this.firing = false;
6029 * Ext JS Library 1.1.1
6030 * Copyright(c) 2006-2007, Ext JS, LLC.
6032 * Originally Released Under LGPL - original licence link has changed is not relivant.
6035 * <script type="text/javascript">
6039 * @class Roo.EventManager
6040 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6041 * several useful events directly.
6042 * See {@link Roo.EventObject} for more details on normalized event objects.
6045 Roo.EventManager = function(){
6046 var docReadyEvent, docReadyProcId, docReadyState = false;
6047 var resizeEvent, resizeTask, textEvent, textSize;
6048 var E = Roo.lib.Event;
6049 var D = Roo.lib.Dom;
6054 var fireDocReady = function(){
6056 docReadyState = true;
6059 clearInterval(docReadyProcId);
6061 if(Roo.isGecko || Roo.isOpera) {
6062 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6065 var defer = document.getElementById("ie-deferred-loader");
6067 defer.onreadystatechange = null;
6068 defer.parentNode.removeChild(defer);
6072 docReadyEvent.fire();
6073 docReadyEvent.clearListeners();
6078 var initDocReady = function(){
6079 docReadyEvent = new Roo.util.Event();
6080 if(Roo.isGecko || Roo.isOpera) {
6081 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6083 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6084 var defer = document.getElementById("ie-deferred-loader");
6085 defer.onreadystatechange = function(){
6086 if(this.readyState == "complete"){
6090 }else if(Roo.isSafari){
6091 docReadyProcId = setInterval(function(){
6092 var rs = document.readyState;
6093 if(rs == "complete") {
6098 // no matter what, make sure it fires on load
6099 E.on(window, "load", fireDocReady);
6102 var createBuffered = function(h, o){
6103 var task = new Roo.util.DelayedTask(h);
6105 // create new event object impl so new events don't wipe out properties
6106 e = new Roo.EventObjectImpl(e);
6107 task.delay(o.buffer, h, null, [e]);
6111 var createSingle = function(h, el, ename, fn){
6113 Roo.EventManager.removeListener(el, ename, fn);
6118 var createDelayed = function(h, o){
6120 // create new event object impl so new events don't wipe out properties
6121 e = new Roo.EventObjectImpl(e);
6122 setTimeout(function(){
6127 var transitionEndVal = false;
6129 var transitionEnd = function()
6131 if (transitionEndVal) {
6132 return transitionEndVal;
6134 var el = document.createElement('div');
6136 var transEndEventNames = {
6137 WebkitTransition : 'webkitTransitionEnd',
6138 MozTransition : 'transitionend',
6139 OTransition : 'oTransitionEnd otransitionend',
6140 transition : 'transitionend'
6143 for (var name in transEndEventNames) {
6144 if (el.style[name] !== undefined) {
6145 transitionEndVal = transEndEventNames[name];
6146 return transitionEndVal ;
6152 var listen = function(element, ename, opt, fn, scope){
6153 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6154 fn = fn || o.fn; scope = scope || o.scope;
6155 var el = Roo.getDom(element);
6159 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6162 if (ename == 'transitionend') {
6163 ename = transitionEnd();
6165 var h = function(e){
6166 e = Roo.EventObject.setEvent(e);
6169 t = e.getTarget(o.delegate, el);
6176 if(o.stopEvent === true){
6179 if(o.preventDefault === true){
6182 if(o.stopPropagation === true){
6183 e.stopPropagation();
6186 if(o.normalized === false){
6190 fn.call(scope || el, e, t, o);
6193 h = createDelayed(h, o);
6196 h = createSingle(h, el, ename, fn);
6199 h = createBuffered(h, o);
6201 fn._handlers = fn._handlers || [];
6204 fn._handlers.push([Roo.id(el), ename, h]);
6209 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6210 el.addEventListener("DOMMouseScroll", h, false);
6211 E.on(window, 'unload', function(){
6212 el.removeEventListener("DOMMouseScroll", h, false);
6215 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6216 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6221 var stopListening = function(el, ename, fn){
6222 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6224 for(var i = 0, len = hds.length; i < len; i++){
6226 if(h[0] == id && h[1] == ename){
6233 E.un(el, ename, hd);
6234 el = Roo.getDom(el);
6235 if(ename == "mousewheel" && el.addEventListener){
6236 el.removeEventListener("DOMMouseScroll", hd, false);
6238 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6239 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6243 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6250 * @scope Roo.EventManager
6255 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6256 * object with a Roo.EventObject
6257 * @param {Function} fn The method the event invokes
6258 * @param {Object} scope An object that becomes the scope of the handler
6259 * @param {boolean} override If true, the obj passed in becomes
6260 * the execution scope of the listener
6261 * @return {Function} The wrapped function
6264 wrap : function(fn, scope, override){
6266 Roo.EventObject.setEvent(e);
6267 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6272 * Appends an event handler to an element (shorthand for addListener)
6273 * @param {String/HTMLElement} element The html element or id to assign the
6274 * @param {String} eventName The type of event to listen for
6275 * @param {Function} handler The method the event invokes
6276 * @param {Object} scope (optional) The scope in which to execute the handler
6277 * function. The handler function's "this" context.
6278 * @param {Object} options (optional) An object containing handler configuration
6279 * properties. This may contain any of the following properties:<ul>
6280 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6281 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6282 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6283 * <li>preventDefault {Boolean} True to prevent the default action</li>
6284 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6285 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6286 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6287 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6288 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6289 * by the specified number of milliseconds. If the event fires again within that time, the original
6290 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6293 * <b>Combining Options</b><br>
6294 * Using the options argument, it is possible to combine different types of listeners:<br>
6296 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6298 el.on('click', this.onClick, this, {
6305 * <b>Attaching multiple handlers in 1 call</b><br>
6306 * The method also allows for a single argument to be passed which is a config object containing properties
6307 * which specify multiple handlers.
6317 fn: this.onMouseOver
6326 * Or a shorthand syntax:<br>
6329 'click' : this.onClick,
6330 'mouseover' : this.onMouseOver,
6331 'mouseout' : this.onMouseOut
6335 addListener : function(element, eventName, fn, scope, options){
6336 if(typeof eventName == "object"){
6342 if(typeof o[e] == "function"){
6344 listen(element, e, o, o[e], o.scope);
6346 // individual options
6347 listen(element, e, o[e]);
6352 return listen(element, eventName, options, fn, scope);
6356 * Removes an event handler
6358 * @param {String/HTMLElement} element The id or html element to remove the
6360 * @param {String} eventName The type of event
6361 * @param {Function} fn
6362 * @return {Boolean} True if a listener was actually removed
6364 removeListener : function(element, eventName, fn){
6365 return stopListening(element, eventName, fn);
6369 * Fires when the document is ready (before onload and before images are loaded). Can be
6370 * accessed shorthanded Roo.onReady().
6371 * @param {Function} fn The method the event invokes
6372 * @param {Object} scope An object that becomes the scope of the handler
6373 * @param {boolean} options
6375 onDocumentReady : function(fn, scope, options){
6376 if(docReadyState){ // if it already fired
6377 docReadyEvent.addListener(fn, scope, options);
6378 docReadyEvent.fire();
6379 docReadyEvent.clearListeners();
6385 docReadyEvent.addListener(fn, scope, options);
6389 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6390 * @param {Function} fn The method the event invokes
6391 * @param {Object} scope An object that becomes the scope of the handler
6392 * @param {boolean} options
6394 onWindowResize : function(fn, scope, options){
6396 resizeEvent = new Roo.util.Event();
6397 resizeTask = new Roo.util.DelayedTask(function(){
6398 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6400 E.on(window, "resize", function(){
6402 resizeTask.delay(50);
6404 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6408 resizeEvent.addListener(fn, scope, options);
6412 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6413 * @param {Function} fn The method the event invokes
6414 * @param {Object} scope An object that becomes the scope of the handler
6415 * @param {boolean} options
6417 onTextResize : function(fn, scope, options){
6419 textEvent = new Roo.util.Event();
6420 var textEl = new Roo.Element(document.createElement('div'));
6421 textEl.dom.className = 'x-text-resize';
6422 textEl.dom.innerHTML = 'X';
6423 textEl.appendTo(document.body);
6424 textSize = textEl.dom.offsetHeight;
6425 setInterval(function(){
6426 if(textEl.dom.offsetHeight != textSize){
6427 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6429 }, this.textResizeInterval);
6431 textEvent.addListener(fn, scope, options);
6435 * Removes the passed window resize listener.
6436 * @param {Function} fn The method the event invokes
6437 * @param {Object} scope The scope of handler
6439 removeResizeListener : function(fn, scope){
6441 resizeEvent.removeListener(fn, scope);
6446 fireResize : function(){
6448 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6452 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6456 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6458 textResizeInterval : 50
6463 * @scopeAlias pub=Roo.EventManager
6467 * Appends an event handler to an element (shorthand for addListener)
6468 * @param {String/HTMLElement} element The html element or id to assign the
6469 * @param {String} eventName The type of event to listen for
6470 * @param {Function} handler The method the event invokes
6471 * @param {Object} scope (optional) The scope in which to execute the handler
6472 * function. The handler function's "this" context.
6473 * @param {Object} options (optional) An object containing handler configuration
6474 * properties. This may contain any of the following properties:<ul>
6475 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6476 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6477 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6478 * <li>preventDefault {Boolean} True to prevent the default action</li>
6479 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6480 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6481 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6482 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6483 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6484 * by the specified number of milliseconds. If the event fires again within that time, the original
6485 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6488 * <b>Combining Options</b><br>
6489 * Using the options argument, it is possible to combine different types of listeners:<br>
6491 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6493 el.on('click', this.onClick, this, {
6500 * <b>Attaching multiple handlers in 1 call</b><br>
6501 * The method also allows for a single argument to be passed which is a config object containing properties
6502 * which specify multiple handlers.
6512 fn: this.onMouseOver
6521 * Or a shorthand syntax:<br>
6524 'click' : this.onClick,
6525 'mouseover' : this.onMouseOver,
6526 'mouseout' : this.onMouseOut
6530 pub.on = pub.addListener;
6531 pub.un = pub.removeListener;
6533 pub.stoppedMouseDownEvent = new Roo.util.Event();
6537 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6538 * @param {Function} fn The method the event invokes
6539 * @param {Object} scope An object that becomes the scope of the handler
6540 * @param {boolean} override If true, the obj passed in becomes
6541 * the execution scope of the listener
6545 Roo.onReady = Roo.EventManager.onDocumentReady;
6547 Roo.onReady(function(){
6548 var bd = Roo.get(document.body);
6553 : Roo.isGecko ? "roo-gecko"
6554 : Roo.isOpera ? "roo-opera"
6555 : Roo.isSafari ? "roo-safari" : ""];
6558 cls.push("roo-mac");
6561 cls.push("roo-linux");
6563 if(Roo.isBorderBox){
6564 cls.push('roo-border-box');
6566 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6567 var p = bd.dom.parentNode;
6569 p.className += ' roo-strict';
6572 bd.addClass(cls.join(' '));
6576 * @class Roo.EventObject
6577 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6578 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6581 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6583 var target = e.getTarget();
6586 var myDiv = Roo.get("myDiv");
6587 myDiv.on("click", handleClick);
6589 Roo.EventManager.on("myDiv", 'click', handleClick);
6590 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6594 Roo.EventObject = function(){
6596 var E = Roo.lib.Event;
6598 // safari keypress events for special keys return bad keycodes
6601 63235 : 39, // right
6604 63276 : 33, // page up
6605 63277 : 34, // page down
6606 63272 : 46, // delete
6611 // normalize button clicks
6612 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6613 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6615 Roo.EventObjectImpl = function(e){
6617 this.setEvent(e.browserEvent || e);
6620 Roo.EventObjectImpl.prototype = {
6622 * Used to fix doc tools.
6623 * @scope Roo.EventObject.prototype
6629 /** The normal browser event */
6630 browserEvent : null,
6631 /** The button pressed in a mouse event */
6633 /** True if the shift key was down during the event */
6635 /** True if the control key was down during the event */
6637 /** True if the alt key was down during the event */
6696 setEvent : function(e){
6697 if(e == this || (e && e.browserEvent)){ // already wrapped
6700 this.browserEvent = e;
6702 // normalize buttons
6703 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6704 if(e.type == 'click' && this.button == -1){
6708 this.shiftKey = e.shiftKey;
6709 // mac metaKey behaves like ctrlKey
6710 this.ctrlKey = e.ctrlKey || e.metaKey;
6711 this.altKey = e.altKey;
6712 // in getKey these will be normalized for the mac
6713 this.keyCode = e.keyCode;
6714 // keyup warnings on firefox.
6715 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6716 // cache the target for the delayed and or buffered events
6717 this.target = E.getTarget(e);
6719 this.xy = E.getXY(e);
6722 this.shiftKey = false;
6723 this.ctrlKey = false;
6724 this.altKey = false;
6734 * Stop the event (preventDefault and stopPropagation)
6736 stopEvent : function(){
6737 if(this.browserEvent){
6738 if(this.browserEvent.type == 'mousedown'){
6739 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6741 E.stopEvent(this.browserEvent);
6746 * Prevents the browsers default handling of the event.
6748 preventDefault : function(){
6749 if(this.browserEvent){
6750 E.preventDefault(this.browserEvent);
6755 isNavKeyPress : function(){
6756 var k = this.keyCode;
6757 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6758 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6761 isSpecialKey : function(){
6762 var k = this.keyCode;
6763 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6764 (k == 16) || (k == 17) ||
6765 (k >= 18 && k <= 20) ||
6766 (k >= 33 && k <= 35) ||
6767 (k >= 36 && k <= 39) ||
6768 (k >= 44 && k <= 45);
6771 * Cancels bubbling of the event.
6773 stopPropagation : function(){
6774 if(this.browserEvent){
6775 if(this.type == 'mousedown'){
6776 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6778 E.stopPropagation(this.browserEvent);
6783 * Gets the key code for the event.
6786 getCharCode : function(){
6787 return this.charCode || this.keyCode;
6791 * Returns a normalized keyCode for the event.
6792 * @return {Number} The key code
6794 getKey : function(){
6795 var k = this.keyCode || this.charCode;
6796 return Roo.isSafari ? (safariKeys[k] || k) : k;
6800 * Gets the x coordinate of the event.
6803 getPageX : function(){
6808 * Gets the y coordinate of the event.
6811 getPageY : function(){
6816 * Gets the time of the event.
6819 getTime : function(){
6820 if(this.browserEvent){
6821 return E.getTime(this.browserEvent);
6827 * Gets the page coordinates of the event.
6828 * @return {Array} The xy values like [x, y]
6835 * Gets the target for the event.
6836 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6837 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6838 search as a number or element (defaults to 10 || document.body)
6839 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6840 * @return {HTMLelement}
6842 getTarget : function(selector, maxDepth, returnEl){
6843 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6846 * Gets the related target.
6847 * @return {HTMLElement}
6849 getRelatedTarget : function(){
6850 if(this.browserEvent){
6851 return E.getRelatedTarget(this.browserEvent);
6857 * Normalizes mouse wheel delta across browsers
6858 * @return {Number} The delta
6860 getWheelDelta : function(){
6861 var e = this.browserEvent;
6863 if(e.wheelDelta){ /* IE/Opera. */
6864 delta = e.wheelDelta/120;
6865 }else if(e.detail){ /* Mozilla case. */
6866 delta = -e.detail/3;
6872 * Returns true if the control, meta, shift or alt key was pressed during this event.
6875 hasModifier : function(){
6876 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6880 * Returns true if the target of this event equals el or is a child of el
6881 * @param {String/HTMLElement/Element} el
6882 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6885 within : function(el, related){
6886 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6887 return t && Roo.fly(el).contains(t);
6890 getPoint : function(){
6891 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6895 return new Roo.EventObjectImpl();
6900 * Ext JS Library 1.1.1
6901 * Copyright(c) 2006-2007, Ext JS, LLC.
6903 * Originally Released Under LGPL - original licence link has changed is not relivant.
6906 * <script type="text/javascript">
6910 // was in Composite Element!??!?!
6913 var D = Roo.lib.Dom;
6914 var E = Roo.lib.Event;
6915 var A = Roo.lib.Anim;
6917 // local style camelizing for speed
6919 var camelRe = /(-[a-z])/gi;
6920 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6921 var view = document.defaultView;
6924 * @class Roo.Element
6925 * Represents an Element in the DOM.<br><br>
6928 var el = Roo.get("my-div");
6931 var el = getEl("my-div");
6933 // or with a DOM element
6934 var el = Roo.get(myDivElement);
6936 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6937 * each call instead of constructing a new one.<br><br>
6938 * <b>Animations</b><br />
6939 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6940 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6942 Option Default Description
6943 --------- -------- ---------------------------------------------
6944 duration .35 The duration of the animation in seconds
6945 easing easeOut The YUI easing method
6946 callback none A function to execute when the anim completes
6947 scope this The scope (this) of the callback function
6949 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6950 * manipulate the animation. Here's an example:
6952 var el = Roo.get("my-div");
6957 // default animation
6958 el.setWidth(100, true);
6960 // animation with some options set
6967 // using the "anim" property to get the Anim object
6973 el.setWidth(100, opt);
6975 if(opt.anim.isAnimated()){
6979 * <b> Composite (Collections of) Elements</b><br />
6980 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6981 * @constructor Create a new Element directly.
6982 * @param {String/HTMLElement} element
6983 * @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).
6985 Roo.Element = function(element, forceNew){
6986 var dom = typeof element == "string" ?
6987 document.getElementById(element) : element;
6988 if(!dom){ // invalid id/element
6992 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6993 return Roo.Element.cache[id];
7003 * The DOM element ID
7006 this.id = id || Roo.id(dom);
7009 var El = Roo.Element;
7013 * The element's default display mode (defaults to "")
7016 originalDisplay : "",
7020 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7025 * Sets the element's visibility mode. When setVisible() is called it
7026 * will use this to determine whether to set the visibility or the display property.
7027 * @param visMode Element.VISIBILITY or Element.DISPLAY
7028 * @return {Roo.Element} this
7030 setVisibilityMode : function(visMode){
7031 this.visibilityMode = visMode;
7035 * Convenience method for setVisibilityMode(Element.DISPLAY)
7036 * @param {String} display (optional) What to set display to when visible
7037 * @return {Roo.Element} this
7039 enableDisplayMode : function(display){
7040 this.setVisibilityMode(El.DISPLAY);
7041 if(typeof display != "undefined") this.originalDisplay = display;
7046 * 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)
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 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7051 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7053 findParent : function(simpleSelector, maxDepth, returnEl){
7054 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7055 maxDepth = maxDepth || 50;
7056 if(typeof maxDepth != "number"){
7057 stopEl = Roo.getDom(maxDepth);
7060 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7061 if(dq.is(p, simpleSelector)){
7062 return returnEl ? Roo.get(p) : p;
7072 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7073 * @param {String} selector The simple selector to test
7074 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7075 search as a number or element (defaults to 10 || document.body)
7076 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7077 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7079 findParentNode : function(simpleSelector, maxDepth, returnEl){
7080 var p = Roo.fly(this.dom.parentNode, '_internal');
7081 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7085 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7086 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7087 * @param {String} selector The simple selector to test
7088 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7089 search as a number or element (defaults to 10 || document.body)
7090 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7092 up : function(simpleSelector, maxDepth){
7093 return this.findParentNode(simpleSelector, maxDepth, true);
7099 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7100 * @param {String} selector The simple selector to test
7101 * @return {Boolean} True if this element matches the selector, else false
7103 is : function(simpleSelector){
7104 return Roo.DomQuery.is(this.dom, simpleSelector);
7108 * Perform animation on this element.
7109 * @param {Object} args The YUI animation control args
7110 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7111 * @param {Function} onComplete (optional) Function to call when animation completes
7112 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7113 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7114 * @return {Roo.Element} this
7116 animate : function(args, duration, onComplete, easing, animType){
7117 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7122 * @private Internal animation call
7124 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7125 animType = animType || 'run';
7127 var anim = Roo.lib.Anim[animType](
7129 (opt.duration || defaultDur) || .35,
7130 (opt.easing || defaultEase) || 'easeOut',
7132 Roo.callback(cb, this);
7133 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7141 // private legacy anim prep
7142 preanim : function(a, i){
7143 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7147 * Removes worthless text nodes
7148 * @param {Boolean} forceReclean (optional) By default the element
7149 * keeps track if it has been cleaned already so
7150 * you can call this over and over. However, if you update the element and
7151 * need to force a reclean, you can pass true.
7153 clean : function(forceReclean){
7154 if(this.isCleaned && forceReclean !== true){
7158 var d = this.dom, n = d.firstChild, ni = -1;
7160 var nx = n.nextSibling;
7161 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7168 this.isCleaned = true;
7173 calcOffsetsTo : function(el){
7176 var restorePos = false;
7177 if(el.getStyle('position') == 'static'){
7178 el.position('relative');
7183 while(op && op != d && op.tagName != 'HTML'){
7186 op = op.offsetParent;
7189 el.position('static');
7195 * Scrolls this element into view within the passed container.
7196 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7197 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7198 * @return {Roo.Element} this
7200 scrollIntoView : function(container, hscroll){
7201 var c = Roo.getDom(container) || document.body;
7204 var o = this.calcOffsetsTo(c),
7207 b = t+el.offsetHeight,
7208 r = l+el.offsetWidth;
7210 var ch = c.clientHeight;
7211 var ct = parseInt(c.scrollTop, 10);
7212 var cl = parseInt(c.scrollLeft, 10);
7214 var cr = cl + c.clientWidth;
7222 if(hscroll !== false){
7226 c.scrollLeft = r-c.clientWidth;
7233 scrollChildIntoView : function(child, hscroll){
7234 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7238 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7239 * the new height may not be available immediately.
7240 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7241 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7242 * @param {Function} onComplete (optional) Function to call when animation completes
7243 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7244 * @return {Roo.Element} this
7246 autoHeight : function(animate, duration, onComplete, easing){
7247 var oldHeight = this.getHeight();
7249 this.setHeight(1); // force clipping
7250 setTimeout(function(){
7251 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7253 this.setHeight(height);
7255 if(typeof onComplete == "function"){
7259 this.setHeight(oldHeight); // restore original height
7260 this.setHeight(height, animate, duration, function(){
7262 if(typeof onComplete == "function") onComplete();
7263 }.createDelegate(this), easing);
7265 }.createDelegate(this), 0);
7270 * Returns true if this element is an ancestor of the passed element
7271 * @param {HTMLElement/String} el The element to check
7272 * @return {Boolean} True if this element is an ancestor of el, else false
7274 contains : function(el){
7275 if(!el){return false;}
7276 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7280 * Checks whether the element is currently visible using both visibility and display properties.
7281 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7282 * @return {Boolean} True if the element is currently visible, else false
7284 isVisible : function(deep) {
7285 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7286 if(deep !== true || !vis){
7289 var p = this.dom.parentNode;
7290 while(p && p.tagName.toLowerCase() != "body"){
7291 if(!Roo.fly(p, '_isVisible').isVisible()){
7300 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7301 * @param {String} selector The CSS selector
7302 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7303 * @return {CompositeElement/CompositeElementLite} The composite element
7305 select : function(selector, unique){
7306 return El.select(selector, unique, this.dom);
7310 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7311 * @param {String} selector The CSS selector
7312 * @return {Array} An array of the matched nodes
7314 query : function(selector, unique){
7315 return Roo.DomQuery.select(selector, this.dom);
7319 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7320 * @param {String} selector The CSS selector
7321 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7322 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7324 child : function(selector, returnDom){
7325 var n = Roo.DomQuery.selectNode(selector, this.dom);
7326 return returnDom ? n : Roo.get(n);
7330 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7331 * @param {String} selector The CSS selector
7332 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7333 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7335 down : function(selector, returnDom){
7336 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7337 return returnDom ? n : Roo.get(n);
7341 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7342 * @param {String} group The group the DD object is member of
7343 * @param {Object} config The DD config object
7344 * @param {Object} overrides An object containing methods to override/implement on the DD object
7345 * @return {Roo.dd.DD} The DD object
7347 initDD : function(group, config, overrides){
7348 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7349 return Roo.apply(dd, overrides);
7353 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7354 * @param {String} group The group the DDProxy object is member of
7355 * @param {Object} config The DDProxy config object
7356 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7357 * @return {Roo.dd.DDProxy} The DDProxy object
7359 initDDProxy : function(group, config, overrides){
7360 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7361 return Roo.apply(dd, overrides);
7365 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7366 * @param {String} group The group the DDTarget object is member of
7367 * @param {Object} config The DDTarget config object
7368 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7369 * @return {Roo.dd.DDTarget} The DDTarget object
7371 initDDTarget : function(group, config, overrides){
7372 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7373 return Roo.apply(dd, overrides);
7377 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7378 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7379 * @param {Boolean} visible Whether the element is visible
7380 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7381 * @return {Roo.Element} this
7383 setVisible : function(visible, animate){
7385 if(this.visibilityMode == El.DISPLAY){
7386 this.setDisplayed(visible);
7389 this.dom.style.visibility = visible ? "visible" : "hidden";
7392 // closure for composites
7394 var visMode = this.visibilityMode;
7396 this.setOpacity(.01);
7397 this.setVisible(true);
7399 this.anim({opacity: { to: (visible?1:0) }},
7400 this.preanim(arguments, 1),
7401 null, .35, 'easeIn', function(){
7403 if(visMode == El.DISPLAY){
7404 dom.style.display = "none";
7406 dom.style.visibility = "hidden";
7408 Roo.get(dom).setOpacity(1);
7416 * Returns true if display is not "none"
7419 isDisplayed : function() {
7420 return this.getStyle("display") != "none";
7424 * Toggles the element's visibility or display, depending on visibility mode.
7425 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7426 * @return {Roo.Element} this
7428 toggle : function(animate){
7429 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7434 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7435 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7436 * @return {Roo.Element} this
7438 setDisplayed : function(value) {
7439 if(typeof value == "boolean"){
7440 value = value ? this.originalDisplay : "none";
7442 this.setStyle("display", value);
7447 * Tries to focus the element. Any exceptions are caught and ignored.
7448 * @return {Roo.Element} this
7450 focus : function() {
7458 * Tries to blur the element. Any exceptions are caught and ignored.
7459 * @return {Roo.Element} this
7469 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7470 * @param {String/Array} className The CSS class to add, or an array of classes
7471 * @return {Roo.Element} this
7473 addClass : function(className){
7474 if(className instanceof Array){
7475 for(var i = 0, len = className.length; i < len; i++) {
7476 this.addClass(className[i]);
7479 if(className && !this.hasClass(className)){
7480 this.dom.className = this.dom.className + " " + className;
7487 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7488 * @param {String/Array} className The CSS class to add, or an array of classes
7489 * @return {Roo.Element} this
7491 radioClass : function(className){
7492 var siblings = this.dom.parentNode.childNodes;
7493 for(var i = 0; i < siblings.length; i++) {
7494 var s = siblings[i];
7495 if(s.nodeType == 1){
7496 Roo.get(s).removeClass(className);
7499 this.addClass(className);
7504 * Removes one or more CSS classes from the element.
7505 * @param {String/Array} className The CSS class to remove, or an array of classes
7506 * @return {Roo.Element} this
7508 removeClass : function(className){
7509 if(!className || !this.dom.className){
7512 if(className instanceof Array){
7513 for(var i = 0, len = className.length; i < len; i++) {
7514 this.removeClass(className[i]);
7517 if(this.hasClass(className)){
7518 var re = this.classReCache[className];
7520 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7521 this.classReCache[className] = re;
7523 this.dom.className =
7524 this.dom.className.replace(re, " ");
7534 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7535 * @param {String} className The CSS class to toggle
7536 * @return {Roo.Element} this
7538 toggleClass : function(className){
7539 if(this.hasClass(className)){
7540 this.removeClass(className);
7542 this.addClass(className);
7548 * Checks if the specified CSS class exists on this element's DOM node.
7549 * @param {String} className The CSS class to check for
7550 * @return {Boolean} True if the class exists, else false
7552 hasClass : function(className){
7553 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7557 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7558 * @param {String} oldClassName The CSS class to replace
7559 * @param {String} newClassName The replacement CSS class
7560 * @return {Roo.Element} this
7562 replaceClass : function(oldClassName, newClassName){
7563 this.removeClass(oldClassName);
7564 this.addClass(newClassName);
7569 * Returns an object with properties matching the styles requested.
7570 * For example, el.getStyles('color', 'font-size', 'width') might return
7571 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7572 * @param {String} style1 A style name
7573 * @param {String} style2 A style name
7574 * @param {String} etc.
7575 * @return {Object} The style object
7577 getStyles : function(){
7578 var a = arguments, len = a.length, r = {};
7579 for(var i = 0; i < len; i++){
7580 r[a[i]] = this.getStyle(a[i]);
7586 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7587 * @param {String} property The style property whose value is returned.
7588 * @return {String} The current value of the style property for this element.
7590 getStyle : function(){
7591 return view && view.getComputedStyle ?
7593 var el = this.dom, v, cs, camel;
7594 if(prop == 'float'){
7597 if(el.style && (v = el.style[prop])){
7600 if(cs = view.getComputedStyle(el, "")){
7601 if(!(camel = propCache[prop])){
7602 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7609 var el = this.dom, v, cs, camel;
7610 if(prop == 'opacity'){
7611 if(typeof el.style.filter == 'string'){
7612 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7614 var fv = parseFloat(m[1]);
7616 return fv ? fv / 100 : 0;
7621 }else if(prop == 'float'){
7622 prop = "styleFloat";
7624 if(!(camel = propCache[prop])){
7625 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7627 if(v = el.style[camel]){
7630 if(cs = el.currentStyle){
7638 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7639 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7640 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7641 * @return {Roo.Element} this
7643 setStyle : function(prop, value){
7644 if(typeof prop == "string"){
7646 if (prop == 'float') {
7647 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7652 if(!(camel = propCache[prop])){
7653 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7656 if(camel == 'opacity') {
7657 this.setOpacity(value);
7659 this.dom.style[camel] = value;
7662 for(var style in prop){
7663 if(typeof prop[style] != "function"){
7664 this.setStyle(style, prop[style]);
7672 * More flexible version of {@link #setStyle} for setting style properties.
7673 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7674 * a function which returns such a specification.
7675 * @return {Roo.Element} this
7677 applyStyles : function(style){
7678 Roo.DomHelper.applyStyles(this.dom, style);
7683 * 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).
7684 * @return {Number} The X position of the element
7687 return D.getX(this.dom);
7691 * 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).
7692 * @return {Number} The Y position of the element
7695 return D.getY(this.dom);
7699 * 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).
7700 * @return {Array} The XY position of the element
7703 return D.getXY(this.dom);
7707 * 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).
7708 * @param {Number} The X position of the element
7709 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7710 * @return {Roo.Element} this
7712 setX : function(x, animate){
7714 D.setX(this.dom, x);
7716 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7722 * 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).
7723 * @param {Number} The Y position of the element
7724 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7725 * @return {Roo.Element} this
7727 setY : function(y, animate){
7729 D.setY(this.dom, y);
7731 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7737 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7738 * @param {String} left The left CSS property value
7739 * @return {Roo.Element} this
7741 setLeft : function(left){
7742 this.setStyle("left", this.addUnits(left));
7747 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7748 * @param {String} top The top CSS property value
7749 * @return {Roo.Element} this
7751 setTop : function(top){
7752 this.setStyle("top", this.addUnits(top));
7757 * Sets the element's CSS right style.
7758 * @param {String} right The right CSS property value
7759 * @return {Roo.Element} this
7761 setRight : function(right){
7762 this.setStyle("right", this.addUnits(right));
7767 * Sets the element's CSS bottom style.
7768 * @param {String} bottom The bottom CSS property value
7769 * @return {Roo.Element} this
7771 setBottom : function(bottom){
7772 this.setStyle("bottom", this.addUnits(bottom));
7777 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7778 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7779 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7780 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7781 * @return {Roo.Element} this
7783 setXY : function(pos, animate){
7785 D.setXY(this.dom, pos);
7787 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7793 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7794 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7795 * @param {Number} x X value for new position (coordinates are page-based)
7796 * @param {Number} y Y value for new position (coordinates are page-based)
7797 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7798 * @return {Roo.Element} this
7800 setLocation : function(x, y, animate){
7801 this.setXY([x, y], this.preanim(arguments, 2));
7806 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7807 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7808 * @param {Number} x X value for new position (coordinates are page-based)
7809 * @param {Number} y Y value for new position (coordinates are page-based)
7810 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7811 * @return {Roo.Element} this
7813 moveTo : function(x, y, animate){
7814 this.setXY([x, y], this.preanim(arguments, 2));
7819 * Returns the region of the given element.
7820 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7821 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7823 getRegion : function(){
7824 return D.getRegion(this.dom);
7828 * Returns the offset height of the element
7829 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7830 * @return {Number} The element's height
7832 getHeight : function(contentHeight){
7833 var h = this.dom.offsetHeight || 0;
7834 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7838 * Returns the offset width of the element
7839 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7840 * @return {Number} The element's width
7842 getWidth : function(contentWidth){
7843 var w = this.dom.offsetWidth || 0;
7844 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7848 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7849 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7850 * if a height has not been set using CSS.
7853 getComputedHeight : function(){
7854 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7856 h = parseInt(this.getStyle('height'), 10) || 0;
7857 if(!this.isBorderBox()){
7858 h += this.getFrameWidth('tb');
7865 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7866 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7867 * if a width has not been set using CSS.
7870 getComputedWidth : function(){
7871 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7873 w = parseInt(this.getStyle('width'), 10) || 0;
7874 if(!this.isBorderBox()){
7875 w += this.getFrameWidth('lr');
7882 * Returns the size of the element.
7883 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7884 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7886 getSize : function(contentSize){
7887 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7891 * Returns the width and height of the viewport.
7892 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7894 getViewSize : function(){
7895 var d = this.dom, doc = document, aw = 0, ah = 0;
7896 if(d == doc || d == doc.body){
7897 return {width : D.getViewWidth(), height: D.getViewHeight()};
7900 width : d.clientWidth,
7901 height: d.clientHeight
7907 * Returns the value of the "value" attribute
7908 * @param {Boolean} asNumber true to parse the value as a number
7909 * @return {String/Number}
7911 getValue : function(asNumber){
7912 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7916 adjustWidth : function(width){
7917 if(typeof width == "number"){
7918 if(this.autoBoxAdjust && !this.isBorderBox()){
7919 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7929 adjustHeight : function(height){
7930 if(typeof height == "number"){
7931 if(this.autoBoxAdjust && !this.isBorderBox()){
7932 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7942 * Set the width of the element
7943 * @param {Number} width The new width
7944 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7945 * @return {Roo.Element} this
7947 setWidth : function(width, animate){
7948 width = this.adjustWidth(width);
7950 this.dom.style.width = this.addUnits(width);
7952 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7958 * Set the height of the element
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 setHeight : function(height, animate){
7964 height = this.adjustHeight(height);
7966 this.dom.style.height = this.addUnits(height);
7968 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7974 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7975 * @param {Number} width The new width
7976 * @param {Number} height The new height
7977 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7978 * @return {Roo.Element} this
7980 setSize : function(width, height, animate){
7981 if(typeof width == "object"){ // in case of object from getSize()
7982 height = width.height; width = width.width;
7984 width = this.adjustWidth(width); height = this.adjustHeight(height);
7986 this.dom.style.width = this.addUnits(width);
7987 this.dom.style.height = this.addUnits(height);
7989 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7995 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7996 * @param {Number} x X value for new position (coordinates are page-based)
7997 * @param {Number} y Y value for new position (coordinates are page-based)
7998 * @param {Number} width The new width
7999 * @param {Number} height The new height
8000 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8001 * @return {Roo.Element} this
8003 setBounds : function(x, y, width, height, animate){
8005 this.setSize(width, height);
8006 this.setLocation(x, y);
8008 width = this.adjustWidth(width); height = this.adjustHeight(height);
8009 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8010 this.preanim(arguments, 4), 'motion');
8016 * 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.
8017 * @param {Roo.lib.Region} region The region to fill
8018 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8019 * @return {Roo.Element} this
8021 setRegion : function(region, animate){
8022 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8027 * Appends an event handler
8029 * @param {String} eventName The type of event to append
8030 * @param {Function} fn The method the event invokes
8031 * @param {Object} scope (optional) The scope (this object) of the fn
8032 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8034 addListener : function(eventName, fn, scope, options){
8036 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8041 * Removes an event handler from this element
8042 * @param {String} eventName the type of event to remove
8043 * @param {Function} fn the method the event invokes
8044 * @return {Roo.Element} this
8046 removeListener : function(eventName, fn){
8047 Roo.EventManager.removeListener(this.dom, eventName, fn);
8052 * Removes all previous added listeners from this element
8053 * @return {Roo.Element} this
8055 removeAllListeners : function(){
8056 E.purgeElement(this.dom);
8060 relayEvent : function(eventName, observable){
8061 this.on(eventName, function(e){
8062 observable.fireEvent(eventName, e);
8067 * Set the opacity of the element
8068 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8069 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8070 * @return {Roo.Element} this
8072 setOpacity : function(opacity, animate){
8074 var s = this.dom.style;
8077 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8078 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8080 s.opacity = opacity;
8083 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8089 * Gets the left X coordinate
8090 * @param {Boolean} local True to get the local css position instead of page coordinate
8093 getLeft : function(local){
8097 return parseInt(this.getStyle("left"), 10) || 0;
8102 * Gets the right X coordinate of the element (element X position + element width)
8103 * @param {Boolean} local True to get the local css position instead of page coordinate
8106 getRight : function(local){
8108 return this.getX() + this.getWidth();
8110 return (this.getLeft(true) + this.getWidth()) || 0;
8115 * Gets the top Y coordinate
8116 * @param {Boolean} local True to get the local css position instead of page coordinate
8119 getTop : function(local) {
8123 return parseInt(this.getStyle("top"), 10) || 0;
8128 * Gets the bottom Y coordinate of the element (element Y position + element height)
8129 * @param {Boolean} local True to get the local css position instead of page coordinate
8132 getBottom : function(local){
8134 return this.getY() + this.getHeight();
8136 return (this.getTop(true) + this.getHeight()) || 0;
8141 * Initializes positioning on this element. If a desired position is not passed, it will make the
8142 * the element positioned relative IF it is not already positioned.
8143 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8144 * @param {Number} zIndex (optional) The zIndex to apply
8145 * @param {Number} x (optional) Set the page X position
8146 * @param {Number} y (optional) Set the page Y position
8148 position : function(pos, zIndex, x, y){
8150 if(this.getStyle('position') == 'static'){
8151 this.setStyle('position', 'relative');
8154 this.setStyle("position", pos);
8157 this.setStyle("z-index", zIndex);
8159 if(x !== undefined && y !== undefined){
8161 }else if(x !== undefined){
8163 }else if(y !== undefined){
8169 * Clear positioning back to the default when the document was loaded
8170 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8171 * @return {Roo.Element} this
8173 clearPositioning : function(value){
8181 "position" : "static"
8187 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8188 * snapshot before performing an update and then restoring the element.
8191 getPositioning : function(){
8192 var l = this.getStyle("left");
8193 var t = this.getStyle("top");
8195 "position" : this.getStyle("position"),
8197 "right" : l ? "" : this.getStyle("right"),
8199 "bottom" : t ? "" : this.getStyle("bottom"),
8200 "z-index" : this.getStyle("z-index")
8205 * Gets the width of the border(s) for the specified side(s)
8206 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8207 * passing lr would get the border (l)eft width + the border (r)ight width.
8208 * @return {Number} The width of the sides passed added together
8210 getBorderWidth : function(side){
8211 return this.addStyles(side, El.borders);
8215 * Gets the width of the padding(s) for the specified side(s)
8216 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8217 * passing lr would get the padding (l)eft + the padding (r)ight.
8218 * @return {Number} The padding of the sides passed added together
8220 getPadding : function(side){
8221 return this.addStyles(side, El.paddings);
8225 * Set positioning with an object returned by getPositioning().
8226 * @param {Object} posCfg
8227 * @return {Roo.Element} this
8229 setPositioning : function(pc){
8230 this.applyStyles(pc);
8231 if(pc.right == "auto"){
8232 this.dom.style.right = "";
8234 if(pc.bottom == "auto"){
8235 this.dom.style.bottom = "";
8241 fixDisplay : function(){
8242 if(this.getStyle("display") == "none"){
8243 this.setStyle("visibility", "hidden");
8244 this.setStyle("display", this.originalDisplay); // first try reverting to default
8245 if(this.getStyle("display") == "none"){ // if that fails, default to block
8246 this.setStyle("display", "block");
8252 * Quick set left and top adding default units
8253 * @param {String} left The left CSS property value
8254 * @param {String} top The top CSS property value
8255 * @return {Roo.Element} this
8257 setLeftTop : function(left, top){
8258 this.dom.style.left = this.addUnits(left);
8259 this.dom.style.top = this.addUnits(top);
8264 * Move this element relative to its current position.
8265 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8266 * @param {Number} distance How far to move the element in pixels
8267 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8268 * @return {Roo.Element} this
8270 move : function(direction, distance, animate){
8271 var xy = this.getXY();
8272 direction = direction.toLowerCase();
8276 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8280 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8285 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8290 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8297 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8298 * @return {Roo.Element} this
8301 if(!this.isClipped){
8302 this.isClipped = true;
8303 this.originalClip = {
8304 "o": this.getStyle("overflow"),
8305 "x": this.getStyle("overflow-x"),
8306 "y": this.getStyle("overflow-y")
8308 this.setStyle("overflow", "hidden");
8309 this.setStyle("overflow-x", "hidden");
8310 this.setStyle("overflow-y", "hidden");
8316 * Return clipping (overflow) to original clipping before clip() was called
8317 * @return {Roo.Element} this
8319 unclip : function(){
8321 this.isClipped = false;
8322 var o = this.originalClip;
8323 if(o.o){this.setStyle("overflow", o.o);}
8324 if(o.x){this.setStyle("overflow-x", o.x);}
8325 if(o.y){this.setStyle("overflow-y", o.y);}
8332 * Gets the x,y coordinates specified by the anchor position on the element.
8333 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8334 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8335 * {width: (target width), height: (target height)} (defaults to the element's current size)
8336 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8337 * @return {Array} [x, y] An array containing the element's x and y coordinates
8339 getAnchorXY : function(anchor, local, s){
8340 //Passing a different size is useful for pre-calculating anchors,
8341 //especially for anchored animations that change the el size.
8343 var w, h, vp = false;
8346 if(d == document.body || d == document){
8348 w = D.getViewWidth(); h = D.getViewHeight();
8350 w = this.getWidth(); h = this.getHeight();
8353 w = s.width; h = s.height;
8355 var x = 0, y = 0, r = Math.round;
8356 switch((anchor || "tl").toLowerCase()){
8398 var sc = this.getScroll();
8399 return [x + sc.left, y + sc.top];
8401 //Add the element's offset xy
8402 var o = this.getXY();
8403 return [x+o[0], y+o[1]];
8407 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8408 * supported position values.
8409 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8410 * @param {String} position The position to align to.
8411 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8412 * @return {Array} [x, y]
8414 getAlignToXY : function(el, p, o){
8418 throw "Element.alignTo with an element that doesn't exist";
8420 var c = false; //constrain to viewport
8421 var p1 = "", p2 = "";
8428 }else if(p.indexOf("-") == -1){
8431 p = p.toLowerCase();
8432 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8434 throw "Element.alignTo with an invalid alignment " + p;
8436 p1 = m[1]; p2 = m[2]; c = !!m[3];
8438 //Subtract the aligned el's internal xy from the target's offset xy
8439 //plus custom offset to get the aligned el's new offset xy
8440 var a1 = this.getAnchorXY(p1, true);
8441 var a2 = el.getAnchorXY(p2, false);
8442 var x = a2[0] - a1[0] + o[0];
8443 var y = a2[1] - a1[1] + o[1];
8445 //constrain the aligned el to viewport if necessary
8446 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8447 // 5px of margin for ie
8448 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8450 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8451 //perpendicular to the vp border, allow the aligned el to slide on that border,
8452 //otherwise swap the aligned el to the opposite border of the target.
8453 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8454 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8455 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8456 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8459 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8460 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8462 if((x+w) > dw + scrollX){
8463 x = swapX ? r.left-w : dw+scrollX-w;
8466 x = swapX ? r.right : scrollX;
8468 if((y+h) > dh + scrollY){
8469 y = swapY ? r.top-h : dh+scrollY-h;
8472 y = swapY ? r.bottom : scrollY;
8479 getConstrainToXY : function(){
8480 var os = {top:0, left:0, bottom:0, right: 0};
8482 return function(el, local, offsets, proposedXY){
8484 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8486 var vw, vh, vx = 0, vy = 0;
8487 if(el.dom == document.body || el.dom == document){
8488 vw = Roo.lib.Dom.getViewWidth();
8489 vh = Roo.lib.Dom.getViewHeight();
8491 vw = el.dom.clientWidth;
8492 vh = el.dom.clientHeight;
8494 var vxy = el.getXY();
8500 var s = el.getScroll();
8502 vx += offsets.left + s.left;
8503 vy += offsets.top + s.top;
8505 vw -= offsets.right;
8506 vh -= offsets.bottom;
8511 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8512 var x = xy[0], y = xy[1];
8513 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8515 // only move it if it needs it
8518 // first validate right/bottom
8527 // then make sure top/left isn't negative
8536 return moved ? [x, y] : false;
8541 adjustForConstraints : function(xy, parent, offsets){
8542 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8546 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8547 * document it aligns it to the viewport.
8548 * The position parameter is optional, and can be specified in any one of the following formats:
8550 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8551 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8552 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8553 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8554 * <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
8555 * element's anchor point, and the second value is used as the target's anchor point.</li>
8557 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8558 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8559 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8560 * that specified in order to enforce the viewport constraints.
8561 * Following are all of the supported anchor positions:
8564 ----- -----------------------------
8565 tl The top left corner (default)
8566 t The center of the top edge
8567 tr The top right corner
8568 l The center of the left edge
8569 c In the center of the element
8570 r The center of the right edge
8571 bl The bottom left corner
8572 b The center of the bottom edge
8573 br The bottom right corner
8577 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8578 el.alignTo("other-el");
8580 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8581 el.alignTo("other-el", "tr?");
8583 // align the bottom right corner of el with the center left edge of other-el
8584 el.alignTo("other-el", "br-l?");
8586 // align the center of el with the bottom left corner of other-el and
8587 // adjust the x position by -6 pixels (and the y position by 0)
8588 el.alignTo("other-el", "c-bl", [-6, 0]);
8590 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8591 * @param {String} position The position to align to.
8592 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8593 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8594 * @return {Roo.Element} this
8596 alignTo : function(element, position, offsets, animate){
8597 var xy = this.getAlignToXY(element, position, offsets);
8598 this.setXY(xy, this.preanim(arguments, 3));
8603 * Anchors an element to another element and realigns it when the window is resized.
8604 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8605 * @param {String} position The position to align to.
8606 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8607 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8608 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8609 * is a number, it is used as the buffer delay (defaults to 50ms).
8610 * @param {Function} callback The function to call after the animation finishes
8611 * @return {Roo.Element} this
8613 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8614 var action = function(){
8615 this.alignTo(el, alignment, offsets, animate);
8616 Roo.callback(callback, this);
8618 Roo.EventManager.onWindowResize(action, this);
8619 var tm = typeof monitorScroll;
8620 if(tm != 'undefined'){
8621 Roo.EventManager.on(window, 'scroll', action, this,
8622 {buffer: tm == 'number' ? monitorScroll : 50});
8624 action.call(this); // align immediately
8628 * Clears any opacity settings from this element. Required in some cases for IE.
8629 * @return {Roo.Element} this
8631 clearOpacity : function(){
8632 if (window.ActiveXObject) {
8633 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8634 this.dom.style.filter = "";
8637 this.dom.style.opacity = "";
8638 this.dom.style["-moz-opacity"] = "";
8639 this.dom.style["-khtml-opacity"] = "";
8645 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8646 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8647 * @return {Roo.Element} this
8649 hide : function(animate){
8650 this.setVisible(false, this.preanim(arguments, 0));
8655 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8656 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8657 * @return {Roo.Element} this
8659 show : function(animate){
8660 this.setVisible(true, this.preanim(arguments, 0));
8665 * @private Test if size has a unit, otherwise appends the default
8667 addUnits : function(size){
8668 return Roo.Element.addUnits(size, this.defaultUnit);
8672 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8673 * @return {Roo.Element} this
8675 beginMeasure : function(){
8677 if(el.offsetWidth || el.offsetHeight){
8678 return this; // offsets work already
8681 var p = this.dom, b = document.body; // start with this element
8682 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8683 var pe = Roo.get(p);
8684 if(pe.getStyle('display') == 'none'){
8685 changed.push({el: p, visibility: pe.getStyle("visibility")});
8686 p.style.visibility = "hidden";
8687 p.style.display = "block";
8691 this._measureChanged = changed;
8697 * Restores displays to before beginMeasure was called
8698 * @return {Roo.Element} this
8700 endMeasure : function(){
8701 var changed = this._measureChanged;
8703 for(var i = 0, len = changed.length; i < len; i++) {
8705 r.el.style.visibility = r.visibility;
8706 r.el.style.display = "none";
8708 this._measureChanged = null;
8714 * Update the innerHTML of this element, optionally searching for and processing scripts
8715 * @param {String} html The new HTML
8716 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8717 * @param {Function} callback For async script loading you can be noticed when the update completes
8718 * @return {Roo.Element} this
8720 update : function(html, loadScripts, callback){
8721 if(typeof html == "undefined"){
8724 if(loadScripts !== true){
8725 this.dom.innerHTML = html;
8726 if(typeof callback == "function"){
8734 html += '<span id="' + id + '"></span>';
8736 E.onAvailable(id, function(){
8737 var hd = document.getElementsByTagName("head")[0];
8738 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8739 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8740 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8743 while(match = re.exec(html)){
8744 var attrs = match[1];
8745 var srcMatch = attrs ? attrs.match(srcRe) : false;
8746 if(srcMatch && srcMatch[2]){
8747 var s = document.createElement("script");
8748 s.src = srcMatch[2];
8749 var typeMatch = attrs.match(typeRe);
8750 if(typeMatch && typeMatch[2]){
8751 s.type = typeMatch[2];
8754 }else if(match[2] && match[2].length > 0){
8755 if(window.execScript) {
8756 window.execScript(match[2]);
8764 window.eval(match[2]);
8768 var el = document.getElementById(id);
8769 if(el){el.parentNode.removeChild(el);}
8770 if(typeof callback == "function"){
8774 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8779 * Direct access to the UpdateManager update() method (takes the same parameters).
8780 * @param {String/Function} url The url for this request or a function to call to get the url
8781 * @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}
8782 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8783 * @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.
8784 * @return {Roo.Element} this
8787 var um = this.getUpdateManager();
8788 um.update.apply(um, arguments);
8793 * Gets this element's UpdateManager
8794 * @return {Roo.UpdateManager} The UpdateManager
8796 getUpdateManager : function(){
8797 if(!this.updateManager){
8798 this.updateManager = new Roo.UpdateManager(this);
8800 return this.updateManager;
8804 * Disables text selection for this element (normalized across browsers)
8805 * @return {Roo.Element} this
8807 unselectable : function(){
8808 this.dom.unselectable = "on";
8809 this.swallowEvent("selectstart", true);
8810 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8811 this.addClass("x-unselectable");
8816 * Calculates the x, y to center this element on the screen
8817 * @return {Array} The x, y values [x, y]
8819 getCenterXY : function(){
8820 return this.getAlignToXY(document, 'c-c');
8824 * Centers the Element in either the viewport, or another Element.
8825 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8827 center : function(centerIn){
8828 this.alignTo(centerIn || document, 'c-c');
8833 * Tests various css rules/browsers to determine if this element uses a border box
8836 isBorderBox : function(){
8837 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8841 * Return a box {x, y, width, height} that can be used to set another elements
8842 * size/location to match this element.
8843 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8844 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8845 * @return {Object} box An object in the format {x, y, width, height}
8847 getBox : function(contentBox, local){
8852 var left = parseInt(this.getStyle("left"), 10) || 0;
8853 var top = parseInt(this.getStyle("top"), 10) || 0;
8856 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8858 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8860 var l = this.getBorderWidth("l")+this.getPadding("l");
8861 var r = this.getBorderWidth("r")+this.getPadding("r");
8862 var t = this.getBorderWidth("t")+this.getPadding("t");
8863 var b = this.getBorderWidth("b")+this.getPadding("b");
8864 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)};
8866 bx.right = bx.x + bx.width;
8867 bx.bottom = bx.y + bx.height;
8872 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8873 for more information about the sides.
8874 * @param {String} sides
8877 getFrameWidth : function(sides, onlyContentBox){
8878 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8882 * 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.
8883 * @param {Object} box The box to fill {x, y, width, height}
8884 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8885 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8886 * @return {Roo.Element} this
8888 setBox : function(box, adjust, animate){
8889 var w = box.width, h = box.height;
8890 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8891 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8892 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8894 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8899 * Forces the browser to repaint this element
8900 * @return {Roo.Element} this
8902 repaint : function(){
8904 this.addClass("x-repaint");
8905 setTimeout(function(){
8906 Roo.get(dom).removeClass("x-repaint");
8912 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8913 * then it returns the calculated width of the sides (see getPadding)
8914 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8915 * @return {Object/Number}
8917 getMargins : function(side){
8920 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8921 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8922 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8923 right: parseInt(this.getStyle("margin-right"), 10) || 0
8926 return this.addStyles(side, El.margins);
8931 addStyles : function(sides, styles){
8933 for(var i = 0, len = sides.length; i < len; i++){
8934 v = this.getStyle(styles[sides.charAt(i)]);
8936 w = parseInt(v, 10);
8944 * Creates a proxy element of this element
8945 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8946 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8947 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8948 * @return {Roo.Element} The new proxy element
8950 createProxy : function(config, renderTo, matchBox){
8952 renderTo = Roo.getDom(renderTo);
8954 renderTo = document.body;
8956 config = typeof config == "object" ?
8957 config : {tag : "div", cls: config};
8958 var proxy = Roo.DomHelper.append(renderTo, config, true);
8960 proxy.setBox(this.getBox());
8966 * Puts a mask over this element to disable user interaction. Requires core.css.
8967 * This method can only be applied to elements which accept child nodes.
8968 * @param {String} msg (optional) A message to display in the mask
8969 * @param {String} msgCls (optional) A css class to apply to the msg element
8970 * @return {Element} The mask element
8972 mask : function(msg, msgCls)
8974 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8975 this.setStyle("position", "relative");
8978 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8980 this.addClass("x-masked");
8981 this._mask.setDisplayed(true);
8986 while (dom && dom.style) {
8987 if (!isNaN(parseInt(dom.style.zIndex))) {
8988 z = Math.max(z, parseInt(dom.style.zIndex));
8990 dom = dom.parentNode;
8992 // if we are masking the body - then it hides everything..
8993 if (this.dom == document.body) {
8995 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8996 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8999 if(typeof msg == 'string'){
9001 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9003 var mm = this._maskMsg;
9004 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9005 mm.dom.firstChild.innerHTML = msg;
9006 mm.setDisplayed(true);
9008 mm.setStyle('z-index', z + 102);
9010 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9011 this._mask.setHeight(this.getHeight());
9013 this._mask.setStyle('z-index', z + 100);
9019 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9020 * it is cached for reuse.
9022 unmask : function(removeEl){
9024 if(removeEl === true){
9025 this._mask.remove();
9028 this._maskMsg.remove();
9029 delete this._maskMsg;
9032 this._mask.setDisplayed(false);
9034 this._maskMsg.setDisplayed(false);
9038 this.removeClass("x-masked");
9042 * Returns true if this element is masked
9045 isMasked : function(){
9046 return this._mask && this._mask.isVisible();
9050 * Creates an iframe shim for this element to keep selects and other windowed objects from
9052 * @return {Roo.Element} The new shim element
9054 createShim : function(){
9055 var el = document.createElement('iframe');
9056 el.frameBorder = 'no';
9057 el.className = 'roo-shim';
9058 if(Roo.isIE && Roo.isSecure){
9059 el.src = Roo.SSL_SECURE_URL;
9061 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9062 shim.autoBoxAdjust = false;
9067 * Removes this element from the DOM and deletes it from the cache
9069 remove : function(){
9070 if(this.dom.parentNode){
9071 this.dom.parentNode.removeChild(this.dom);
9073 delete El.cache[this.dom.id];
9077 * Sets up event handlers to add and remove a css class when the mouse is over this element
9078 * @param {String} className
9079 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9080 * mouseout events for children elements
9081 * @return {Roo.Element} this
9083 addClassOnOver : function(className, preventFlicker){
9084 this.on("mouseover", function(){
9085 Roo.fly(this, '_internal').addClass(className);
9087 var removeFn = function(e){
9088 if(preventFlicker !== true || !e.within(this, true)){
9089 Roo.fly(this, '_internal').removeClass(className);
9092 this.on("mouseout", removeFn, this.dom);
9097 * Sets up event handlers to add and remove a css class when this element has the focus
9098 * @param {String} className
9099 * @return {Roo.Element} this
9101 addClassOnFocus : function(className){
9102 this.on("focus", function(){
9103 Roo.fly(this, '_internal').addClass(className);
9105 this.on("blur", function(){
9106 Roo.fly(this, '_internal').removeClass(className);
9111 * 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)
9112 * @param {String} className
9113 * @return {Roo.Element} this
9115 addClassOnClick : function(className){
9117 this.on("mousedown", function(){
9118 Roo.fly(dom, '_internal').addClass(className);
9119 var d = Roo.get(document);
9120 var fn = function(){
9121 Roo.fly(dom, '_internal').removeClass(className);
9122 d.removeListener("mouseup", fn);
9124 d.on("mouseup", fn);
9130 * Stops the specified event from bubbling and optionally prevents the default action
9131 * @param {String} eventName
9132 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9133 * @return {Roo.Element} this
9135 swallowEvent : function(eventName, preventDefault){
9136 var fn = function(e){
9137 e.stopPropagation();
9142 if(eventName instanceof Array){
9143 for(var i = 0, len = eventName.length; i < len; i++){
9144 this.on(eventName[i], fn);
9148 this.on(eventName, fn);
9155 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9158 * Sizes this element to its parent element's dimensions performing
9159 * neccessary box adjustments.
9160 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9161 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9162 * @return {Roo.Element} this
9164 fitToParent : function(monitorResize, targetParent) {
9165 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9166 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9167 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9170 var p = Roo.get(targetParent || this.dom.parentNode);
9171 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9172 if (monitorResize === true) {
9173 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9174 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9180 * Gets the next sibling, skipping text nodes
9181 * @return {HTMLElement} The next sibling or null
9183 getNextSibling : function(){
9184 var n = this.dom.nextSibling;
9185 while(n && n.nodeType != 1){
9192 * Gets the previous sibling, skipping text nodes
9193 * @return {HTMLElement} The previous sibling or null
9195 getPrevSibling : function(){
9196 var n = this.dom.previousSibling;
9197 while(n && n.nodeType != 1){
9198 n = n.previousSibling;
9205 * Appends the passed element(s) to this element
9206 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9207 * @return {Roo.Element} this
9209 appendChild: function(el){
9216 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9217 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9218 * automatically generated with the specified attributes.
9219 * @param {HTMLElement} insertBefore (optional) a child element of this element
9220 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9221 * @return {Roo.Element} The new child element
9223 createChild: function(config, insertBefore, returnDom){
9224 config = config || {tag:'div'};
9226 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9228 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9232 * Appends this element to the passed element
9233 * @param {String/HTMLElement/Element} el The new parent element
9234 * @return {Roo.Element} this
9236 appendTo: function(el){
9237 el = Roo.getDom(el);
9238 el.appendChild(this.dom);
9243 * Inserts this element before the passed element in the DOM
9244 * @param {String/HTMLElement/Element} el The element to insert before
9245 * @return {Roo.Element} this
9247 insertBefore: function(el){
9248 el = Roo.getDom(el);
9249 el.parentNode.insertBefore(this.dom, el);
9254 * Inserts this element after the passed element in the DOM
9255 * @param {String/HTMLElement/Element} el The element to insert after
9256 * @return {Roo.Element} this
9258 insertAfter: function(el){
9259 el = Roo.getDom(el);
9260 el.parentNode.insertBefore(this.dom, el.nextSibling);
9265 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9266 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9267 * @return {Roo.Element} The new child
9269 insertFirst: function(el, returnDom){
9271 if(typeof el == 'object' && !el.nodeType){ // dh config
9272 return this.createChild(el, this.dom.firstChild, returnDom);
9274 el = Roo.getDom(el);
9275 this.dom.insertBefore(el, this.dom.firstChild);
9276 return !returnDom ? Roo.get(el) : el;
9281 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9282 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9283 * @param {String} where (optional) 'before' or 'after' defaults to before
9284 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9285 * @return {Roo.Element} the inserted Element
9287 insertSibling: function(el, where, returnDom){
9288 where = where ? where.toLowerCase() : 'before';
9290 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9292 if(typeof el == 'object' && !el.nodeType){ // dh config
9293 if(where == 'after' && !this.dom.nextSibling){
9294 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9296 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9300 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9301 where == 'before' ? this.dom : this.dom.nextSibling);
9310 * Creates and wraps this element with another element
9311 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9312 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9313 * @return {HTMLElement/Element} The newly created wrapper element
9315 wrap: function(config, returnDom){
9317 config = {tag: "div"};
9319 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9320 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9325 * Replaces the passed element with this element
9326 * @param {String/HTMLElement/Element} el The element to replace
9327 * @return {Roo.Element} this
9329 replace: function(el){
9331 this.insertBefore(el);
9337 * Inserts an html fragment into this element
9338 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9339 * @param {String} html The HTML fragment
9340 * @param {Boolean} returnEl True to return an Roo.Element
9341 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9343 insertHtml : function(where, html, returnEl){
9344 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9345 return returnEl ? Roo.get(el) : el;
9349 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9350 * @param {Object} o The object with the attributes
9351 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9352 * @return {Roo.Element} this
9354 set : function(o, useSet){
9356 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9358 if(attr == "style" || typeof o[attr] == "function") continue;
9360 el.className = o["cls"];
9362 if(useSet) el.setAttribute(attr, o[attr]);
9363 else el[attr] = o[attr];
9367 Roo.DomHelper.applyStyles(el, o.style);
9373 * Convenience method for constructing a KeyMap
9374 * @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:
9375 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9376 * @param {Function} fn The function to call
9377 * @param {Object} scope (optional) The scope of the function
9378 * @return {Roo.KeyMap} The KeyMap created
9380 addKeyListener : function(key, fn, scope){
9382 if(typeof key != "object" || key instanceof Array){
9398 return new Roo.KeyMap(this, config);
9402 * Creates a KeyMap for this element
9403 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9404 * @return {Roo.KeyMap} The KeyMap created
9406 addKeyMap : function(config){
9407 return new Roo.KeyMap(this, config);
9411 * Returns true if this element is scrollable.
9414 isScrollable : function(){
9416 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9420 * 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().
9421 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9422 * @param {Number} value The new scroll value
9423 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9424 * @return {Element} this
9427 scrollTo : function(side, value, animate){
9428 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9430 this.dom[prop] = value;
9432 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9433 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9439 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9440 * within this element's scrollable range.
9441 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9442 * @param {Number} distance How far to scroll the element in pixels
9443 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9444 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9445 * was scrolled as far as it could go.
9447 scroll : function(direction, distance, animate){
9448 if(!this.isScrollable()){
9452 var l = el.scrollLeft, t = el.scrollTop;
9453 var w = el.scrollWidth, h = el.scrollHeight;
9454 var cw = el.clientWidth, ch = el.clientHeight;
9455 direction = direction.toLowerCase();
9456 var scrolled = false;
9457 var a = this.preanim(arguments, 2);
9462 var v = Math.min(l + distance, w-cw);
9463 this.scrollTo("left", v, a);
9470 var v = Math.max(l - distance, 0);
9471 this.scrollTo("left", v, a);
9479 var v = Math.max(t - distance, 0);
9480 this.scrollTo("top", v, a);
9488 var v = Math.min(t + distance, h-ch);
9489 this.scrollTo("top", v, a);
9498 * Translates the passed page coordinates into left/top css values for this element
9499 * @param {Number/Array} x The page x or an array containing [x, y]
9500 * @param {Number} y The page y
9501 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9503 translatePoints : function(x, y){
9504 if(typeof x == 'object' || x instanceof Array){
9507 var p = this.getStyle('position');
9508 var o = this.getXY();
9510 var l = parseInt(this.getStyle('left'), 10);
9511 var t = parseInt(this.getStyle('top'), 10);
9514 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9517 t = (p == "relative") ? 0 : this.dom.offsetTop;
9520 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9524 * Returns the current scroll position of the element.
9525 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9527 getScroll : function(){
9528 var d = this.dom, doc = document;
9529 if(d == doc || d == doc.body){
9530 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9531 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9532 return {left: l, top: t};
9534 return {left: d.scrollLeft, top: d.scrollTop};
9539 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9540 * are convert to standard 6 digit hex color.
9541 * @param {String} attr The css attribute
9542 * @param {String} defaultValue The default value to use when a valid color isn't found
9543 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9546 getColor : function(attr, defaultValue, prefix){
9547 var v = this.getStyle(attr);
9548 if(!v || v == "transparent" || v == "inherit") {
9549 return defaultValue;
9551 var color = typeof prefix == "undefined" ? "#" : prefix;
9552 if(v.substr(0, 4) == "rgb("){
9553 var rvs = v.slice(4, v.length -1).split(",");
9554 for(var i = 0; i < 3; i++){
9555 var h = parseInt(rvs[i]).toString(16);
9562 if(v.substr(0, 1) == "#"){
9564 for(var i = 1; i < 4; i++){
9565 var c = v.charAt(i);
9568 }else if(v.length == 7){
9569 color += v.substr(1);
9573 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9577 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9578 * gradient background, rounded corners and a 4-way shadow.
9579 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9580 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9581 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9582 * @return {Roo.Element} this
9584 boxWrap : function(cls){
9585 cls = cls || 'x-box';
9586 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9587 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9592 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9593 * @param {String} namespace The namespace in which to look for the attribute
9594 * @param {String} name The attribute name
9595 * @return {String} The attribute value
9597 getAttributeNS : Roo.isIE ? function(ns, name){
9599 var type = typeof d[ns+":"+name];
9600 if(type != 'undefined' && type != 'unknown'){
9601 return d[ns+":"+name];
9604 } : function(ns, name){
9606 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9611 * Sets or Returns the value the dom attribute value
9612 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9613 * @param {String} value (optional) The value to set the attribute to
9614 * @return {String} The attribute value
9616 attr : function(name){
9617 if (arguments.length > 1) {
9618 this.dom.setAttribute(name, arguments[1]);
9619 return arguments[1];
9621 if (typeof(name) == 'object') {
9622 for(var i in name) {
9623 this.attr(i, name[i]);
9629 if (!this.dom.hasAttribute(name)) {
9632 return this.dom.getAttribute(name);
9639 var ep = El.prototype;
9642 * Appends an event handler (Shorthand for addListener)
9643 * @param {String} eventName The type of event to append
9644 * @param {Function} fn The method the event invokes
9645 * @param {Object} scope (optional) The scope (this object) of the fn
9646 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9649 ep.on = ep.addListener;
9651 ep.mon = ep.addListener;
9654 * Removes an event handler from this element (shorthand for removeListener)
9655 * @param {String} eventName the type of event to remove
9656 * @param {Function} fn the method the event invokes
9657 * @return {Roo.Element} this
9660 ep.un = ep.removeListener;
9663 * true to automatically adjust width and height settings for box-model issues (default to true)
9665 ep.autoBoxAdjust = true;
9668 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9671 El.addUnits = function(v, defaultUnit){
9672 if(v === "" || v == "auto"){
9675 if(v === undefined){
9678 if(typeof v == "number" || !El.unitPattern.test(v)){
9679 return v + (defaultUnit || 'px');
9684 // special markup used throughout Roo when box wrapping elements
9685 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>';
9687 * Visibility mode constant - Use visibility to hide element
9693 * Visibility mode constant - Use display to hide element
9699 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9700 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9701 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9713 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9714 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9715 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9716 * @return {Element} The Element object
9719 El.get = function(el){
9721 if(!el){ return null; }
9722 if(typeof el == "string"){ // element id
9723 if(!(elm = document.getElementById(el))){
9726 if(ex = El.cache[el]){
9729 ex = El.cache[el] = new El(elm);
9732 }else if(el.tagName){ // dom element
9736 if(ex = El.cache[id]){
9739 ex = El.cache[id] = new El(el);
9742 }else if(el instanceof El){
9744 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9745 // catch case where it hasn't been appended
9746 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9749 }else if(el.isComposite){
9751 }else if(el instanceof Array){
9752 return El.select(el);
9753 }else if(el == document){
9754 // create a bogus element object representing the document object
9756 var f = function(){};
9757 f.prototype = El.prototype;
9759 docEl.dom = document;
9767 El.uncache = function(el){
9768 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9770 delete El.cache[a[i].id || a[i]];
9776 // Garbage collection - uncache elements/purge listeners on orphaned elements
9777 // so we don't hold a reference and cause the browser to retain them
9778 El.garbageCollect = function(){
9779 if(!Roo.enableGarbageCollector){
9780 clearInterval(El.collectorThread);
9783 for(var eid in El.cache){
9784 var el = El.cache[eid], d = el.dom;
9785 // -------------------------------------------------------
9786 // Determining what is garbage:
9787 // -------------------------------------------------------
9789 // dom node is null, definitely garbage
9790 // -------------------------------------------------------
9792 // no parentNode == direct orphan, definitely garbage
9793 // -------------------------------------------------------
9794 // !d.offsetParent && !document.getElementById(eid)
9795 // display none elements have no offsetParent so we will
9796 // also try to look it up by it's id. However, check
9797 // offsetParent first so we don't do unneeded lookups.
9798 // This enables collection of elements that are not orphans
9799 // directly, but somewhere up the line they have an orphan
9801 // -------------------------------------------------------
9802 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9803 delete El.cache[eid];
9804 if(d && Roo.enableListenerCollection){
9810 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9814 El.Flyweight = function(dom){
9817 El.Flyweight.prototype = El.prototype;
9819 El._flyweights = {};
9821 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9822 * the dom node can be overwritten by other code.
9823 * @param {String/HTMLElement} el The dom node or id
9824 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9825 * prevent conflicts (e.g. internally Roo uses "_internal")
9827 * @return {Element} The shared Element object
9829 El.fly = function(el, named){
9830 named = named || '_global';
9831 el = Roo.getDom(el);
9835 if(!El._flyweights[named]){
9836 El._flyweights[named] = new El.Flyweight();
9838 El._flyweights[named].dom = el;
9839 return El._flyweights[named];
9843 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9844 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9845 * Shorthand of {@link Roo.Element#get}
9846 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9847 * @return {Element} The Element object
9853 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9854 * the dom node can be overwritten by other code.
9855 * Shorthand of {@link Roo.Element#fly}
9856 * @param {String/HTMLElement} el The dom node or id
9857 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9858 * prevent conflicts (e.g. internally Roo uses "_internal")
9860 * @return {Element} The shared Element object
9866 // speedy lookup for elements never to box adjust
9867 var noBoxAdjust = Roo.isStrict ? {
9870 input:1, select:1, textarea:1
9872 if(Roo.isIE || Roo.isGecko){
9873 noBoxAdjust['button'] = 1;
9877 Roo.EventManager.on(window, 'unload', function(){
9879 delete El._flyweights;
9887 Roo.Element.selectorFunction = Roo.DomQuery.select;
9890 Roo.Element.select = function(selector, unique, root){
9892 if(typeof selector == "string"){
9893 els = Roo.Element.selectorFunction(selector, root);
9894 }else if(selector.length !== undefined){
9897 throw "Invalid selector";
9899 if(unique === true){
9900 return new Roo.CompositeElement(els);
9902 return new Roo.CompositeElementLite(els);
9906 * Selects elements based on the passed CSS selector to enable working on them as 1.
9907 * @param {String/Array} selector The CSS selector or an array of elements
9908 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9909 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9910 * @return {CompositeElementLite/CompositeElement}
9914 Roo.select = Roo.Element.select;
9931 * Ext JS Library 1.1.1
9932 * Copyright(c) 2006-2007, Ext JS, LLC.
9934 * Originally Released Under LGPL - original licence link has changed is not relivant.
9937 * <script type="text/javascript">
9942 //Notifies Element that fx methods are available
9943 Roo.enableFx = true;
9947 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9948 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9949 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9950 * Element effects to work.</p><br/>
9952 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9953 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9954 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9955 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9956 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9957 * expected results and should be done with care.</p><br/>
9959 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9960 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9963 ----- -----------------------------
9964 tl The top left corner
9965 t The center of the top edge
9966 tr The top right corner
9967 l The center of the left edge
9968 r The center of the right edge
9969 bl The bottom left corner
9970 b The center of the bottom edge
9971 br The bottom right corner
9973 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9974 * below are common options that can be passed to any Fx method.</b>
9975 * @cfg {Function} callback A function called when the effect is finished
9976 * @cfg {Object} scope The scope of the effect function
9977 * @cfg {String} easing A valid Easing value for the effect
9978 * @cfg {String} afterCls A css class to apply after the effect
9979 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9980 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9981 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9982 * effects that end with the element being visually hidden, ignored otherwise)
9983 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9984 * a function which returns such a specification that will be applied to the Element after the effect finishes
9985 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9986 * @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
9987 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9991 * Slides the element into view. An anchor point can be optionally passed to set the point of
9992 * origin for the slide effect. This function automatically handles wrapping the element with
9993 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9996 // default: slide the element in from the top
9999 // custom: slide the element in from the right with a 2-second duration
10000 el.slideIn('r', { duration: 2 });
10002 // common config options shown with default values
10008 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10009 * @param {Object} options (optional) Object literal with any of the Fx config options
10010 * @return {Roo.Element} The Element
10012 slideIn : function(anchor, o){
10013 var el = this.getFxEl();
10016 el.queueFx(o, function(){
10018 anchor = anchor || "t";
10020 // fix display to visibility
10023 // restore values after effect
10024 var r = this.getFxRestore();
10025 var b = this.getBox();
10026 // fixed size for slide
10030 var wrap = this.fxWrap(r.pos, o, "hidden");
10032 var st = this.dom.style;
10033 st.visibility = "visible";
10034 st.position = "absolute";
10036 // clear out temp styles after slide and unwrap
10037 var after = function(){
10038 el.fxUnwrap(wrap, r.pos, o);
10039 st.width = r.width;
10040 st.height = r.height;
10043 // time to calc the positions
10044 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10046 switch(anchor.toLowerCase()){
10048 wrap.setSize(b.width, 0);
10049 st.left = st.bottom = "0";
10053 wrap.setSize(0, b.height);
10054 st.right = st.top = "0";
10058 wrap.setSize(0, b.height);
10059 wrap.setX(b.right);
10060 st.left = st.top = "0";
10061 a = {width: bw, points: pt};
10064 wrap.setSize(b.width, 0);
10065 wrap.setY(b.bottom);
10066 st.left = st.top = "0";
10067 a = {height: bh, points: pt};
10070 wrap.setSize(0, 0);
10071 st.right = st.bottom = "0";
10072 a = {width: bw, height: bh};
10075 wrap.setSize(0, 0);
10076 wrap.setY(b.y+b.height);
10077 st.right = st.top = "0";
10078 a = {width: bw, height: bh, points: pt};
10081 wrap.setSize(0, 0);
10082 wrap.setXY([b.right, b.bottom]);
10083 st.left = st.top = "0";
10084 a = {width: bw, height: bh, points: pt};
10087 wrap.setSize(0, 0);
10088 wrap.setX(b.x+b.width);
10089 st.left = st.bottom = "0";
10090 a = {width: bw, height: bh, points: pt};
10093 this.dom.style.visibility = "visible";
10096 arguments.callee.anim = wrap.fxanim(a,
10106 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10107 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10108 * 'hidden') but block elements will still take up space in the document. The element must be removed
10109 * from the DOM using the 'remove' config option if desired. This function automatically handles
10110 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10113 // default: slide the element out to the top
10116 // custom: slide the element out to the right with a 2-second duration
10117 el.slideOut('r', { duration: 2 });
10119 // common config options shown with default values
10127 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10128 * @param {Object} options (optional) Object literal with any of the Fx config options
10129 * @return {Roo.Element} The Element
10131 slideOut : function(anchor, o){
10132 var el = this.getFxEl();
10135 el.queueFx(o, function(){
10137 anchor = anchor || "t";
10139 // restore values after effect
10140 var r = this.getFxRestore();
10142 var b = this.getBox();
10143 // fixed size for slide
10147 var wrap = this.fxWrap(r.pos, o, "visible");
10149 var st = this.dom.style;
10150 st.visibility = "visible";
10151 st.position = "absolute";
10155 var after = function(){
10157 el.setDisplayed(false);
10162 el.fxUnwrap(wrap, r.pos, o);
10164 st.width = r.width;
10165 st.height = r.height;
10170 var a, zero = {to: 0};
10171 switch(anchor.toLowerCase()){
10173 st.left = st.bottom = "0";
10174 a = {height: zero};
10177 st.right = st.top = "0";
10181 st.left = st.top = "0";
10182 a = {width: zero, points: {to:[b.right, b.y]}};
10185 st.left = st.top = "0";
10186 a = {height: zero, points: {to:[b.x, b.bottom]}};
10189 st.right = st.bottom = "0";
10190 a = {width: zero, height: zero};
10193 st.right = st.top = "0";
10194 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10197 st.left = st.top = "0";
10198 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10201 st.left = st.bottom = "0";
10202 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10206 arguments.callee.anim = wrap.fxanim(a,
10216 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10217 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10218 * The element must be removed from the DOM using the 'remove' config option if desired.
10224 // common config options shown with default values
10232 * @param {Object} options (optional) Object literal with any of the Fx config options
10233 * @return {Roo.Element} The Element
10235 puff : function(o){
10236 var el = this.getFxEl();
10239 el.queueFx(o, function(){
10240 this.clearOpacity();
10243 // restore values after effect
10244 var r = this.getFxRestore();
10245 var st = this.dom.style;
10247 var after = function(){
10249 el.setDisplayed(false);
10256 el.setPositioning(r.pos);
10257 st.width = r.width;
10258 st.height = r.height;
10263 var width = this.getWidth();
10264 var height = this.getHeight();
10266 arguments.callee.anim = this.fxanim({
10267 width : {to: this.adjustWidth(width * 2)},
10268 height : {to: this.adjustHeight(height * 2)},
10269 points : {by: [-(width * .5), -(height * .5)]},
10271 fontSize: {to:200, unit: "%"}
10282 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10283 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10284 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10290 // all config options shown with default values
10298 * @param {Object} options (optional) Object literal with any of the Fx config options
10299 * @return {Roo.Element} The Element
10301 switchOff : function(o){
10302 var el = this.getFxEl();
10305 el.queueFx(o, function(){
10306 this.clearOpacity();
10309 // restore values after effect
10310 var r = this.getFxRestore();
10311 var st = this.dom.style;
10313 var after = function(){
10315 el.setDisplayed(false);
10321 el.setPositioning(r.pos);
10322 st.width = r.width;
10323 st.height = r.height;
10328 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10329 this.clearOpacity();
10333 points:{by:[0, this.getHeight() * .5]}
10334 }, o, 'motion', 0.3, 'easeIn', after);
10335 }).defer(100, this);
10342 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10343 * changed using the "attr" config option) and then fading back to the original color. If no original
10344 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10347 // default: highlight background to yellow
10350 // custom: highlight foreground text to blue for 2 seconds
10351 el.highlight("0000ff", { attr: 'color', duration: 2 });
10353 // common config options shown with default values
10354 el.highlight("ffff9c", {
10355 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10356 endColor: (current color) or "ffffff",
10361 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10362 * @param {Object} options (optional) Object literal with any of the Fx config options
10363 * @return {Roo.Element} The Element
10365 highlight : function(color, o){
10366 var el = this.getFxEl();
10369 el.queueFx(o, function(){
10370 color = color || "ffff9c";
10371 attr = o.attr || "backgroundColor";
10373 this.clearOpacity();
10376 var origColor = this.getColor(attr);
10377 var restoreColor = this.dom.style[attr];
10378 endColor = (o.endColor || origColor) || "ffffff";
10380 var after = function(){
10381 el.dom.style[attr] = restoreColor;
10386 a[attr] = {from: color, to: endColor};
10387 arguments.callee.anim = this.fxanim(a,
10397 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10400 // default: a single light blue ripple
10403 // custom: 3 red ripples lasting 3 seconds total
10404 el.frame("ff0000", 3, { duration: 3 });
10406 // common config options shown with default values
10407 el.frame("C3DAF9", 1, {
10408 duration: 1 //duration of entire animation (not each individual ripple)
10409 // Note: Easing is not configurable and will be ignored if included
10412 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10413 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10414 * @param {Object} options (optional) Object literal with any of the Fx config options
10415 * @return {Roo.Element} The Element
10417 frame : function(color, count, o){
10418 var el = this.getFxEl();
10421 el.queueFx(o, function(){
10422 color = color || "#C3DAF9";
10423 if(color.length == 6){
10424 color = "#" + color;
10426 count = count || 1;
10427 duration = o.duration || 1;
10430 var b = this.getBox();
10431 var animFn = function(){
10432 var proxy = this.createProxy({
10435 visbility:"hidden",
10436 position:"absolute",
10437 "z-index":"35000", // yee haw
10438 border:"0px solid " + color
10441 var scale = Roo.isBorderBox ? 2 : 1;
10443 top:{from:b.y, to:b.y - 20},
10444 left:{from:b.x, to:b.x - 20},
10445 borderWidth:{from:0, to:10},
10446 opacity:{from:1, to:0},
10447 height:{from:b.height, to:(b.height + (20*scale))},
10448 width:{from:b.width, to:(b.width + (20*scale))}
10449 }, duration, function(){
10453 animFn.defer((duration/2)*1000, this);
10464 * Creates a pause before any subsequent queued effects begin. If there are
10465 * no effects queued after the pause it will have no effect.
10470 * @param {Number} seconds The length of time to pause (in seconds)
10471 * @return {Roo.Element} The Element
10473 pause : function(seconds){
10474 var el = this.getFxEl();
10477 el.queueFx(o, function(){
10478 setTimeout(function(){
10480 }, seconds * 1000);
10486 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10487 * using the "endOpacity" config option.
10490 // default: fade in from opacity 0 to 100%
10493 // custom: fade in from opacity 0 to 75% over 2 seconds
10494 el.fadeIn({ endOpacity: .75, duration: 2});
10496 // common config options shown with default values
10498 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10503 * @param {Object} options (optional) Object literal with any of the Fx config options
10504 * @return {Roo.Element} The Element
10506 fadeIn : function(o){
10507 var el = this.getFxEl();
10509 el.queueFx(o, function(){
10510 this.setOpacity(0);
10512 this.dom.style.visibility = 'visible';
10513 var to = o.endOpacity || 1;
10514 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10515 o, null, .5, "easeOut", function(){
10517 this.clearOpacity();
10526 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10527 * using the "endOpacity" config option.
10530 // default: fade out from the element's current opacity to 0
10533 // custom: fade out from the element's current opacity to 25% over 2 seconds
10534 el.fadeOut({ endOpacity: .25, duration: 2});
10536 // common config options shown with default values
10538 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10545 * @param {Object} options (optional) Object literal with any of the Fx config options
10546 * @return {Roo.Element} The Element
10548 fadeOut : function(o){
10549 var el = this.getFxEl();
10551 el.queueFx(o, function(){
10552 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10553 o, null, .5, "easeOut", function(){
10554 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10555 this.dom.style.display = "none";
10557 this.dom.style.visibility = "hidden";
10559 this.clearOpacity();
10567 * Animates the transition of an element's dimensions from a starting height/width
10568 * to an ending height/width.
10571 // change height and width to 100x100 pixels
10572 el.scale(100, 100);
10574 // common config options shown with default values. The height and width will default to
10575 // the element's existing values if passed as null.
10578 [element's height], {
10583 * @param {Number} width The new width (pass undefined to keep the original width)
10584 * @param {Number} height The new height (pass undefined to keep the original height)
10585 * @param {Object} options (optional) Object literal with any of the Fx config options
10586 * @return {Roo.Element} The Element
10588 scale : function(w, h, o){
10589 this.shift(Roo.apply({}, o, {
10597 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10598 * Any of these properties not specified in the config object will not be changed. This effect
10599 * requires that at least one new dimension, position or opacity setting must be passed in on
10600 * the config object in order for the function to have any effect.
10603 // slide the element horizontally to x position 200 while changing the height and opacity
10604 el.shift({ x: 200, height: 50, opacity: .8 });
10606 // common config options shown with default values.
10608 width: [element's width],
10609 height: [element's height],
10610 x: [element's x position],
10611 y: [element's y position],
10612 opacity: [element's opacity],
10617 * @param {Object} options Object literal with any of the Fx config options
10618 * @return {Roo.Element} The Element
10620 shift : function(o){
10621 var el = this.getFxEl();
10623 el.queueFx(o, function(){
10624 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10625 if(w !== undefined){
10626 a.width = {to: this.adjustWidth(w)};
10628 if(h !== undefined){
10629 a.height = {to: this.adjustHeight(h)};
10631 if(x !== undefined || y !== undefined){
10633 x !== undefined ? x : this.getX(),
10634 y !== undefined ? y : this.getY()
10637 if(op !== undefined){
10638 a.opacity = {to: op};
10640 if(o.xy !== undefined){
10641 a.points = {to: o.xy};
10643 arguments.callee.anim = this.fxanim(a,
10644 o, 'motion', .35, "easeOut", function(){
10652 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10653 * ending point of the effect.
10656 // default: slide the element downward while fading out
10659 // custom: slide the element out to the right with a 2-second duration
10660 el.ghost('r', { duration: 2 });
10662 // common config options shown with default values
10670 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10671 * @param {Object} options (optional) Object literal with any of the Fx config options
10672 * @return {Roo.Element} The Element
10674 ghost : function(anchor, o){
10675 var el = this.getFxEl();
10678 el.queueFx(o, function(){
10679 anchor = anchor || "b";
10681 // restore values after effect
10682 var r = this.getFxRestore();
10683 var w = this.getWidth(),
10684 h = this.getHeight();
10686 var st = this.dom.style;
10688 var after = function(){
10690 el.setDisplayed(false);
10696 el.setPositioning(r.pos);
10697 st.width = r.width;
10698 st.height = r.height;
10703 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10704 switch(anchor.toLowerCase()){
10731 arguments.callee.anim = this.fxanim(a,
10741 * Ensures that all effects queued after syncFx is called on the element are
10742 * run concurrently. This is the opposite of {@link #sequenceFx}.
10743 * @return {Roo.Element} The Element
10745 syncFx : function(){
10746 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10755 * Ensures that all effects queued after sequenceFx is called on the element are
10756 * run in sequence. This is the opposite of {@link #syncFx}.
10757 * @return {Roo.Element} The Element
10759 sequenceFx : function(){
10760 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10762 concurrent : false,
10769 nextFx : function(){
10770 var ef = this.fxQueue[0];
10777 * Returns true if the element has any effects actively running or queued, else returns false.
10778 * @return {Boolean} True if element has active effects, else false
10780 hasActiveFx : function(){
10781 return this.fxQueue && this.fxQueue[0];
10785 * Stops any running effects and clears the element's internal effects queue if it contains
10786 * any additional effects that haven't started yet.
10787 * @return {Roo.Element} The Element
10789 stopFx : function(){
10790 if(this.hasActiveFx()){
10791 var cur = this.fxQueue[0];
10792 if(cur && cur.anim && cur.anim.isAnimated()){
10793 this.fxQueue = [cur]; // clear out others
10794 cur.anim.stop(true);
10801 beforeFx : function(o){
10802 if(this.hasActiveFx() && !o.concurrent){
10813 * Returns true if the element is currently blocking so that no other effect can be queued
10814 * until this effect is finished, else returns false if blocking is not set. This is commonly
10815 * used to ensure that an effect initiated by a user action runs to completion prior to the
10816 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10817 * @return {Boolean} True if blocking, else false
10819 hasFxBlock : function(){
10820 var q = this.fxQueue;
10821 return q && q[0] && q[0].block;
10825 queueFx : function(o, fn){
10829 if(!this.hasFxBlock()){
10830 Roo.applyIf(o, this.fxDefaults);
10832 var run = this.beforeFx(o);
10833 fn.block = o.block;
10834 this.fxQueue.push(fn);
10846 fxWrap : function(pos, o, vis){
10848 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10851 wrapXY = this.getXY();
10853 var div = document.createElement("div");
10854 div.style.visibility = vis;
10855 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10856 wrap.setPositioning(pos);
10857 if(wrap.getStyle("position") == "static"){
10858 wrap.position("relative");
10860 this.clearPositioning('auto');
10862 wrap.dom.appendChild(this.dom);
10864 wrap.setXY(wrapXY);
10871 fxUnwrap : function(wrap, pos, o){
10872 this.clearPositioning();
10873 this.setPositioning(pos);
10875 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10881 getFxRestore : function(){
10882 var st = this.dom.style;
10883 return {pos: this.getPositioning(), width: st.width, height : st.height};
10887 afterFx : function(o){
10889 this.applyStyles(o.afterStyle);
10892 this.addClass(o.afterCls);
10894 if(o.remove === true){
10897 Roo.callback(o.callback, o.scope, [this]);
10899 this.fxQueue.shift();
10905 getFxEl : function(){ // support for composite element fx
10906 return Roo.get(this.dom);
10910 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10911 animType = animType || 'run';
10913 var anim = Roo.lib.Anim[animType](
10915 (opt.duration || defaultDur) || .35,
10916 (opt.easing || defaultEase) || 'easeOut',
10918 Roo.callback(cb, this);
10927 // backwords compat
10928 Roo.Fx.resize = Roo.Fx.scale;
10930 //When included, Roo.Fx is automatically applied to Element so that all basic
10931 //effects are available directly via the Element API
10932 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10934 * Ext JS Library 1.1.1
10935 * Copyright(c) 2006-2007, Ext JS, LLC.
10937 * Originally Released Under LGPL - original licence link has changed is not relivant.
10940 * <script type="text/javascript">
10945 * @class Roo.CompositeElement
10946 * Standard composite class. Creates a Roo.Element for every element in the collection.
10948 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10949 * actions will be performed on all the elements in this collection.</b>
10951 * All methods return <i>this</i> and can be chained.
10953 var els = Roo.select("#some-el div.some-class", true);
10954 // or select directly from an existing element
10955 var el = Roo.get('some-el');
10956 el.select('div.some-class', true);
10958 els.setWidth(100); // all elements become 100 width
10959 els.hide(true); // all elements fade out and hide
10961 els.setWidth(100).hide(true);
10964 Roo.CompositeElement = function(els){
10965 this.elements = [];
10966 this.addElements(els);
10968 Roo.CompositeElement.prototype = {
10970 addElements : function(els){
10971 if(!els) return this;
10972 if(typeof els == "string"){
10973 els = Roo.Element.selectorFunction(els);
10975 var yels = this.elements;
10976 var index = yels.length-1;
10977 for(var i = 0, len = els.length; i < len; i++) {
10978 yels[++index] = Roo.get(els[i]);
10984 * Clears this composite and adds the elements returned by the passed selector.
10985 * @param {String/Array} els A string CSS selector, an array of elements or an element
10986 * @return {CompositeElement} this
10988 fill : function(els){
10989 this.elements = [];
10995 * Filters this composite to only elements that match the passed selector.
10996 * @param {String} selector A string CSS selector
10997 * @param {Boolean} inverse return inverse filter (not matches)
10998 * @return {CompositeElement} this
11000 filter : function(selector, inverse){
11002 inverse = inverse || false;
11003 this.each(function(el){
11004 var match = inverse ? !el.is(selector) : el.is(selector);
11006 els[els.length] = el.dom;
11013 invoke : function(fn, args){
11014 var els = this.elements;
11015 for(var i = 0, len = els.length; i < len; i++) {
11016 Roo.Element.prototype[fn].apply(els[i], args);
11021 * Adds elements to this composite.
11022 * @param {String/Array} els A string CSS selector, an array of elements or an element
11023 * @return {CompositeElement} this
11025 add : function(els){
11026 if(typeof els == "string"){
11027 this.addElements(Roo.Element.selectorFunction(els));
11028 }else if(els.length !== undefined){
11029 this.addElements(els);
11031 this.addElements([els]);
11036 * Calls the passed function passing (el, this, index) for each element in this composite.
11037 * @param {Function} fn The function to call
11038 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11039 * @return {CompositeElement} this
11041 each : function(fn, scope){
11042 var els = this.elements;
11043 for(var i = 0, len = els.length; i < len; i++){
11044 if(fn.call(scope || els[i], els[i], this, i) === false) {
11052 * Returns the Element object at the specified index
11053 * @param {Number} index
11054 * @return {Roo.Element}
11056 item : function(index){
11057 return this.elements[index] || null;
11061 * Returns the first Element
11062 * @return {Roo.Element}
11064 first : function(){
11065 return this.item(0);
11069 * Returns the last Element
11070 * @return {Roo.Element}
11073 return this.item(this.elements.length-1);
11077 * Returns the number of elements in this composite
11080 getCount : function(){
11081 return this.elements.length;
11085 * Returns true if this composite contains the passed element
11088 contains : function(el){
11089 return this.indexOf(el) !== -1;
11093 * Returns true if this composite contains the passed element
11096 indexOf : function(el){
11097 return this.elements.indexOf(Roo.get(el));
11102 * Removes the specified element(s).
11103 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11104 * or an array of any of those.
11105 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11106 * @return {CompositeElement} this
11108 removeElement : function(el, removeDom){
11109 if(el instanceof Array){
11110 for(var i = 0, len = el.length; i < len; i++){
11111 this.removeElement(el[i]);
11115 var index = typeof el == 'number' ? el : this.indexOf(el);
11118 var d = this.elements[index];
11122 d.parentNode.removeChild(d);
11125 this.elements.splice(index, 1);
11131 * Replaces the specified element with the passed element.
11132 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11134 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11135 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11136 * @return {CompositeElement} this
11138 replaceElement : function(el, replacement, domReplace){
11139 var index = typeof el == 'number' ? el : this.indexOf(el);
11142 this.elements[index].replaceWith(replacement);
11144 this.elements.splice(index, 1, Roo.get(replacement))
11151 * Removes all elements.
11153 clear : function(){
11154 this.elements = [];
11158 Roo.CompositeElement.createCall = function(proto, fnName){
11159 if(!proto[fnName]){
11160 proto[fnName] = function(){
11161 return this.invoke(fnName, arguments);
11165 for(var fnName in Roo.Element.prototype){
11166 if(typeof Roo.Element.prototype[fnName] == "function"){
11167 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11173 * Ext JS Library 1.1.1
11174 * Copyright(c) 2006-2007, Ext JS, LLC.
11176 * Originally Released Under LGPL - original licence link has changed is not relivant.
11179 * <script type="text/javascript">
11183 * @class Roo.CompositeElementLite
11184 * @extends Roo.CompositeElement
11185 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11187 var els = Roo.select("#some-el div.some-class");
11188 // or select directly from an existing element
11189 var el = Roo.get('some-el');
11190 el.select('div.some-class');
11192 els.setWidth(100); // all elements become 100 width
11193 els.hide(true); // all elements fade out and hide
11195 els.setWidth(100).hide(true);
11196 </code></pre><br><br>
11197 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11198 * actions will be performed on all the elements in this collection.</b>
11200 Roo.CompositeElementLite = function(els){
11201 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11202 this.el = new Roo.Element.Flyweight();
11204 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11205 addElements : function(els){
11207 if(els instanceof Array){
11208 this.elements = this.elements.concat(els);
11210 var yels = this.elements;
11211 var index = yels.length-1;
11212 for(var i = 0, len = els.length; i < len; i++) {
11213 yels[++index] = els[i];
11219 invoke : function(fn, args){
11220 var els = this.elements;
11222 for(var i = 0, len = els.length; i < len; i++) {
11224 Roo.Element.prototype[fn].apply(el, args);
11229 * Returns a flyweight Element of the dom element object at the specified index
11230 * @param {Number} index
11231 * @return {Roo.Element}
11233 item : function(index){
11234 if(!this.elements[index]){
11237 this.el.dom = this.elements[index];
11241 // fixes scope with flyweight
11242 addListener : function(eventName, handler, scope, opt){
11243 var els = this.elements;
11244 for(var i = 0, len = els.length; i < len; i++) {
11245 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11251 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11252 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11253 * a reference to the dom node, use el.dom.</b>
11254 * @param {Function} fn The function to call
11255 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11256 * @return {CompositeElement} this
11258 each : function(fn, scope){
11259 var els = this.elements;
11261 for(var i = 0, len = els.length; i < len; i++){
11263 if(fn.call(scope || el, el, this, i) === false){
11270 indexOf : function(el){
11271 return this.elements.indexOf(Roo.getDom(el));
11274 replaceElement : function(el, replacement, domReplace){
11275 var index = typeof el == 'number' ? el : this.indexOf(el);
11277 replacement = Roo.getDom(replacement);
11279 var d = this.elements[index];
11280 d.parentNode.insertBefore(replacement, d);
11281 d.parentNode.removeChild(d);
11283 this.elements.splice(index, 1, replacement);
11288 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11292 * Ext JS Library 1.1.1
11293 * Copyright(c) 2006-2007, Ext JS, LLC.
11295 * Originally Released Under LGPL - original licence link has changed is not relivant.
11298 * <script type="text/javascript">
11304 * @class Roo.data.Connection
11305 * @extends Roo.util.Observable
11306 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11307 * either to a configured URL, or to a URL specified at request time.<br><br>
11309 * Requests made by this class are asynchronous, and will return immediately. No data from
11310 * the server will be available to the statement immediately following the {@link #request} call.
11311 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11313 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11314 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11315 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11316 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11317 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11318 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11319 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11320 * standard DOM methods.
11322 * @param {Object} config a configuration object.
11324 Roo.data.Connection = function(config){
11325 Roo.apply(this, config);
11328 * @event beforerequest
11329 * Fires before a network request is made to retrieve a data object.
11330 * @param {Connection} conn This Connection object.
11331 * @param {Object} options The options config object passed to the {@link #request} method.
11333 "beforerequest" : true,
11335 * @event requestcomplete
11336 * Fires if the request was successfully completed.
11337 * @param {Connection} conn This Connection object.
11338 * @param {Object} response The XHR object containing the response data.
11339 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11340 * @param {Object} options The options config object passed to the {@link #request} method.
11342 "requestcomplete" : true,
11344 * @event requestexception
11345 * Fires if an error HTTP status was returned from the server.
11346 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11347 * @param {Connection} conn This Connection object.
11348 * @param {Object} response The XHR object containing the response data.
11349 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11350 * @param {Object} options The options config object passed to the {@link #request} method.
11352 "requestexception" : true
11354 Roo.data.Connection.superclass.constructor.call(this);
11357 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11359 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11362 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11363 * extra parameters to each request made by this object. (defaults to undefined)
11366 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11367 * to each request made by this object. (defaults to undefined)
11370 * @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)
11373 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11377 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11383 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11386 disableCaching: true,
11389 * Sends an HTTP request to a remote server.
11390 * @param {Object} options An object which may contain the following properties:<ul>
11391 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11392 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11393 * request, a url encoded string or a function to call to get either.</li>
11394 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11395 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11396 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11397 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11398 * <li>options {Object} The parameter to the request call.</li>
11399 * <li>success {Boolean} True if the request succeeded.</li>
11400 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11402 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11403 * The callback is passed the following parameters:<ul>
11404 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11405 * <li>options {Object} The parameter to the request call.</li>
11407 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11408 * The callback is passed the following parameters:<ul>
11409 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11410 * <li>options {Object} The parameter to the request call.</li>
11412 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11413 * for the callback function. Defaults to the browser window.</li>
11414 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11415 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11416 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11417 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11418 * params for the post data. Any params will be appended to the URL.</li>
11419 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11421 * @return {Number} transactionId
11423 request : function(o){
11424 if(this.fireEvent("beforerequest", this, o) !== false){
11427 if(typeof p == "function"){
11428 p = p.call(o.scope||window, o);
11430 if(typeof p == "object"){
11431 p = Roo.urlEncode(o.params);
11433 if(this.extraParams){
11434 var extras = Roo.urlEncode(this.extraParams);
11435 p = p ? (p + '&' + extras) : extras;
11438 var url = o.url || this.url;
11439 if(typeof url == 'function'){
11440 url = url.call(o.scope||window, o);
11444 var form = Roo.getDom(o.form);
11445 url = url || form.action;
11447 var enctype = form.getAttribute("enctype");
11448 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11449 return this.doFormUpload(o, p, url);
11451 var f = Roo.lib.Ajax.serializeForm(form);
11452 p = p ? (p + '&' + f) : f;
11455 var hs = o.headers;
11456 if(this.defaultHeaders){
11457 hs = Roo.apply(hs || {}, this.defaultHeaders);
11464 success: this.handleResponse,
11465 failure: this.handleFailure,
11467 argument: {options: o},
11468 timeout : o.timeout || this.timeout
11471 var method = o.method||this.method||(p ? "POST" : "GET");
11473 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11474 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11477 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11481 }else if(this.autoAbort !== false){
11485 if((method == 'GET' && p) || o.xmlData){
11486 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11489 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11490 return this.transId;
11492 Roo.callback(o.callback, o.scope, [o, null, null]);
11498 * Determine whether this object has a request outstanding.
11499 * @param {Number} transactionId (Optional) defaults to the last transaction
11500 * @return {Boolean} True if there is an outstanding request.
11502 isLoading : function(transId){
11504 return Roo.lib.Ajax.isCallInProgress(transId);
11506 return this.transId ? true : false;
11511 * Aborts any outstanding request.
11512 * @param {Number} transactionId (Optional) defaults to the last transaction
11514 abort : function(transId){
11515 if(transId || this.isLoading()){
11516 Roo.lib.Ajax.abort(transId || this.transId);
11521 handleResponse : function(response){
11522 this.transId = false;
11523 var options = response.argument.options;
11524 response.argument = options ? options.argument : null;
11525 this.fireEvent("requestcomplete", this, response, options);
11526 Roo.callback(options.success, options.scope, [response, options]);
11527 Roo.callback(options.callback, options.scope, [options, true, response]);
11531 handleFailure : function(response, e){
11532 this.transId = false;
11533 var options = response.argument.options;
11534 response.argument = options ? options.argument : null;
11535 this.fireEvent("requestexception", this, response, options, e);
11536 Roo.callback(options.failure, options.scope, [response, options]);
11537 Roo.callback(options.callback, options.scope, [options, false, response]);
11541 doFormUpload : function(o, ps, url){
11543 var frame = document.createElement('iframe');
11546 frame.className = 'x-hidden';
11548 frame.src = Roo.SSL_SECURE_URL;
11550 document.body.appendChild(frame);
11553 document.frames[id].name = id;
11556 var form = Roo.getDom(o.form);
11558 form.method = 'POST';
11559 form.enctype = form.encoding = 'multipart/form-data';
11565 if(ps){ // add dynamic params
11567 ps = Roo.urlDecode(ps, false);
11569 if(ps.hasOwnProperty(k)){
11570 hd = document.createElement('input');
11571 hd.type = 'hidden';
11574 form.appendChild(hd);
11581 var r = { // bogus response object
11586 r.argument = o ? o.argument : null;
11591 doc = frame.contentWindow.document;
11593 doc = (frame.contentDocument || window.frames[id].document);
11595 if(doc && doc.body){
11596 r.responseText = doc.body.innerHTML;
11598 if(doc && doc.XMLDocument){
11599 r.responseXML = doc.XMLDocument;
11601 r.responseXML = doc;
11608 Roo.EventManager.removeListener(frame, 'load', cb, this);
11610 this.fireEvent("requestcomplete", this, r, o);
11611 Roo.callback(o.success, o.scope, [r, o]);
11612 Roo.callback(o.callback, o.scope, [o, true, r]);
11614 setTimeout(function(){document.body.removeChild(frame);}, 100);
11617 Roo.EventManager.on(frame, 'load', cb, this);
11620 if(hiddens){ // remove dynamic params
11621 for(var i = 0, len = hiddens.length; i < len; i++){
11622 form.removeChild(hiddens[i]);
11629 * Ext JS Library 1.1.1
11630 * Copyright(c) 2006-2007, Ext JS, LLC.
11632 * Originally Released Under LGPL - original licence link has changed is not relivant.
11635 * <script type="text/javascript">
11639 * Global Ajax request class.
11642 * @extends Roo.data.Connection
11645 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11646 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11647 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11648 * @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)
11649 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11650 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11651 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11653 Roo.Ajax = new Roo.data.Connection({
11662 * Serialize the passed form into a url encoded string
11664 * @param {String/HTMLElement} form
11667 serializeForm : function(form){
11668 return Roo.lib.Ajax.serializeForm(form);
11672 * Ext JS Library 1.1.1
11673 * Copyright(c) 2006-2007, Ext JS, LLC.
11675 * Originally Released Under LGPL - original licence link has changed is not relivant.
11678 * <script type="text/javascript">
11683 * @class Roo.UpdateManager
11684 * @extends Roo.util.Observable
11685 * Provides AJAX-style update for Element object.<br><br>
11688 * // Get it from a Roo.Element object
11689 * var el = Roo.get("foo");
11690 * var mgr = el.getUpdateManager();
11691 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11693 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11695 * // or directly (returns the same UpdateManager instance)
11696 * var mgr = new Roo.UpdateManager("myElementId");
11697 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11698 * mgr.on("update", myFcnNeedsToKnow);
11700 // short handed call directly from the element object
11701 Roo.get("foo").load({
11705 text: "Loading Foo..."
11709 * Create new UpdateManager directly.
11710 * @param {String/HTMLElement/Roo.Element} el The element to update
11711 * @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).
11713 Roo.UpdateManager = function(el, forceNew){
11715 if(!forceNew && el.updateManager){
11716 return el.updateManager;
11719 * The Element object
11720 * @type Roo.Element
11724 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11727 this.defaultUrl = null;
11731 * @event beforeupdate
11732 * Fired before an update is made, return false from your handler and the update is cancelled.
11733 * @param {Roo.Element} el
11734 * @param {String/Object/Function} url
11735 * @param {String/Object} params
11737 "beforeupdate": true,
11740 * Fired after successful update is made.
11741 * @param {Roo.Element} el
11742 * @param {Object} oResponseObject The response Object
11747 * Fired on update failure.
11748 * @param {Roo.Element} el
11749 * @param {Object} oResponseObject The response Object
11753 var d = Roo.UpdateManager.defaults;
11755 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11758 this.sslBlankUrl = d.sslBlankUrl;
11760 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11763 this.disableCaching = d.disableCaching;
11765 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11768 this.indicatorText = d.indicatorText;
11770 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11773 this.showLoadIndicator = d.showLoadIndicator;
11775 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11778 this.timeout = d.timeout;
11781 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11784 this.loadScripts = d.loadScripts;
11787 * Transaction object of current executing transaction
11789 this.transaction = null;
11794 this.autoRefreshProcId = null;
11796 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11799 this.refreshDelegate = this.refresh.createDelegate(this);
11801 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11804 this.updateDelegate = this.update.createDelegate(this);
11806 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11809 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11813 this.successDelegate = this.processSuccess.createDelegate(this);
11817 this.failureDelegate = this.processFailure.createDelegate(this);
11819 if(!this.renderer){
11821 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11823 this.renderer = new Roo.UpdateManager.BasicRenderer();
11826 Roo.UpdateManager.superclass.constructor.call(this);
11829 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11831 * Get the Element this UpdateManager is bound to
11832 * @return {Roo.Element} The element
11834 getEl : function(){
11838 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11839 * @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:
11842 url: "your-url.php",<br/>
11843 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11844 callback: yourFunction,<br/>
11845 scope: yourObject, //(optional scope) <br/>
11846 discardUrl: false, <br/>
11847 nocache: false,<br/>
11848 text: "Loading...",<br/>
11850 scripts: false<br/>
11853 * The only required property is url. The optional properties nocache, text and scripts
11854 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11855 * @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}
11856 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11857 * @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.
11859 update : function(url, params, callback, discardUrl){
11860 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11861 var method = this.method,
11863 if(typeof url == "object"){ // must be config object
11866 params = params || cfg.params;
11867 callback = callback || cfg.callback;
11868 discardUrl = discardUrl || cfg.discardUrl;
11869 if(callback && cfg.scope){
11870 callback = callback.createDelegate(cfg.scope);
11872 if(typeof cfg.method != "undefined"){method = cfg.method;};
11873 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11874 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11875 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11876 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11878 this.showLoading();
11880 this.defaultUrl = url;
11882 if(typeof url == "function"){
11883 url = url.call(this);
11886 method = method || (params ? "POST" : "GET");
11887 if(method == "GET"){
11888 url = this.prepareUrl(url);
11891 var o = Roo.apply(cfg ||{}, {
11894 success: this.successDelegate,
11895 failure: this.failureDelegate,
11896 callback: undefined,
11897 timeout: (this.timeout*1000),
11898 argument: {"url": url, "form": null, "callback": callback, "params": params}
11900 Roo.log("updated manager called with timeout of " + o.timeout);
11901 this.transaction = Roo.Ajax.request(o);
11906 * 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.
11907 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11908 * @param {String/HTMLElement} form The form Id or form element
11909 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11910 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11911 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11913 formUpdate : function(form, url, reset, callback){
11914 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11915 if(typeof url == "function"){
11916 url = url.call(this);
11918 form = Roo.getDom(form);
11919 this.transaction = Roo.Ajax.request({
11922 success: this.successDelegate,
11923 failure: this.failureDelegate,
11924 timeout: (this.timeout*1000),
11925 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11927 this.showLoading.defer(1, this);
11932 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11933 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11935 refresh : function(callback){
11936 if(this.defaultUrl == null){
11939 this.update(this.defaultUrl, null, callback, true);
11943 * Set this element to auto refresh.
11944 * @param {Number} interval How often to update (in seconds).
11945 * @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)
11946 * @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}
11947 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11948 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11950 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11952 this.update(url || this.defaultUrl, params, callback, true);
11954 if(this.autoRefreshProcId){
11955 clearInterval(this.autoRefreshProcId);
11957 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11961 * Stop auto refresh on this element.
11963 stopAutoRefresh : function(){
11964 if(this.autoRefreshProcId){
11965 clearInterval(this.autoRefreshProcId);
11966 delete this.autoRefreshProcId;
11970 isAutoRefreshing : function(){
11971 return this.autoRefreshProcId ? true : false;
11974 * Called to update the element to "Loading" state. Override to perform custom action.
11976 showLoading : function(){
11977 if(this.showLoadIndicator){
11978 this.el.update(this.indicatorText);
11983 * Adds unique parameter to query string if disableCaching = true
11986 prepareUrl : function(url){
11987 if(this.disableCaching){
11988 var append = "_dc=" + (new Date().getTime());
11989 if(url.indexOf("?") !== -1){
11990 url += "&" + append;
11992 url += "?" + append;
12001 processSuccess : function(response){
12002 this.transaction = null;
12003 if(response.argument.form && response.argument.reset){
12004 try{ // put in try/catch since some older FF releases had problems with this
12005 response.argument.form.reset();
12008 if(this.loadScripts){
12009 this.renderer.render(this.el, response, this,
12010 this.updateComplete.createDelegate(this, [response]));
12012 this.renderer.render(this.el, response, this);
12013 this.updateComplete(response);
12017 updateComplete : function(response){
12018 this.fireEvent("update", this.el, response);
12019 if(typeof response.argument.callback == "function"){
12020 response.argument.callback(this.el, true, response);
12027 processFailure : function(response){
12028 this.transaction = null;
12029 this.fireEvent("failure", this.el, response);
12030 if(typeof response.argument.callback == "function"){
12031 response.argument.callback(this.el, false, response);
12036 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12037 * @param {Object} renderer The object implementing the render() method
12039 setRenderer : function(renderer){
12040 this.renderer = renderer;
12043 getRenderer : function(){
12044 return this.renderer;
12048 * Set the defaultUrl used for updates
12049 * @param {String/Function} defaultUrl The url or a function to call to get the url
12051 setDefaultUrl : function(defaultUrl){
12052 this.defaultUrl = defaultUrl;
12056 * Aborts the executing transaction
12058 abort : function(){
12059 if(this.transaction){
12060 Roo.Ajax.abort(this.transaction);
12065 * Returns true if an update is in progress
12066 * @return {Boolean}
12068 isUpdating : function(){
12069 if(this.transaction){
12070 return Roo.Ajax.isLoading(this.transaction);
12077 * @class Roo.UpdateManager.defaults
12078 * @static (not really - but it helps the doc tool)
12079 * The defaults collection enables customizing the default properties of UpdateManager
12081 Roo.UpdateManager.defaults = {
12083 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12089 * True to process scripts by default (Defaults to false).
12092 loadScripts : false,
12095 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12098 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12100 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12103 disableCaching : false,
12105 * Whether to show indicatorText when loading (Defaults to true).
12108 showLoadIndicator : true,
12110 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12113 indicatorText : '<div class="loading-indicator">Loading...</div>'
12117 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12119 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12120 * @param {String/HTMLElement/Roo.Element} el The element to update
12121 * @param {String} url The url
12122 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12123 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12126 * @member Roo.UpdateManager
12128 Roo.UpdateManager.updateElement = function(el, url, params, options){
12129 var um = Roo.get(el, true).getUpdateManager();
12130 Roo.apply(um, options);
12131 um.update(url, params, options ? options.callback : null);
12133 // alias for backwards compat
12134 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12136 * @class Roo.UpdateManager.BasicRenderer
12137 * Default Content renderer. Updates the elements innerHTML with the responseText.
12139 Roo.UpdateManager.BasicRenderer = function(){};
12141 Roo.UpdateManager.BasicRenderer.prototype = {
12143 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12144 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12145 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12146 * @param {Roo.Element} el The element being rendered
12147 * @param {Object} response The YUI Connect response object
12148 * @param {UpdateManager} updateManager The calling update manager
12149 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12151 render : function(el, response, updateManager, callback){
12152 el.update(response.responseText, updateManager.loadScripts, callback);
12158 * (c)) Alan Knowles
12164 * @class Roo.DomTemplate
12165 * @extends Roo.Template
12166 * An effort at a dom based template engine..
12168 * Similar to XTemplate, except it uses dom parsing to create the template..
12170 * Supported features:
12175 {a_variable} - output encoded.
12176 {a_variable.format:("Y-m-d")} - call a method on the variable
12177 {a_variable:raw} - unencoded output
12178 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12179 {a_variable:this.method_on_template(...)} - call a method on the template object.
12184 <div roo-for="a_variable or condition.."></div>
12185 <div roo-if="a_variable or condition"></div>
12186 <div roo-exec="some javascript"></div>
12187 <div roo-name="named_template"></div>
12192 Roo.DomTemplate = function()
12194 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12201 Roo.extend(Roo.DomTemplate, Roo.Template, {
12203 * id counter for sub templates.
12207 * flag to indicate if dom parser is inside a pre,
12208 * it will strip whitespace if not.
12213 * The various sub templates
12221 * basic tag replacing syntax
12224 * // you can fake an object call by doing this
12228 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12229 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12231 iterChild : function (node, method) {
12233 var oldPre = this.inPre;
12234 if (node.tagName == 'PRE') {
12237 for( var i = 0; i < node.childNodes.length; i++) {
12238 method.call(this, node.childNodes[i]);
12240 this.inPre = oldPre;
12246 * compile the template
12248 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12251 compile: function()
12255 // covert the html into DOM...
12259 doc = document.implementation.createHTMLDocument("");
12260 doc.documentElement.innerHTML = this.html ;
12261 div = doc.documentElement;
12263 // old IE... - nasty -- it causes all sorts of issues.. with
12264 // images getting pulled from server..
12265 div = document.createElement('div');
12266 div.innerHTML = this.html;
12268 //doc.documentElement.innerHTML = htmlBody
12274 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12276 var tpls = this.tpls;
12278 // create a top level template from the snippet..
12280 //Roo.log(div.innerHTML);
12287 body : div.innerHTML,
12300 Roo.each(tpls, function(tp){
12301 this.compileTpl(tp);
12302 this.tpls[tp.id] = tp;
12305 this.master = tpls[0];
12311 compileNode : function(node, istop) {
12316 // skip anything not a tag..
12317 if (node.nodeType != 1) {
12318 if (node.nodeType == 3 && !this.inPre) {
12319 // reduce white space..
12320 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12343 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12344 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12345 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12346 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12352 // just itterate children..
12353 this.iterChild(node,this.compileNode);
12356 tpl.uid = this.id++;
12357 tpl.value = node.getAttribute('roo-' + tpl.attr);
12358 node.removeAttribute('roo-'+ tpl.attr);
12359 if (tpl.attr != 'name') {
12360 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12361 node.parentNode.replaceChild(placeholder, node);
12364 var placeholder = document.createElement('span');
12365 placeholder.className = 'roo-tpl-' + tpl.value;
12366 node.parentNode.replaceChild(placeholder, node);
12369 // parent now sees '{domtplXXXX}
12370 this.iterChild(node,this.compileNode);
12372 // we should now have node body...
12373 var div = document.createElement('div');
12374 div.appendChild(node);
12376 // this has the unfortunate side effect of converting tagged attributes
12377 // eg. href="{...}" into %7C...%7D
12378 // this has been fixed by searching for those combo's although it's a bit hacky..
12381 tpl.body = div.innerHTML;
12388 switch (tpl.value) {
12389 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12390 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12391 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12396 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12400 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12404 tpl.id = tpl.value; // replace non characters???
12410 this.tpls.push(tpl);
12420 * Compile a segment of the template into a 'sub-template'
12426 compileTpl : function(tpl)
12428 var fm = Roo.util.Format;
12429 var useF = this.disableFormats !== true;
12431 var sep = Roo.isGecko ? "+\n" : ",\n";
12433 var undef = function(str) {
12434 Roo.debug && Roo.log("Property not found :" + str);
12438 //Roo.log(tpl.body);
12442 var fn = function(m, lbrace, name, format, args)
12445 //Roo.log(arguments);
12446 args = args ? args.replace(/\\'/g,"'") : args;
12447 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12448 if (typeof(format) == 'undefined') {
12449 format = 'htmlEncode';
12451 if (format == 'raw' ) {
12455 if(name.substr(0, 6) == 'domtpl'){
12456 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12459 // build an array of options to determine if value is undefined..
12461 // basically get 'xxxx.yyyy' then do
12462 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12463 // (function () { Roo.log("Property not found"); return ''; })() :
12468 Roo.each(name.split('.'), function(st) {
12469 lookfor += (lookfor.length ? '.': '') + st;
12470 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12473 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12476 if(format && useF){
12478 args = args ? ',' + args : "";
12480 if(format.substr(0, 5) != "this."){
12481 format = "fm." + format + '(';
12483 format = 'this.call("'+ format.substr(5) + '", ';
12487 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12490 if (args && args.length) {
12491 // called with xxyx.yuu:(test,test)
12493 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12495 // raw.. - :raw modifier..
12496 return "'"+ sep + udef_st + name + ")"+sep+"'";
12500 // branched to use + in gecko and [].join() in others
12502 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12503 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12506 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12507 body.push(tpl.body.replace(/(\r\n|\n)/g,
12508 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12509 body.push("'].join('');};};");
12510 body = body.join('');
12513 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12515 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12522 * same as applyTemplate, except it's done to one of the subTemplates
12523 * when using named templates, you can do:
12525 * var str = pl.applySubTemplate('your-name', values);
12528 * @param {Number} id of the template
12529 * @param {Object} values to apply to template
12530 * @param {Object} parent (normaly the instance of this object)
12532 applySubTemplate : function(id, values, parent)
12536 var t = this.tpls[id];
12540 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12541 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12545 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12552 if(t.execCall && t.execCall.call(this, values, parent)){
12556 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12562 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12563 parent = t.target ? values : parent;
12564 if(t.forCall && vs instanceof Array){
12566 for(var i = 0, len = vs.length; i < len; i++){
12568 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12570 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12572 //Roo.log(t.compiled);
12576 return buf.join('');
12579 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12584 return t.compiled.call(this, vs, parent);
12586 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12588 //Roo.log(t.compiled);
12596 applyTemplate : function(values){
12597 return this.master.compiled.call(this, values, {});
12598 //var s = this.subs;
12601 apply : function(){
12602 return this.applyTemplate.apply(this, arguments);
12607 Roo.DomTemplate.from = function(el){
12608 el = Roo.getDom(el);
12609 return new Roo.Domtemplate(el.value || el.innerHTML);
12612 * Ext JS Library 1.1.1
12613 * Copyright(c) 2006-2007, Ext JS, LLC.
12615 * Originally Released Under LGPL - original licence link has changed is not relivant.
12618 * <script type="text/javascript">
12622 * @class Roo.util.DelayedTask
12623 * Provides a convenient method of performing setTimeout where a new
12624 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12625 * You can use this class to buffer
12626 * the keypress events for a certain number of milliseconds, and perform only if they stop
12627 * for that amount of time.
12628 * @constructor The parameters to this constructor serve as defaults and are not required.
12629 * @param {Function} fn (optional) The default function to timeout
12630 * @param {Object} scope (optional) The default scope of that timeout
12631 * @param {Array} args (optional) The default Array of arguments
12633 Roo.util.DelayedTask = function(fn, scope, args){
12634 var id = null, d, t;
12636 var call = function(){
12637 var now = new Date().getTime();
12641 fn.apply(scope, args || []);
12645 * Cancels any pending timeout and queues a new one
12646 * @param {Number} delay The milliseconds to delay
12647 * @param {Function} newFn (optional) Overrides function passed to constructor
12648 * @param {Object} newScope (optional) Overrides scope passed to constructor
12649 * @param {Array} newArgs (optional) Overrides args passed to constructor
12651 this.delay = function(delay, newFn, newScope, newArgs){
12652 if(id && delay != d){
12656 t = new Date().getTime();
12658 scope = newScope || scope;
12659 args = newArgs || args;
12661 id = setInterval(call, d);
12666 * Cancel the last queued timeout
12668 this.cancel = function(){
12676 * Ext JS Library 1.1.1
12677 * Copyright(c) 2006-2007, Ext JS, LLC.
12679 * Originally Released Under LGPL - original licence link has changed is not relivant.
12682 * <script type="text/javascript">
12686 Roo.util.TaskRunner = function(interval){
12687 interval = interval || 10;
12688 var tasks = [], removeQueue = [];
12690 var running = false;
12692 var stopThread = function(){
12698 var startThread = function(){
12701 id = setInterval(runTasks, interval);
12705 var removeTask = function(task){
12706 removeQueue.push(task);
12712 var runTasks = function(){
12713 if(removeQueue.length > 0){
12714 for(var i = 0, len = removeQueue.length; i < len; i++){
12715 tasks.remove(removeQueue[i]);
12718 if(tasks.length < 1){
12723 var now = new Date().getTime();
12724 for(var i = 0, len = tasks.length; i < len; ++i){
12726 var itime = now - t.taskRunTime;
12727 if(t.interval <= itime){
12728 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12729 t.taskRunTime = now;
12730 if(rt === false || t.taskRunCount === t.repeat){
12735 if(t.duration && t.duration <= (now - t.taskStartTime)){
12742 * Queues a new task.
12743 * @param {Object} task
12745 this.start = function(task){
12747 task.taskStartTime = new Date().getTime();
12748 task.taskRunTime = 0;
12749 task.taskRunCount = 0;
12754 this.stop = function(task){
12759 this.stopAll = function(){
12761 for(var i = 0, len = tasks.length; i < len; i++){
12762 if(tasks[i].onStop){
12771 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12773 * Ext JS Library 1.1.1
12774 * Copyright(c) 2006-2007, Ext JS, LLC.
12776 * Originally Released Under LGPL - original licence link has changed is not relivant.
12779 * <script type="text/javascript">
12784 * @class Roo.util.MixedCollection
12785 * @extends Roo.util.Observable
12786 * A Collection class that maintains both numeric indexes and keys and exposes events.
12788 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12789 * collection (defaults to false)
12790 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12791 * and return the key value for that item. This is used when available to look up the key on items that
12792 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12793 * equivalent to providing an implementation for the {@link #getKey} method.
12795 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12803 * Fires when the collection is cleared.
12808 * Fires when an item is added to the collection.
12809 * @param {Number} index The index at which the item was added.
12810 * @param {Object} o The item added.
12811 * @param {String} key The key associated with the added item.
12816 * Fires when an item is replaced in the collection.
12817 * @param {String} key he key associated with the new added.
12818 * @param {Object} old The item being replaced.
12819 * @param {Object} new The new item.
12824 * Fires when an item is removed from the collection.
12825 * @param {Object} o The item being removed.
12826 * @param {String} key (optional) The key associated with the removed item.
12831 this.allowFunctions = allowFunctions === true;
12833 this.getKey = keyFn;
12835 Roo.util.MixedCollection.superclass.constructor.call(this);
12838 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12839 allowFunctions : false,
12842 * Adds an item to the collection.
12843 * @param {String} key The key to associate with the item
12844 * @param {Object} o The item to add.
12845 * @return {Object} The item added.
12847 add : function(key, o){
12848 if(arguments.length == 1){
12850 key = this.getKey(o);
12852 if(typeof key == "undefined" || key === null){
12854 this.items.push(o);
12855 this.keys.push(null);
12857 var old = this.map[key];
12859 return this.replace(key, o);
12862 this.items.push(o);
12864 this.keys.push(key);
12866 this.fireEvent("add", this.length-1, o, key);
12871 * MixedCollection has a generic way to fetch keys if you implement getKey.
12874 var mc = new Roo.util.MixedCollection();
12875 mc.add(someEl.dom.id, someEl);
12876 mc.add(otherEl.dom.id, otherEl);
12880 var mc = new Roo.util.MixedCollection();
12881 mc.getKey = function(el){
12887 // or via the constructor
12888 var mc = new Roo.util.MixedCollection(false, function(el){
12894 * @param o {Object} The item for which to find the key.
12895 * @return {Object} The key for the passed item.
12897 getKey : function(o){
12902 * Replaces an item in the collection.
12903 * @param {String} key The key associated with the item to replace, or the item to replace.
12904 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12905 * @return {Object} The new item.
12907 replace : function(key, o){
12908 if(arguments.length == 1){
12910 key = this.getKey(o);
12912 var old = this.item(key);
12913 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12914 return this.add(key, o);
12916 var index = this.indexOfKey(key);
12917 this.items[index] = o;
12919 this.fireEvent("replace", key, old, o);
12924 * Adds all elements of an Array or an Object to the collection.
12925 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12926 * an Array of values, each of which are added to the collection.
12928 addAll : function(objs){
12929 if(arguments.length > 1 || objs instanceof Array){
12930 var args = arguments.length > 1 ? arguments : objs;
12931 for(var i = 0, len = args.length; i < len; i++){
12935 for(var key in objs){
12936 if(this.allowFunctions || typeof objs[key] != "function"){
12937 this.add(key, objs[key]);
12944 * Executes the specified function once for every item in the collection, passing each
12945 * item as the first and only parameter. returning false from the function will stop the iteration.
12946 * @param {Function} fn The function to execute for each item.
12947 * @param {Object} scope (optional) The scope in which to execute the function.
12949 each : function(fn, scope){
12950 var items = [].concat(this.items); // each safe for removal
12951 for(var i = 0, len = items.length; i < len; i++){
12952 if(fn.call(scope || items[i], items[i], i, len) === false){
12959 * Executes the specified function once for every key in the collection, passing each
12960 * key, and its associated item as the first two parameters.
12961 * @param {Function} fn The function to execute for each item.
12962 * @param {Object} scope (optional) The scope in which to execute the function.
12964 eachKey : function(fn, scope){
12965 for(var i = 0, len = this.keys.length; i < len; i++){
12966 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12971 * Returns the first item in the collection which elicits a true return value from the
12972 * passed selection function.
12973 * @param {Function} fn The selection function to execute for each item.
12974 * @param {Object} scope (optional) The scope in which to execute the function.
12975 * @return {Object} The first item in the collection which returned true from the selection function.
12977 find : function(fn, scope){
12978 for(var i = 0, len = this.items.length; i < len; i++){
12979 if(fn.call(scope || window, this.items[i], this.keys[i])){
12980 return this.items[i];
12987 * Inserts an item at the specified index in the collection.
12988 * @param {Number} index The index to insert the item at.
12989 * @param {String} key The key to associate with the new item, or the item itself.
12990 * @param {Object} o (optional) If the second parameter was a key, the new item.
12991 * @return {Object} The item inserted.
12993 insert : function(index, key, o){
12994 if(arguments.length == 2){
12996 key = this.getKey(o);
12998 if(index >= this.length){
12999 return this.add(key, o);
13002 this.items.splice(index, 0, o);
13003 if(typeof key != "undefined" && key != null){
13006 this.keys.splice(index, 0, key);
13007 this.fireEvent("add", index, o, key);
13012 * Removed an item from the collection.
13013 * @param {Object} o The item to remove.
13014 * @return {Object} The item removed.
13016 remove : function(o){
13017 return this.removeAt(this.indexOf(o));
13021 * Remove an item from a specified index in the collection.
13022 * @param {Number} index The index within the collection of the item to remove.
13024 removeAt : function(index){
13025 if(index < this.length && index >= 0){
13027 var o = this.items[index];
13028 this.items.splice(index, 1);
13029 var key = this.keys[index];
13030 if(typeof key != "undefined"){
13031 delete this.map[key];
13033 this.keys.splice(index, 1);
13034 this.fireEvent("remove", o, key);
13039 * Removed an item associated with the passed key fom the collection.
13040 * @param {String} key The key of the item to remove.
13042 removeKey : function(key){
13043 return this.removeAt(this.indexOfKey(key));
13047 * Returns the number of items in the collection.
13048 * @return {Number} the number of items in the collection.
13050 getCount : function(){
13051 return this.length;
13055 * Returns index within the collection of the passed Object.
13056 * @param {Object} o The item to find the index of.
13057 * @return {Number} index of the item.
13059 indexOf : function(o){
13060 if(!this.items.indexOf){
13061 for(var i = 0, len = this.items.length; i < len; i++){
13062 if(this.items[i] == o) return i;
13066 return this.items.indexOf(o);
13071 * Returns index within the collection of the passed key.
13072 * @param {String} key The key to find the index of.
13073 * @return {Number} index of the key.
13075 indexOfKey : function(key){
13076 if(!this.keys.indexOf){
13077 for(var i = 0, len = this.keys.length; i < len; i++){
13078 if(this.keys[i] == key) return i;
13082 return this.keys.indexOf(key);
13087 * Returns the item associated with the passed key OR index. Key has priority over index.
13088 * @param {String/Number} key The key or index of the item.
13089 * @return {Object} The item associated with the passed key.
13091 item : function(key){
13092 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13093 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13097 * Returns the item at the specified index.
13098 * @param {Number} index The index of the item.
13101 itemAt : function(index){
13102 return this.items[index];
13106 * Returns the item associated with the passed key.
13107 * @param {String/Number} key The key of the item.
13108 * @return {Object} The item associated with the passed key.
13110 key : function(key){
13111 return this.map[key];
13115 * Returns true if the collection contains the passed Object as an item.
13116 * @param {Object} o The Object to look for in the collection.
13117 * @return {Boolean} True if the collection contains the Object as an item.
13119 contains : function(o){
13120 return this.indexOf(o) != -1;
13124 * Returns true if the collection contains the passed Object as a key.
13125 * @param {String} key The key to look for in the collection.
13126 * @return {Boolean} True if the collection contains the Object as a key.
13128 containsKey : function(key){
13129 return typeof this.map[key] != "undefined";
13133 * Removes all items from the collection.
13135 clear : function(){
13140 this.fireEvent("clear");
13144 * Returns the first item in the collection.
13145 * @return {Object} the first item in the collection..
13147 first : function(){
13148 return this.items[0];
13152 * Returns the last item in the collection.
13153 * @return {Object} the last item in the collection..
13156 return this.items[this.length-1];
13159 _sort : function(property, dir, fn){
13160 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13161 fn = fn || function(a, b){
13164 var c = [], k = this.keys, items = this.items;
13165 for(var i = 0, len = items.length; i < len; i++){
13166 c[c.length] = {key: k[i], value: items[i], index: i};
13168 c.sort(function(a, b){
13169 var v = fn(a[property], b[property]) * dsc;
13171 v = (a.index < b.index ? -1 : 1);
13175 for(var i = 0, len = c.length; i < len; i++){
13176 items[i] = c[i].value;
13179 this.fireEvent("sort", this);
13183 * Sorts this collection with the passed comparison function
13184 * @param {String} direction (optional) "ASC" or "DESC"
13185 * @param {Function} fn (optional) comparison function
13187 sort : function(dir, fn){
13188 this._sort("value", dir, fn);
13192 * Sorts this collection by keys
13193 * @param {String} direction (optional) "ASC" or "DESC"
13194 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13196 keySort : function(dir, fn){
13197 this._sort("key", dir, fn || function(a, b){
13198 return String(a).toUpperCase()-String(b).toUpperCase();
13203 * Returns a range of items in this collection
13204 * @param {Number} startIndex (optional) defaults to 0
13205 * @param {Number} endIndex (optional) default to the last item
13206 * @return {Array} An array of items
13208 getRange : function(start, end){
13209 var items = this.items;
13210 if(items.length < 1){
13213 start = start || 0;
13214 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13217 for(var i = start; i <= end; i++) {
13218 r[r.length] = items[i];
13221 for(var i = start; i >= end; i--) {
13222 r[r.length] = items[i];
13229 * Filter the <i>objects</i> in this collection by a specific property.
13230 * Returns a new collection that has been filtered.
13231 * @param {String} property A property on your objects
13232 * @param {String/RegExp} value Either string that the property values
13233 * should start with or a RegExp to test against the property
13234 * @return {MixedCollection} The new filtered collection
13236 filter : function(property, value){
13237 if(!value.exec){ // not a regex
13238 value = String(value);
13239 if(value.length == 0){
13240 return this.clone();
13242 value = new RegExp("^" + Roo.escapeRe(value), "i");
13244 return this.filterBy(function(o){
13245 return o && value.test(o[property]);
13250 * Filter by a function. * Returns a new collection that has been filtered.
13251 * The passed function will be called with each
13252 * object in the collection. If the function returns true, the value is included
13253 * otherwise it is filtered.
13254 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13255 * @param {Object} scope (optional) The scope of the function (defaults to this)
13256 * @return {MixedCollection} The new filtered collection
13258 filterBy : function(fn, scope){
13259 var r = new Roo.util.MixedCollection();
13260 r.getKey = this.getKey;
13261 var k = this.keys, it = this.items;
13262 for(var i = 0, len = it.length; i < len; i++){
13263 if(fn.call(scope||this, it[i], k[i])){
13264 r.add(k[i], it[i]);
13271 * Creates a duplicate of this collection
13272 * @return {MixedCollection}
13274 clone : function(){
13275 var r = new Roo.util.MixedCollection();
13276 var k = this.keys, it = this.items;
13277 for(var i = 0, len = it.length; i < len; i++){
13278 r.add(k[i], it[i]);
13280 r.getKey = this.getKey;
13285 * Returns the item associated with the passed key or index.
13287 * @param {String/Number} key The key or index of the item.
13288 * @return {Object} The item associated with the passed key.
13290 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13292 * Ext JS Library 1.1.1
13293 * Copyright(c) 2006-2007, Ext JS, LLC.
13295 * Originally Released Under LGPL - original licence link has changed is not relivant.
13298 * <script type="text/javascript">
13301 * @class Roo.util.JSON
13302 * Modified version of Douglas Crockford"s json.js that doesn"t
13303 * mess with the Object prototype
13304 * http://www.json.org/js.html
13307 Roo.util.JSON = new (function(){
13308 var useHasOwn = {}.hasOwnProperty ? true : false;
13310 // crashes Safari in some instances
13311 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13313 var pad = function(n) {
13314 return n < 10 ? "0" + n : n;
13327 var encodeString = function(s){
13328 if (/["\\\x00-\x1f]/.test(s)) {
13329 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13334 c = b.charCodeAt();
13336 Math.floor(c / 16).toString(16) +
13337 (c % 16).toString(16);
13340 return '"' + s + '"';
13343 var encodeArray = function(o){
13344 var a = ["["], b, i, l = o.length, v;
13345 for (i = 0; i < l; i += 1) {
13347 switch (typeof v) {
13356 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13364 var encodeDate = function(o){
13365 return '"' + o.getFullYear() + "-" +
13366 pad(o.getMonth() + 1) + "-" +
13367 pad(o.getDate()) + "T" +
13368 pad(o.getHours()) + ":" +
13369 pad(o.getMinutes()) + ":" +
13370 pad(o.getSeconds()) + '"';
13374 * Encodes an Object, Array or other value
13375 * @param {Mixed} o The variable to encode
13376 * @return {String} The JSON string
13378 this.encode = function(o)
13380 // should this be extended to fully wrap stringify..
13382 if(typeof o == "undefined" || o === null){
13384 }else if(o instanceof Array){
13385 return encodeArray(o);
13386 }else if(o instanceof Date){
13387 return encodeDate(o);
13388 }else if(typeof o == "string"){
13389 return encodeString(o);
13390 }else if(typeof o == "number"){
13391 return isFinite(o) ? String(o) : "null";
13392 }else if(typeof o == "boolean"){
13395 var a = ["{"], b, i, v;
13397 if(!useHasOwn || o.hasOwnProperty(i)) {
13399 switch (typeof v) {
13408 a.push(this.encode(i), ":",
13409 v === null ? "null" : this.encode(v));
13420 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13421 * @param {String} json The JSON string
13422 * @return {Object} The resulting object
13424 this.decode = function(json){
13426 return /** eval:var:json */ eval("(" + json + ')');
13430 * Shorthand for {@link Roo.util.JSON#encode}
13431 * @member Roo encode
13433 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13435 * Shorthand for {@link Roo.util.JSON#decode}
13436 * @member Roo decode
13438 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13441 * Ext JS Library 1.1.1
13442 * Copyright(c) 2006-2007, Ext JS, LLC.
13444 * Originally Released Under LGPL - original licence link has changed is not relivant.
13447 * <script type="text/javascript">
13451 * @class Roo.util.Format
13452 * Reusable data formatting functions
13455 Roo.util.Format = function(){
13456 var trimRe = /^\s+|\s+$/g;
13459 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13460 * @param {String} value The string to truncate
13461 * @param {Number} length The maximum length to allow before truncating
13462 * @return {String} The converted text
13464 ellipsis : function(value, len){
13465 if(value && value.length > len){
13466 return value.substr(0, len-3)+"...";
13472 * Checks a reference and converts it to empty string if it is undefined
13473 * @param {Mixed} value Reference to check
13474 * @return {Mixed} Empty string if converted, otherwise the original value
13476 undef : function(value){
13477 return typeof value != "undefined" ? value : "";
13481 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13482 * @param {String} value The string to encode
13483 * @return {String} The encoded text
13485 htmlEncode : function(value){
13486 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13490 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13491 * @param {String} value The string to decode
13492 * @return {String} The decoded text
13494 htmlDecode : function(value){
13495 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13499 * Trims any whitespace from either side of a string
13500 * @param {String} value The text to trim
13501 * @return {String} The trimmed text
13503 trim : function(value){
13504 return String(value).replace(trimRe, "");
13508 * Returns a substring from within an original string
13509 * @param {String} value The original text
13510 * @param {Number} start The start index of the substring
13511 * @param {Number} length The length of the substring
13512 * @return {String} The substring
13514 substr : function(value, start, length){
13515 return String(value).substr(start, length);
13519 * Converts a string to all lower case letters
13520 * @param {String} value The text to convert
13521 * @return {String} The converted text
13523 lowercase : function(value){
13524 return String(value).toLowerCase();
13528 * Converts a string to all upper case letters
13529 * @param {String} value The text to convert
13530 * @return {String} The converted text
13532 uppercase : function(value){
13533 return String(value).toUpperCase();
13537 * Converts the first character only of a string to upper case
13538 * @param {String} value The text to convert
13539 * @return {String} The converted text
13541 capitalize : function(value){
13542 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13546 call : function(value, fn){
13547 if(arguments.length > 2){
13548 var args = Array.prototype.slice.call(arguments, 2);
13549 args.unshift(value);
13551 return /** eval:var:value */ eval(fn).apply(window, args);
13553 /** eval:var:value */
13554 return /** eval:var:value */ eval(fn).call(window, value);
13560 * safer version of Math.toFixed..??/
13561 * @param {Number/String} value The numeric value to format
13562 * @param {Number/String} value Decimal places
13563 * @return {String} The formatted currency string
13565 toFixed : function(v, n)
13567 // why not use to fixed - precision is buggered???
13569 return Math.round(v-0);
13571 var fact = Math.pow(10,n+1);
13572 v = (Math.round((v-0)*fact))/fact;
13573 var z = (''+fact).substring(2);
13574 if (v == Math.floor(v)) {
13575 return Math.floor(v) + '.' + z;
13578 // now just padd decimals..
13579 var ps = String(v).split('.');
13580 var fd = (ps[1] + z);
13581 var r = fd.substring(0,n);
13582 var rm = fd.substring(n);
13584 return ps[0] + '.' + r;
13586 r*=1; // turn it into a number;
13588 if (String(r).length != n) {
13591 r = String(r).substring(1); // chop the end off.
13594 return ps[0] + '.' + r;
13599 * Format a number as US currency
13600 * @param {Number/String} value The numeric value to format
13601 * @return {String} The formatted currency string
13603 usMoney : function(v){
13604 return '$' + Roo.util.Format.number(v);
13609 * eventually this should probably emulate php's number_format
13610 * @param {Number/String} value The numeric value to format
13611 * @param {Number} decimals number of decimal places
13612 * @return {String} The formatted currency string
13614 number : function(v,decimals)
13616 // multiply and round.
13617 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13618 var mul = Math.pow(10, decimals);
13619 var zero = String(mul).substring(1);
13620 v = (Math.round((v-0)*mul))/mul;
13622 // if it's '0' number.. then
13624 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13626 var ps = v.split('.');
13630 var r = /(\d+)(\d{3})/;
13632 while (r.test(whole)) {
13633 whole = whole.replace(r, '$1' + ',' + '$2');
13639 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13640 // does not have decimals
13641 (decimals ? ('.' + zero) : '');
13644 return whole + sub ;
13648 * Parse a value into a formatted date using the specified format pattern.
13649 * @param {Mixed} value The value to format
13650 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13651 * @return {String} The formatted date string
13653 date : function(v, format){
13657 if(!(v instanceof Date)){
13658 v = new Date(Date.parse(v));
13660 return v.dateFormat(format || Roo.util.Format.defaults.date);
13664 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13665 * @param {String} format Any valid date format string
13666 * @return {Function} The date formatting function
13668 dateRenderer : function(format){
13669 return function(v){
13670 return Roo.util.Format.date(v, format);
13675 stripTagsRE : /<\/?[^>]+>/gi,
13678 * Strips all HTML tags
13679 * @param {Mixed} value The text from which to strip tags
13680 * @return {String} The stripped text
13682 stripTags : function(v){
13683 return !v ? v : String(v).replace(this.stripTagsRE, "");
13687 Roo.util.Format.defaults = {
13691 * Ext JS Library 1.1.1
13692 * Copyright(c) 2006-2007, Ext JS, LLC.
13694 * Originally Released Under LGPL - original licence link has changed is not relivant.
13697 * <script type="text/javascript">
13704 * @class Roo.MasterTemplate
13705 * @extends Roo.Template
13706 * Provides a template that can have child templates. The syntax is:
13708 var t = new Roo.MasterTemplate(
13709 '<select name="{name}">',
13710 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13713 t.add('options', {value: 'foo', text: 'bar'});
13714 // or you can add multiple child elements in one shot
13715 t.addAll('options', [
13716 {value: 'foo', text: 'bar'},
13717 {value: 'foo2', text: 'bar2'},
13718 {value: 'foo3', text: 'bar3'}
13720 // then append, applying the master template values
13721 t.append('my-form', {name: 'my-select'});
13723 * A name attribute for the child template is not required if you have only one child
13724 * template or you want to refer to them by index.
13726 Roo.MasterTemplate = function(){
13727 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13728 this.originalHtml = this.html;
13730 var m, re = this.subTemplateRe;
13733 while(m = re.exec(this.html)){
13734 var name = m[1], content = m[2];
13739 tpl : new Roo.Template(content)
13742 st[name] = st[subIndex];
13744 st[subIndex].tpl.compile();
13745 st[subIndex].tpl.call = this.call.createDelegate(this);
13748 this.subCount = subIndex;
13751 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13753 * The regular expression used to match sub templates
13757 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13760 * Applies the passed values to a child template.
13761 * @param {String/Number} name (optional) The name or index of the child template
13762 * @param {Array/Object} values The values to be applied to the template
13763 * @return {MasterTemplate} this
13765 add : function(name, values){
13766 if(arguments.length == 1){
13767 values = arguments[0];
13770 var s = this.subs[name];
13771 s.buffer[s.buffer.length] = s.tpl.apply(values);
13776 * Applies all the passed values to a child template.
13777 * @param {String/Number} name (optional) The name or index of the child template
13778 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13779 * @param {Boolean} reset (optional) True to reset the template first
13780 * @return {MasterTemplate} this
13782 fill : function(name, values, reset){
13784 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13792 for(var i = 0, len = values.length; i < len; i++){
13793 this.add(name, values[i]);
13799 * Resets the template for reuse
13800 * @return {MasterTemplate} this
13802 reset : function(){
13804 for(var i = 0; i < this.subCount; i++){
13810 applyTemplate : function(values){
13812 var replaceIndex = -1;
13813 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13814 return s[++replaceIndex].buffer.join("");
13816 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13819 apply : function(){
13820 return this.applyTemplate.apply(this, arguments);
13823 compile : function(){return this;}
13827 * Alias for fill().
13830 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13832 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13833 * var tpl = Roo.MasterTemplate.from('element-id');
13834 * @param {String/HTMLElement} el
13835 * @param {Object} config
13838 Roo.MasterTemplate.from = function(el, config){
13839 el = Roo.getDom(el);
13840 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13843 * Ext JS Library 1.1.1
13844 * Copyright(c) 2006-2007, Ext JS, LLC.
13846 * Originally Released Under LGPL - original licence link has changed is not relivant.
13849 * <script type="text/javascript">
13854 * @class Roo.util.CSS
13855 * Utility class for manipulating CSS rules
13858 Roo.util.CSS = function(){
13860 var doc = document;
13862 var camelRe = /(-[a-z])/gi;
13863 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13867 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13868 * tag and appended to the HEAD of the document.
13869 * @param {String|Object} cssText The text containing the css rules
13870 * @param {String} id An id to add to the stylesheet for later removal
13871 * @return {StyleSheet}
13873 createStyleSheet : function(cssText, id){
13875 var head = doc.getElementsByTagName("head")[0];
13876 var nrules = doc.createElement("style");
13877 nrules.setAttribute("type", "text/css");
13879 nrules.setAttribute("id", id);
13881 if (typeof(cssText) != 'string') {
13882 // support object maps..
13883 // not sure if this a good idea..
13884 // perhaps it should be merged with the general css handling
13885 // and handle js style props.
13886 var cssTextNew = [];
13887 for(var n in cssText) {
13889 for(var k in cssText[n]) {
13890 citems.push( k + ' : ' +cssText[n][k] + ';' );
13892 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13895 cssText = cssTextNew.join("\n");
13901 head.appendChild(nrules);
13902 ss = nrules.styleSheet;
13903 ss.cssText = cssText;
13906 nrules.appendChild(doc.createTextNode(cssText));
13908 nrules.cssText = cssText;
13910 head.appendChild(nrules);
13911 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13913 this.cacheStyleSheet(ss);
13918 * Removes a style or link tag by id
13919 * @param {String} id The id of the tag
13921 removeStyleSheet : function(id){
13922 var existing = doc.getElementById(id);
13924 existing.parentNode.removeChild(existing);
13929 * Dynamically swaps an existing stylesheet reference for a new one
13930 * @param {String} id The id of an existing link tag to remove
13931 * @param {String} url The href of the new stylesheet to include
13933 swapStyleSheet : function(id, url){
13934 this.removeStyleSheet(id);
13935 var ss = doc.createElement("link");
13936 ss.setAttribute("rel", "stylesheet");
13937 ss.setAttribute("type", "text/css");
13938 ss.setAttribute("id", id);
13939 ss.setAttribute("href", url);
13940 doc.getElementsByTagName("head")[0].appendChild(ss);
13944 * Refresh the rule cache if you have dynamically added stylesheets
13945 * @return {Object} An object (hash) of rules indexed by selector
13947 refreshCache : function(){
13948 return this.getRules(true);
13952 cacheStyleSheet : function(stylesheet){
13956 try{// try catch for cross domain access issue
13957 var ssRules = stylesheet.cssRules || stylesheet.rules;
13958 for(var j = ssRules.length-1; j >= 0; --j){
13959 rules[ssRules[j].selectorText] = ssRules[j];
13965 * Gets all css rules for the document
13966 * @param {Boolean} refreshCache true to refresh the internal cache
13967 * @return {Object} An object (hash) of rules indexed by selector
13969 getRules : function(refreshCache){
13970 if(rules == null || refreshCache){
13972 var ds = doc.styleSheets;
13973 for(var i =0, len = ds.length; i < len; i++){
13975 this.cacheStyleSheet(ds[i]);
13983 * Gets an an individual CSS rule by selector(s)
13984 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13985 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13986 * @return {CSSRule} The CSS rule or null if one is not found
13988 getRule : function(selector, refreshCache){
13989 var rs = this.getRules(refreshCache);
13990 if(!(selector instanceof Array)){
13991 return rs[selector];
13993 for(var i = 0; i < selector.length; i++){
13994 if(rs[selector[i]]){
13995 return rs[selector[i]];
14003 * Updates a rule property
14004 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14005 * @param {String} property The css property
14006 * @param {String} value The new value for the property
14007 * @return {Boolean} true If a rule was found and updated
14009 updateRule : function(selector, property, value){
14010 if(!(selector instanceof Array)){
14011 var rule = this.getRule(selector);
14013 rule.style[property.replace(camelRe, camelFn)] = value;
14017 for(var i = 0; i < selector.length; i++){
14018 if(this.updateRule(selector[i], property, value)){
14028 * Ext JS Library 1.1.1
14029 * Copyright(c) 2006-2007, Ext JS, LLC.
14031 * Originally Released Under LGPL - original licence link has changed is not relivant.
14034 * <script type="text/javascript">
14040 * @class Roo.util.ClickRepeater
14041 * @extends Roo.util.Observable
14043 * A wrapper class which can be applied to any element. Fires a "click" event while the
14044 * mouse is pressed. The interval between firings may be specified in the config but
14045 * defaults to 10 milliseconds.
14047 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14049 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14050 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14051 * Similar to an autorepeat key delay.
14052 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14053 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14054 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14055 * "interval" and "delay" are ignored. "immediate" is honored.
14056 * @cfg {Boolean} preventDefault True to prevent the default click event
14057 * @cfg {Boolean} stopDefault True to stop the default click event
14060 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14061 * 2007-02-02 jvs Renamed to ClickRepeater
14062 * 2007-02-03 jvs Modifications for FF Mac and Safari
14065 * @param {String/HTMLElement/Element} el The element to listen on
14066 * @param {Object} config
14068 Roo.util.ClickRepeater = function(el, config)
14070 this.el = Roo.get(el);
14071 this.el.unselectable();
14073 Roo.apply(this, config);
14078 * Fires when the mouse button is depressed.
14079 * @param {Roo.util.ClickRepeater} this
14081 "mousedown" : true,
14084 * Fires on a specified interval during the time the element is pressed.
14085 * @param {Roo.util.ClickRepeater} this
14090 * Fires when the mouse key is released.
14091 * @param {Roo.util.ClickRepeater} this
14096 this.el.on("mousedown", this.handleMouseDown, this);
14097 if(this.preventDefault || this.stopDefault){
14098 this.el.on("click", function(e){
14099 if(this.preventDefault){
14100 e.preventDefault();
14102 if(this.stopDefault){
14108 // allow inline handler
14110 this.on("click", this.handler, this.scope || this);
14113 Roo.util.ClickRepeater.superclass.constructor.call(this);
14116 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14119 preventDefault : true,
14120 stopDefault : false,
14124 handleMouseDown : function(){
14125 clearTimeout(this.timer);
14127 if(this.pressClass){
14128 this.el.addClass(this.pressClass);
14130 this.mousedownTime = new Date();
14132 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14133 this.el.on("mouseout", this.handleMouseOut, this);
14135 this.fireEvent("mousedown", this);
14136 this.fireEvent("click", this);
14138 this.timer = this.click.defer(this.delay || this.interval, this);
14142 click : function(){
14143 this.fireEvent("click", this);
14144 this.timer = this.click.defer(this.getInterval(), this);
14148 getInterval: function(){
14149 if(!this.accelerate){
14150 return this.interval;
14152 var pressTime = this.mousedownTime.getElapsed();
14153 if(pressTime < 500){
14155 }else if(pressTime < 1700){
14157 }else if(pressTime < 2600){
14159 }else if(pressTime < 3500){
14161 }else if(pressTime < 4400){
14163 }else if(pressTime < 5300){
14165 }else if(pressTime < 6200){
14173 handleMouseOut : function(){
14174 clearTimeout(this.timer);
14175 if(this.pressClass){
14176 this.el.removeClass(this.pressClass);
14178 this.el.on("mouseover", this.handleMouseReturn, this);
14182 handleMouseReturn : function(){
14183 this.el.un("mouseover", this.handleMouseReturn);
14184 if(this.pressClass){
14185 this.el.addClass(this.pressClass);
14191 handleMouseUp : function(){
14192 clearTimeout(this.timer);
14193 this.el.un("mouseover", this.handleMouseReturn);
14194 this.el.un("mouseout", this.handleMouseOut);
14195 Roo.get(document).un("mouseup", this.handleMouseUp);
14196 this.el.removeClass(this.pressClass);
14197 this.fireEvent("mouseup", this);
14201 * Ext JS Library 1.1.1
14202 * Copyright(c) 2006-2007, Ext JS, LLC.
14204 * Originally Released Under LGPL - original licence link has changed is not relivant.
14207 * <script type="text/javascript">
14212 * @class Roo.KeyNav
14213 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14214 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14215 * way to implement custom navigation schemes for any UI component.</p>
14216 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14217 * pageUp, pageDown, del, home, end. Usage:</p>
14219 var nav = new Roo.KeyNav("my-element", {
14220 "left" : function(e){
14221 this.moveLeft(e.ctrlKey);
14223 "right" : function(e){
14224 this.moveRight(e.ctrlKey);
14226 "enter" : function(e){
14233 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14234 * @param {Object} config The config
14236 Roo.KeyNav = function(el, config){
14237 this.el = Roo.get(el);
14238 Roo.apply(this, config);
14239 if(!this.disabled){
14240 this.disabled = true;
14245 Roo.KeyNav.prototype = {
14247 * @cfg {Boolean} disabled
14248 * True to disable this KeyNav instance (defaults to false)
14252 * @cfg {String} defaultEventAction
14253 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14254 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14255 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14257 defaultEventAction: "stopEvent",
14259 * @cfg {Boolean} forceKeyDown
14260 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14261 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14262 * handle keydown instead of keypress.
14264 forceKeyDown : false,
14267 prepareEvent : function(e){
14268 var k = e.getKey();
14269 var h = this.keyToHandler[k];
14270 //if(h && this[h]){
14271 // e.stopPropagation();
14273 if(Roo.isSafari && h && k >= 37 && k <= 40){
14279 relay : function(e){
14280 var k = e.getKey();
14281 var h = this.keyToHandler[k];
14283 if(this.doRelay(e, this[h], h) !== true){
14284 e[this.defaultEventAction]();
14290 doRelay : function(e, h, hname){
14291 return h.call(this.scope || this, e);
14294 // possible handlers
14308 // quick lookup hash
14325 * Enable this KeyNav
14327 enable: function(){
14329 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14330 // the EventObject will normalize Safari automatically
14331 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14332 this.el.on("keydown", this.relay, this);
14334 this.el.on("keydown", this.prepareEvent, this);
14335 this.el.on("keypress", this.relay, this);
14337 this.disabled = false;
14342 * Disable this KeyNav
14344 disable: function(){
14345 if(!this.disabled){
14346 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14347 this.el.un("keydown", this.relay);
14349 this.el.un("keydown", this.prepareEvent);
14350 this.el.un("keypress", this.relay);
14352 this.disabled = true;
14357 * Ext JS Library 1.1.1
14358 * Copyright(c) 2006-2007, Ext JS, LLC.
14360 * Originally Released Under LGPL - original licence link has changed is not relivant.
14363 * <script type="text/javascript">
14368 * @class Roo.KeyMap
14369 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14370 * The constructor accepts the same config object as defined by {@link #addBinding}.
14371 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14372 * combination it will call the function with this signature (if the match is a multi-key
14373 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14374 * A KeyMap can also handle a string representation of keys.<br />
14377 // map one key by key code
14378 var map = new Roo.KeyMap("my-element", {
14379 key: 13, // or Roo.EventObject.ENTER
14384 // map multiple keys to one action by string
14385 var map = new Roo.KeyMap("my-element", {
14391 // map multiple keys to multiple actions by strings and array of codes
14392 var map = new Roo.KeyMap("my-element", [
14395 fn: function(){ alert("Return was pressed"); }
14398 fn: function(){ alert('a, b or c was pressed'); }
14403 fn: function(){ alert('Control + shift + tab was pressed.'); }
14407 * <b>Note: A KeyMap starts enabled</b>
14409 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14410 * @param {Object} config The config (see {@link #addBinding})
14411 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14413 Roo.KeyMap = function(el, config, eventName){
14414 this.el = Roo.get(el);
14415 this.eventName = eventName || "keydown";
14416 this.bindings = [];
14418 this.addBinding(config);
14423 Roo.KeyMap.prototype = {
14425 * True to stop the event from bubbling and prevent the default browser action if the
14426 * key was handled by the KeyMap (defaults to false)
14432 * Add a new binding to this KeyMap. The following config object properties are supported:
14434 Property Type Description
14435 ---------- --------------- ----------------------------------------------------------------------
14436 key String/Array A single keycode or an array of keycodes to handle
14437 shift Boolean True to handle key only when shift is pressed (defaults to false)
14438 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14439 alt Boolean True to handle key only when alt is pressed (defaults to false)
14440 fn Function The function to call when KeyMap finds the expected key combination
14441 scope Object The scope of the callback function
14447 var map = new Roo.KeyMap(document, {
14448 key: Roo.EventObject.ENTER,
14453 //Add a new binding to the existing KeyMap later
14461 * @param {Object/Array} config A single KeyMap config or an array of configs
14463 addBinding : function(config){
14464 if(config instanceof Array){
14465 for(var i = 0, len = config.length; i < len; i++){
14466 this.addBinding(config[i]);
14470 var keyCode = config.key,
14471 shift = config.shift,
14472 ctrl = config.ctrl,
14475 scope = config.scope;
14476 if(typeof keyCode == "string"){
14478 var keyString = keyCode.toUpperCase();
14479 for(var j = 0, len = keyString.length; j < len; j++){
14480 ks.push(keyString.charCodeAt(j));
14484 var keyArray = keyCode instanceof Array;
14485 var handler = function(e){
14486 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14487 var k = e.getKey();
14489 for(var i = 0, len = keyCode.length; i < len; i++){
14490 if(keyCode[i] == k){
14491 if(this.stopEvent){
14494 fn.call(scope || window, k, e);
14500 if(this.stopEvent){
14503 fn.call(scope || window, k, e);
14508 this.bindings.push(handler);
14512 * Shorthand for adding a single key listener
14513 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14514 * following options:
14515 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14516 * @param {Function} fn The function to call
14517 * @param {Object} scope (optional) The scope of the function
14519 on : function(key, fn, scope){
14520 var keyCode, shift, ctrl, alt;
14521 if(typeof key == "object" && !(key instanceof Array)){
14540 handleKeyDown : function(e){
14541 if(this.enabled){ //just in case
14542 var b = this.bindings;
14543 for(var i = 0, len = b.length; i < len; i++){
14544 b[i].call(this, e);
14550 * Returns true if this KeyMap is enabled
14551 * @return {Boolean}
14553 isEnabled : function(){
14554 return this.enabled;
14558 * Enables this KeyMap
14560 enable: function(){
14562 this.el.on(this.eventName, this.handleKeyDown, this);
14563 this.enabled = true;
14568 * Disable this KeyMap
14570 disable: function(){
14572 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14573 this.enabled = false;
14578 * Ext JS Library 1.1.1
14579 * Copyright(c) 2006-2007, Ext JS, LLC.
14581 * Originally Released Under LGPL - original licence link has changed is not relivant.
14584 * <script type="text/javascript">
14589 * @class Roo.util.TextMetrics
14590 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14591 * wide, in pixels, a given block of text will be.
14594 Roo.util.TextMetrics = function(){
14598 * Measures the size of the specified text
14599 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14600 * that can affect the size of the rendered text
14601 * @param {String} text The text to measure
14602 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14603 * in order to accurately measure the text height
14604 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14606 measure : function(el, text, fixedWidth){
14608 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14611 shared.setFixedWidth(fixedWidth || 'auto');
14612 return shared.getSize(text);
14616 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14617 * the overhead of multiple calls to initialize the style properties on each measurement.
14618 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14619 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14620 * in order to accurately measure the text height
14621 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14623 createInstance : function(el, fixedWidth){
14624 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14631 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14632 var ml = new Roo.Element(document.createElement('div'));
14633 document.body.appendChild(ml.dom);
14634 ml.position('absolute');
14635 ml.setLeftTop(-1000, -1000);
14639 ml.setWidth(fixedWidth);
14644 * Returns the size of the specified text based on the internal element's style and width properties
14645 * @memberOf Roo.util.TextMetrics.Instance#
14646 * @param {String} text The text to measure
14647 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14649 getSize : function(text){
14651 var s = ml.getSize();
14657 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14658 * that can affect the size of the rendered text
14659 * @memberOf Roo.util.TextMetrics.Instance#
14660 * @param {String/HTMLElement} el The element, dom node or id
14662 bind : function(el){
14664 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14669 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14670 * to set a fixed width in order to accurately measure the text height.
14671 * @memberOf Roo.util.TextMetrics.Instance#
14672 * @param {Number} width The width to set on the element
14674 setFixedWidth : function(width){
14675 ml.setWidth(width);
14679 * Returns the measured width of the specified text
14680 * @memberOf Roo.util.TextMetrics.Instance#
14681 * @param {String} text The text to measure
14682 * @return {Number} width The width in pixels
14684 getWidth : function(text){
14685 ml.dom.style.width = 'auto';
14686 return this.getSize(text).width;
14690 * Returns the measured height of the specified text. For multiline text, be sure to call
14691 * {@link #setFixedWidth} if necessary.
14692 * @memberOf Roo.util.TextMetrics.Instance#
14693 * @param {String} text The text to measure
14694 * @return {Number} height The height in pixels
14696 getHeight : function(text){
14697 return this.getSize(text).height;
14701 instance.bind(bindTo);
14706 // backwards compat
14707 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14709 * Ext JS Library 1.1.1
14710 * Copyright(c) 2006-2007, Ext JS, LLC.
14712 * Originally Released Under LGPL - original licence link has changed is not relivant.
14715 * <script type="text/javascript">
14719 * @class Roo.state.Provider
14720 * Abstract base class for state provider implementations. This class provides methods
14721 * for encoding and decoding <b>typed</b> variables including dates and defines the
14722 * Provider interface.
14724 Roo.state.Provider = function(){
14726 * @event statechange
14727 * Fires when a state change occurs.
14728 * @param {Provider} this This state provider
14729 * @param {String} key The state key which was changed
14730 * @param {String} value The encoded value for the state
14733 "statechange": true
14736 Roo.state.Provider.superclass.constructor.call(this);
14738 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14740 * Returns the current value for a key
14741 * @param {String} name The key name
14742 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14743 * @return {Mixed} The state data
14745 get : function(name, defaultValue){
14746 return typeof this.state[name] == "undefined" ?
14747 defaultValue : this.state[name];
14751 * Clears a value from the state
14752 * @param {String} name The key name
14754 clear : function(name){
14755 delete this.state[name];
14756 this.fireEvent("statechange", this, name, null);
14760 * Sets the value for a key
14761 * @param {String} name The key name
14762 * @param {Mixed} value The value to set
14764 set : function(name, value){
14765 this.state[name] = value;
14766 this.fireEvent("statechange", this, name, value);
14770 * Decodes a string previously encoded with {@link #encodeValue}.
14771 * @param {String} value The value to decode
14772 * @return {Mixed} The decoded value
14774 decodeValue : function(cookie){
14775 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14776 var matches = re.exec(unescape(cookie));
14777 if(!matches || !matches[1]) return; // non state cookie
14778 var type = matches[1];
14779 var v = matches[2];
14782 return parseFloat(v);
14784 return new Date(Date.parse(v));
14789 var values = v.split("^");
14790 for(var i = 0, len = values.length; i < len; i++){
14791 all.push(this.decodeValue(values[i]));
14796 var values = v.split("^");
14797 for(var i = 0, len = values.length; i < len; i++){
14798 var kv = values[i].split("=");
14799 all[kv[0]] = this.decodeValue(kv[1]);
14808 * Encodes a value including type information. Decode with {@link #decodeValue}.
14809 * @param {Mixed} value The value to encode
14810 * @return {String} The encoded value
14812 encodeValue : function(v){
14814 if(typeof v == "number"){
14816 }else if(typeof v == "boolean"){
14817 enc = "b:" + (v ? "1" : "0");
14818 }else if(v instanceof Date){
14819 enc = "d:" + v.toGMTString();
14820 }else if(v instanceof Array){
14822 for(var i = 0, len = v.length; i < len; i++){
14823 flat += this.encodeValue(v[i]);
14824 if(i != len-1) flat += "^";
14827 }else if(typeof v == "object"){
14830 if(typeof v[key] != "function"){
14831 flat += key + "=" + this.encodeValue(v[key]) + "^";
14834 enc = "o:" + flat.substring(0, flat.length-1);
14838 return escape(enc);
14844 * Ext JS Library 1.1.1
14845 * Copyright(c) 2006-2007, Ext JS, LLC.
14847 * Originally Released Under LGPL - original licence link has changed is not relivant.
14850 * <script type="text/javascript">
14853 * @class Roo.state.Manager
14854 * This is the global state manager. By default all components that are "state aware" check this class
14855 * for state information if you don't pass them a custom state provider. In order for this class
14856 * to be useful, it must be initialized with a provider when your application initializes.
14858 // in your initialization function
14860 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14862 // supposed you have a {@link Roo.BorderLayout}
14863 var layout = new Roo.BorderLayout(...);
14864 layout.restoreState();
14865 // or a {Roo.BasicDialog}
14866 var dialog = new Roo.BasicDialog(...);
14867 dialog.restoreState();
14871 Roo.state.Manager = function(){
14872 var provider = new Roo.state.Provider();
14876 * Configures the default state provider for your application
14877 * @param {Provider} stateProvider The state provider to set
14879 setProvider : function(stateProvider){
14880 provider = stateProvider;
14884 * Returns the current value for a key
14885 * @param {String} name The key name
14886 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14887 * @return {Mixed} The state data
14889 get : function(key, defaultValue){
14890 return provider.get(key, defaultValue);
14894 * Sets the value for a key
14895 * @param {String} name The key name
14896 * @param {Mixed} value The state data
14898 set : function(key, value){
14899 provider.set(key, value);
14903 * Clears a value from the state
14904 * @param {String} name The key name
14906 clear : function(key){
14907 provider.clear(key);
14911 * Gets the currently configured state provider
14912 * @return {Provider} The state provider
14914 getProvider : function(){
14921 * Ext JS Library 1.1.1
14922 * Copyright(c) 2006-2007, Ext JS, LLC.
14924 * Originally Released Under LGPL - original licence link has changed is not relivant.
14927 * <script type="text/javascript">
14930 * @class Roo.state.CookieProvider
14931 * @extends Roo.state.Provider
14932 * The default Provider implementation which saves state via cookies.
14935 var cp = new Roo.state.CookieProvider({
14937 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14938 domain: "roojs.com"
14940 Roo.state.Manager.setProvider(cp);
14942 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14943 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14944 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14945 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14946 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14947 * domain the page is running on including the 'www' like 'www.roojs.com')
14948 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14950 * Create a new CookieProvider
14951 * @param {Object} config The configuration object
14953 Roo.state.CookieProvider = function(config){
14954 Roo.state.CookieProvider.superclass.constructor.call(this);
14956 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14957 this.domain = null;
14958 this.secure = false;
14959 Roo.apply(this, config);
14960 this.state = this.readCookies();
14963 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14965 set : function(name, value){
14966 if(typeof value == "undefined" || value === null){
14970 this.setCookie(name, value);
14971 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14975 clear : function(name){
14976 this.clearCookie(name);
14977 Roo.state.CookieProvider.superclass.clear.call(this, name);
14981 readCookies : function(){
14983 var c = document.cookie + ";";
14984 var re = /\s?(.*?)=(.*?);/g;
14986 while((matches = re.exec(c)) != null){
14987 var name = matches[1];
14988 var value = matches[2];
14989 if(name && name.substring(0,3) == "ys-"){
14990 cookies[name.substr(3)] = this.decodeValue(value);
14997 setCookie : function(name, value){
14998 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14999 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15000 ((this.path == null) ? "" : ("; path=" + this.path)) +
15001 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15002 ((this.secure == true) ? "; secure" : "");
15006 clearCookie : function(name){
15007 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15008 ((this.path == null) ? "" : ("; path=" + this.path)) +
15009 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15010 ((this.secure == true) ? "; secure" : "");
15014 * Ext JS Library 1.1.1
15015 * Copyright(c) 2006-2007, Ext JS, LLC.
15017 * Originally Released Under LGPL - original licence link has changed is not relivant.
15020 * <script type="text/javascript">
15025 * @class Roo.ComponentMgr
15026 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15029 Roo.ComponentMgr = function(){
15030 var all = new Roo.util.MixedCollection();
15034 * Registers a component.
15035 * @param {Roo.Component} c The component
15037 register : function(c){
15042 * Unregisters a component.
15043 * @param {Roo.Component} c The component
15045 unregister : function(c){
15050 * Returns a component by id
15051 * @param {String} id The component id
15053 get : function(id){
15054 return all.get(id);
15058 * Registers a function that will be called when a specified component is added to ComponentMgr
15059 * @param {String} id The component id
15060 * @param {Funtction} fn The callback function
15061 * @param {Object} scope The scope of the callback
15063 onAvailable : function(id, fn, scope){
15064 all.on("add", function(index, o){
15066 fn.call(scope || o, o);
15067 all.un("add", fn, scope);
15074 * Ext JS Library 1.1.1
15075 * Copyright(c) 2006-2007, Ext JS, LLC.
15077 * Originally Released Under LGPL - original licence link has changed is not relivant.
15080 * <script type="text/javascript">
15084 * @class Roo.Component
15085 * @extends Roo.util.Observable
15086 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15087 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15088 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15089 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15090 * All visual components (widgets) that require rendering into a layout should subclass Component.
15092 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15093 * 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
15094 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15096 Roo.Component = function(config){
15097 config = config || {};
15098 if(config.tagName || config.dom || typeof config == "string"){ // element object
15099 config = {el: config, id: config.id || config};
15101 this.initialConfig = config;
15103 Roo.apply(this, config);
15107 * Fires after the component is disabled.
15108 * @param {Roo.Component} this
15113 * Fires after the component is enabled.
15114 * @param {Roo.Component} this
15118 * @event beforeshow
15119 * Fires before the component is shown. Return false to stop the show.
15120 * @param {Roo.Component} this
15125 * Fires after the component is shown.
15126 * @param {Roo.Component} this
15130 * @event beforehide
15131 * Fires before the component is hidden. Return false to stop the hide.
15132 * @param {Roo.Component} this
15137 * Fires after the component is hidden.
15138 * @param {Roo.Component} this
15142 * @event beforerender
15143 * Fires before the component is rendered. Return false to stop the render.
15144 * @param {Roo.Component} this
15146 beforerender : true,
15149 * Fires after the component is rendered.
15150 * @param {Roo.Component} this
15154 * @event beforedestroy
15155 * Fires before the component is destroyed. Return false to stop the destroy.
15156 * @param {Roo.Component} this
15158 beforedestroy : true,
15161 * Fires after the component is destroyed.
15162 * @param {Roo.Component} this
15167 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15169 Roo.ComponentMgr.register(this);
15170 Roo.Component.superclass.constructor.call(this);
15171 this.initComponent();
15172 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15173 this.render(this.renderTo);
15174 delete this.renderTo;
15179 Roo.Component.AUTO_ID = 1000;
15181 Roo.extend(Roo.Component, Roo.util.Observable, {
15183 * @scope Roo.Component.prototype
15185 * true if this component is hidden. Read-only.
15190 * true if this component is disabled. Read-only.
15195 * true if this component has been rendered. Read-only.
15199 /** @cfg {String} disableClass
15200 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15202 disabledClass : "x-item-disabled",
15203 /** @cfg {Boolean} allowDomMove
15204 * Whether the component can move the Dom node when rendering (defaults to true).
15206 allowDomMove : true,
15207 /** @cfg {String} hideMode
15208 * How this component should hidden. Supported values are
15209 * "visibility" (css visibility), "offsets" (negative offset position) and
15210 * "display" (css display) - defaults to "display".
15212 hideMode: 'display',
15215 ctype : "Roo.Component",
15218 * @cfg {String} actionMode
15219 * which property holds the element that used for hide() / show() / disable() / enable()
15225 getActionEl : function(){
15226 return this[this.actionMode];
15229 initComponent : Roo.emptyFn,
15231 * If this is a lazy rendering component, render it to its container element.
15232 * @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.
15234 render : function(container, position){
15235 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15236 if(!container && this.el){
15237 this.el = Roo.get(this.el);
15238 container = this.el.dom.parentNode;
15239 this.allowDomMove = false;
15241 this.container = Roo.get(container);
15242 this.rendered = true;
15243 if(position !== undefined){
15244 if(typeof position == 'number'){
15245 position = this.container.dom.childNodes[position];
15247 position = Roo.getDom(position);
15250 this.onRender(this.container, position || null);
15252 this.el.addClass(this.cls);
15256 this.el.applyStyles(this.style);
15259 this.fireEvent("render", this);
15260 this.afterRender(this.container);
15272 // default function is not really useful
15273 onRender : function(ct, position){
15275 this.el = Roo.get(this.el);
15276 if(this.allowDomMove !== false){
15277 ct.dom.insertBefore(this.el.dom, position);
15283 getAutoCreate : function(){
15284 var cfg = typeof this.autoCreate == "object" ?
15285 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15286 if(this.id && !cfg.id){
15293 afterRender : Roo.emptyFn,
15296 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15297 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15299 destroy : function(){
15300 if(this.fireEvent("beforedestroy", this) !== false){
15301 this.purgeListeners();
15302 this.beforeDestroy();
15304 this.el.removeAllListeners();
15306 if(this.actionMode == "container"){
15307 this.container.remove();
15311 Roo.ComponentMgr.unregister(this);
15312 this.fireEvent("destroy", this);
15317 beforeDestroy : function(){
15322 onDestroy : function(){
15327 * Returns the underlying {@link Roo.Element}.
15328 * @return {Roo.Element} The element
15330 getEl : function(){
15335 * Returns the id of this component.
15338 getId : function(){
15343 * Try to focus this component.
15344 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15345 * @return {Roo.Component} this
15347 focus : function(selectText){
15350 if(selectText === true){
15351 this.el.dom.select();
15366 * Disable this component.
15367 * @return {Roo.Component} this
15369 disable : function(){
15373 this.disabled = true;
15374 this.fireEvent("disable", this);
15379 onDisable : function(){
15380 this.getActionEl().addClass(this.disabledClass);
15381 this.el.dom.disabled = true;
15385 * Enable this component.
15386 * @return {Roo.Component} this
15388 enable : function(){
15392 this.disabled = false;
15393 this.fireEvent("enable", this);
15398 onEnable : function(){
15399 this.getActionEl().removeClass(this.disabledClass);
15400 this.el.dom.disabled = false;
15404 * Convenience function for setting disabled/enabled by boolean.
15405 * @param {Boolean} disabled
15407 setDisabled : function(disabled){
15408 this[disabled ? "disable" : "enable"]();
15412 * Show this component.
15413 * @return {Roo.Component} this
15416 if(this.fireEvent("beforeshow", this) !== false){
15417 this.hidden = false;
15421 this.fireEvent("show", this);
15427 onShow : function(){
15428 var ae = this.getActionEl();
15429 if(this.hideMode == 'visibility'){
15430 ae.dom.style.visibility = "visible";
15431 }else if(this.hideMode == 'offsets'){
15432 ae.removeClass('x-hidden');
15434 ae.dom.style.display = "";
15439 * Hide this component.
15440 * @return {Roo.Component} this
15443 if(this.fireEvent("beforehide", this) !== false){
15444 this.hidden = true;
15448 this.fireEvent("hide", this);
15454 onHide : function(){
15455 var ae = this.getActionEl();
15456 if(this.hideMode == 'visibility'){
15457 ae.dom.style.visibility = "hidden";
15458 }else if(this.hideMode == 'offsets'){
15459 ae.addClass('x-hidden');
15461 ae.dom.style.display = "none";
15466 * Convenience function to hide or show this component by boolean.
15467 * @param {Boolean} visible True to show, false to hide
15468 * @return {Roo.Component} this
15470 setVisible: function(visible){
15480 * Returns true if this component is visible.
15482 isVisible : function(){
15483 return this.getActionEl().isVisible();
15486 cloneConfig : function(overrides){
15487 overrides = overrides || {};
15488 var id = overrides.id || Roo.id();
15489 var cfg = Roo.applyIf(overrides, this.initialConfig);
15490 cfg.id = id; // prevent dup id
15491 return new this.constructor(cfg);
15495 * Ext JS Library 1.1.1
15496 * Copyright(c) 2006-2007, Ext JS, LLC.
15498 * Originally Released Under LGPL - original licence link has changed is not relivant.
15501 * <script type="text/javascript">
15505 * @class Roo.BoxComponent
15506 * @extends Roo.Component
15507 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15508 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15509 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15510 * layout containers.
15512 * @param {Roo.Element/String/Object} config The configuration options.
15514 Roo.BoxComponent = function(config){
15515 Roo.Component.call(this, config);
15519 * Fires after the component is resized.
15520 * @param {Roo.Component} this
15521 * @param {Number} adjWidth The box-adjusted width that was set
15522 * @param {Number} adjHeight The box-adjusted height that was set
15523 * @param {Number} rawWidth The width that was originally specified
15524 * @param {Number} rawHeight The height that was originally specified
15529 * Fires after the component is moved.
15530 * @param {Roo.Component} this
15531 * @param {Number} x The new x position
15532 * @param {Number} y The new y position
15538 Roo.extend(Roo.BoxComponent, Roo.Component, {
15539 // private, set in afterRender to signify that the component has been rendered
15541 // private, used to defer height settings to subclasses
15542 deferHeight: false,
15543 /** @cfg {Number} width
15544 * width (optional) size of component
15546 /** @cfg {Number} height
15547 * height (optional) size of component
15551 * Sets the width and height of the component. This method fires the resize event. This method can accept
15552 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15553 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15554 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15555 * @return {Roo.BoxComponent} this
15557 setSize : function(w, h){
15558 // support for standard size objects
15559 if(typeof w == 'object'){
15564 if(!this.boxReady){
15570 // prevent recalcs when not needed
15571 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15574 this.lastSize = {width: w, height: h};
15576 var adj = this.adjustSize(w, h);
15577 var aw = adj.width, ah = adj.height;
15578 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15579 var rz = this.getResizeEl();
15580 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15581 rz.setSize(aw, ah);
15582 }else if(!this.deferHeight && ah !== undefined){
15584 }else if(aw !== undefined){
15587 this.onResize(aw, ah, w, h);
15588 this.fireEvent('resize', this, aw, ah, w, h);
15594 * Gets the current size of the component's underlying element.
15595 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15597 getSize : function(){
15598 return this.el.getSize();
15602 * Gets the current XY position of the component's underlying element.
15603 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15604 * @return {Array} The XY position of the element (e.g., [100, 200])
15606 getPosition : function(local){
15607 if(local === true){
15608 return [this.el.getLeft(true), this.el.getTop(true)];
15610 return this.xy || this.el.getXY();
15614 * Gets the current box measurements of the component's underlying element.
15615 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15616 * @returns {Object} box An object in the format {x, y, width, height}
15618 getBox : function(local){
15619 var s = this.el.getSize();
15621 s.x = this.el.getLeft(true);
15622 s.y = this.el.getTop(true);
15624 var xy = this.xy || this.el.getXY();
15632 * Sets the current box measurements of the component's underlying element.
15633 * @param {Object} box An object in the format {x, y, width, height}
15634 * @returns {Roo.BoxComponent} this
15636 updateBox : function(box){
15637 this.setSize(box.width, box.height);
15638 this.setPagePosition(box.x, box.y);
15643 getResizeEl : function(){
15644 return this.resizeEl || this.el;
15648 getPositionEl : function(){
15649 return this.positionEl || this.el;
15653 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15654 * This method fires the move event.
15655 * @param {Number} left The new left
15656 * @param {Number} top The new top
15657 * @returns {Roo.BoxComponent} this
15659 setPosition : function(x, y){
15662 if(!this.boxReady){
15665 var adj = this.adjustPosition(x, y);
15666 var ax = adj.x, ay = adj.y;
15668 var el = this.getPositionEl();
15669 if(ax !== undefined || ay !== undefined){
15670 if(ax !== undefined && ay !== undefined){
15671 el.setLeftTop(ax, ay);
15672 }else if(ax !== undefined){
15674 }else if(ay !== undefined){
15677 this.onPosition(ax, ay);
15678 this.fireEvent('move', this, ax, ay);
15684 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15685 * This method fires the move event.
15686 * @param {Number} x The new x position
15687 * @param {Number} y The new y position
15688 * @returns {Roo.BoxComponent} this
15690 setPagePosition : function(x, y){
15693 if(!this.boxReady){
15696 if(x === undefined || y === undefined){ // cannot translate undefined points
15699 var p = this.el.translatePoints(x, y);
15700 this.setPosition(p.left, p.top);
15705 onRender : function(ct, position){
15706 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15708 this.resizeEl = Roo.get(this.resizeEl);
15710 if(this.positionEl){
15711 this.positionEl = Roo.get(this.positionEl);
15716 afterRender : function(){
15717 Roo.BoxComponent.superclass.afterRender.call(this);
15718 this.boxReady = true;
15719 this.setSize(this.width, this.height);
15720 if(this.x || this.y){
15721 this.setPosition(this.x, this.y);
15723 if(this.pageX || this.pageY){
15724 this.setPagePosition(this.pageX, this.pageY);
15729 * Force the component's size to recalculate based on the underlying element's current height and width.
15730 * @returns {Roo.BoxComponent} this
15732 syncSize : function(){
15733 delete this.lastSize;
15734 this.setSize(this.el.getWidth(), this.el.getHeight());
15739 * Called after the component is resized, this method is empty by default but can be implemented by any
15740 * subclass that needs to perform custom logic after a resize occurs.
15741 * @param {Number} adjWidth The box-adjusted width that was set
15742 * @param {Number} adjHeight The box-adjusted height that was set
15743 * @param {Number} rawWidth The width that was originally specified
15744 * @param {Number} rawHeight The height that was originally specified
15746 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15751 * Called after the component is moved, this method is empty by default but can be implemented by any
15752 * subclass that needs to perform custom logic after a move occurs.
15753 * @param {Number} x The new x position
15754 * @param {Number} y The new y position
15756 onPosition : function(x, y){
15761 adjustSize : function(w, h){
15762 if(this.autoWidth){
15765 if(this.autoHeight){
15768 return {width : w, height: h};
15772 adjustPosition : function(x, y){
15773 return {x : x, y: y};
15776 * Original code for Roojs - LGPL
15777 * <script type="text/javascript">
15781 * @class Roo.XComponent
15782 * A delayed Element creator...
15783 * Or a way to group chunks of interface together.
15784 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15785 * used in conjunction with XComponent.build() it will create an instance of each element,
15786 * then call addxtype() to build the User interface.
15788 * Mypart.xyx = new Roo.XComponent({
15790 parent : 'Mypart.xyz', // empty == document.element.!!
15794 disabled : function() {}
15796 tree : function() { // return an tree of xtype declared components
15800 xtype : 'NestedLayoutPanel',
15807 * It can be used to build a big heiracy, with parent etc.
15808 * or you can just use this to render a single compoent to a dom element
15809 * MYPART.render(Roo.Element | String(id) | dom_element )
15816 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15817 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15819 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15821 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15822 * - if mulitple topModules exist, the last one is defined as the top module.
15826 * When the top level or multiple modules are to embedded into a existing HTML page,
15827 * the parent element can container '#id' of the element where the module will be drawn.
15831 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15832 * it relies more on a include mechanism, where sub modules are included into an outer page.
15833 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15835 * Bootstrap Roo Included elements
15837 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15838 * hence confusing the component builder as it thinks there are multiple top level elements.
15842 * @extends Roo.util.Observable
15844 * @param cfg {Object} configuration of component
15847 Roo.XComponent = function(cfg) {
15848 Roo.apply(this, cfg);
15852 * Fires when this the componnt is built
15853 * @param {Roo.XComponent} c the component
15858 this.region = this.region || 'center'; // default..
15859 Roo.XComponent.register(this);
15860 this.modules = false;
15861 this.el = false; // where the layout goes..
15865 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15868 * The created element (with Roo.factory())
15869 * @type {Roo.Layout}
15875 * for BC - use el in new code
15876 * @type {Roo.Layout}
15882 * for BC - use el in new code
15883 * @type {Roo.Layout}
15888 * @cfg {Function|boolean} disabled
15889 * If this module is disabled by some rule, return true from the funtion
15894 * @cfg {String} parent
15895 * Name of parent element which it get xtype added to..
15900 * @cfg {String} order
15901 * Used to set the order in which elements are created (usefull for multiple tabs)
15906 * @cfg {String} name
15907 * String to display while loading.
15911 * @cfg {String} region
15912 * Region to render component to (defaults to center)
15917 * @cfg {Array} items
15918 * A single item array - the first element is the root of the tree..
15919 * It's done this way to stay compatible with the Xtype system...
15925 * The method that retuns the tree of parts that make up this compoennt
15932 * render element to dom or tree
15933 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15936 render : function(el)
15940 var hp = this.parent ? 1 : 0;
15941 Roo.debug && Roo.log(this);
15943 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15944 // if parent is a '#.....' string, then let's use that..
15945 var ename = this.parent.substr(1);
15946 this.parent = false;
15947 Roo.debug && Roo.log(ename);
15949 case 'bootstrap-body' :
15950 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15951 this.parent = { el : new Roo.bootstrap.Body() };
15952 Roo.debug && Roo.log("setting el to doc body");
15955 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15959 this.parent = { el : true};
15962 el = Roo.get(ename);
15967 if (!el && !this.parent) {
15968 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15972 Roo.debug && Roo.log("EL:");
15973 Roo.debug && Roo.log(el);
15974 Roo.debug && Roo.log("this.parent.el:");
15975 Roo.debug && Roo.log(this.parent.el);
15977 var tree = this._tree ? this._tree() : this.tree();
15979 // altertive root elements ??? - we need a better way to indicate these.
15980 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15981 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15983 if (!this.parent && is_alt) {
15984 //el = Roo.get(document.body);
15985 this.parent = { el : true };
15990 if (!this.parent) {
15992 Roo.debug && Roo.log("no parent - creating one");
15994 el = el ? Roo.get(el) : false;
15996 // it's a top level one..
15998 el : new Roo.BorderLayout(el || document.body, {
16004 tabPosition: 'top',
16005 //resizeTabs: true,
16006 alwaysShowTabs: el && hp? false : true,
16007 hideTabs: el || !hp ? true : false,
16014 if (!this.parent.el) {
16015 // probably an old style ctor, which has been disabled.
16019 // The 'tree' method is '_tree now'
16021 tree.region = tree.region || this.region;
16023 if (this.parent.el === true) {
16024 // bootstrap... - body..
16025 this.parent.el = Roo.factory(tree);
16028 this.el = this.parent.el.addxtype(tree);
16029 this.fireEvent('built', this);
16031 this.panel = this.el;
16032 this.layout = this.panel.layout;
16033 this.parentLayout = this.parent.layout || false;
16039 Roo.apply(Roo.XComponent, {
16041 * @property hideProgress
16042 * true to disable the building progress bar.. usefull on single page renders.
16045 hideProgress : false,
16047 * @property buildCompleted
16048 * True when the builder has completed building the interface.
16051 buildCompleted : false,
16054 * @property topModule
16055 * the upper most module - uses document.element as it's constructor.
16062 * @property modules
16063 * array of modules to be created by registration system.
16064 * @type {Array} of Roo.XComponent
16069 * @property elmodules
16070 * array of modules to be created by which use #ID
16071 * @type {Array} of Roo.XComponent
16077 * @property build_from_html
16078 * Build elements from html - used by bootstrap HTML stuff
16079 * - this is cleared after build is completed
16080 * @type {boolean} true (default false)
16083 build_from_html : false,
16086 * Register components to be built later.
16088 * This solves the following issues
16089 * - Building is not done on page load, but after an authentication process has occured.
16090 * - Interface elements are registered on page load
16091 * - Parent Interface elements may not be loaded before child, so this handles that..
16098 module : 'Pman.Tab.projectMgr',
16100 parent : 'Pman.layout',
16101 disabled : false, // or use a function..
16104 * * @param {Object} details about module
16106 register : function(obj) {
16108 Roo.XComponent.event.fireEvent('register', obj);
16109 switch(typeof(obj.disabled) ) {
16115 if ( obj.disabled() ) {
16121 if (obj.disabled) {
16127 this.modules.push(obj);
16131 * convert a string to an object..
16132 * eg. 'AAA.BBB' -> finds AAA.BBB
16136 toObject : function(str)
16138 if (!str || typeof(str) == 'object') {
16141 if (str.substring(0,1) == '#') {
16145 var ar = str.split('.');
16150 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16152 throw "Module not found : " + str;
16156 throw "Module not found : " + str;
16158 Roo.each(ar, function(e) {
16159 if (typeof(o[e]) == 'undefined') {
16160 throw "Module not found : " + str;
16171 * move modules into their correct place in the tree..
16174 preBuild : function ()
16177 Roo.each(this.modules , function (obj)
16179 Roo.XComponent.event.fireEvent('beforebuild', obj);
16181 var opar = obj.parent;
16183 obj.parent = this.toObject(opar);
16185 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16190 Roo.debug && Roo.log("GOT top level module");
16191 Roo.debug && Roo.log(obj);
16192 obj.modules = new Roo.util.MixedCollection(false,
16193 function(o) { return o.order + '' }
16195 this.topModule = obj;
16198 // parent is a string (usually a dom element name..)
16199 if (typeof(obj.parent) == 'string') {
16200 this.elmodules.push(obj);
16203 if (obj.parent.constructor != Roo.XComponent) {
16204 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16206 if (!obj.parent.modules) {
16207 obj.parent.modules = new Roo.util.MixedCollection(false,
16208 function(o) { return o.order + '' }
16211 if (obj.parent.disabled) {
16212 obj.disabled = true;
16214 obj.parent.modules.add(obj);
16219 * make a list of modules to build.
16220 * @return {Array} list of modules.
16223 buildOrder : function()
16226 var cmp = function(a,b) {
16227 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16229 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16230 throw "No top level modules to build";
16233 // make a flat list in order of modules to build.
16234 var mods = this.topModule ? [ this.topModule ] : [];
16237 // elmodules (is a list of DOM based modules )
16238 Roo.each(this.elmodules, function(e) {
16240 if (!this.topModule &&
16241 typeof(e.parent) == 'string' &&
16242 e.parent.substring(0,1) == '#' &&
16243 Roo.get(e.parent.substr(1))
16246 _this.topModule = e;
16252 // add modules to their parents..
16253 var addMod = function(m) {
16254 Roo.debug && Roo.log("build Order: add: " + m.name);
16257 if (m.modules && !m.disabled) {
16258 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16259 m.modules.keySort('ASC', cmp );
16260 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16262 m.modules.each(addMod);
16264 Roo.debug && Roo.log("build Order: no child modules");
16266 // not sure if this is used any more..
16268 m.finalize.name = m.name + " (clean up) ";
16269 mods.push(m.finalize);
16273 if (this.topModule && this.topModule.modules) {
16274 this.topModule.modules.keySort('ASC', cmp );
16275 this.topModule.modules.each(addMod);
16281 * Build the registered modules.
16282 * @param {Object} parent element.
16283 * @param {Function} optional method to call after module has been added.
16287 build : function(opts)
16290 if (typeof(opts) != 'undefined') {
16291 Roo.apply(this,opts);
16295 var mods = this.buildOrder();
16297 //this.allmods = mods;
16298 //Roo.debug && Roo.log(mods);
16300 if (!mods.length) { // should not happen
16301 throw "NO modules!!!";
16305 var msg = "Building Interface...";
16306 // flash it up as modal - so we store the mask!?
16307 if (!this.hideProgress && Roo.MessageBox) {
16308 Roo.MessageBox.show({ title: 'loading' });
16309 Roo.MessageBox.show({
16310 title: "Please wait...",
16319 var total = mods.length;
16322 var progressRun = function() {
16323 if (!mods.length) {
16324 Roo.debug && Roo.log('hide?');
16325 if (!this.hideProgress && Roo.MessageBox) {
16326 Roo.MessageBox.hide();
16328 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16330 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16336 var m = mods.shift();
16339 Roo.debug && Roo.log(m);
16340 // not sure if this is supported any more.. - modules that are are just function
16341 if (typeof(m) == 'function') {
16343 return progressRun.defer(10, _this);
16347 msg = "Building Interface " + (total - mods.length) +
16349 (m.name ? (' - ' + m.name) : '');
16350 Roo.debug && Roo.log(msg);
16351 if (!this.hideProgress && Roo.MessageBox) {
16352 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16356 // is the module disabled?
16357 var disabled = (typeof(m.disabled) == 'function') ?
16358 m.disabled.call(m.module.disabled) : m.disabled;
16362 return progressRun(); // we do not update the display!
16370 // it's 10 on top level, and 1 on others??? why...
16371 return progressRun.defer(10, _this);
16374 progressRun.defer(1, _this);
16388 * wrapper for event.on - aliased later..
16389 * Typically use to register a event handler for register:
16391 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16400 Roo.XComponent.event = new Roo.util.Observable({
16404 * Fires when an Component is registered,
16405 * set the disable property on the Component to stop registration.
16406 * @param {Roo.XComponent} c the component being registerd.
16411 * @event beforebuild
16412 * Fires before each Component is built
16413 * can be used to apply permissions.
16414 * @param {Roo.XComponent} c the component being registerd.
16417 'beforebuild' : true,
16419 * @event buildcomplete
16420 * Fires on the top level element when all elements have been built
16421 * @param {Roo.XComponent} the top level component.
16423 'buildcomplete' : true
16428 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16431 * Ext JS Library 1.1.1
16432 * Copyright(c) 2006-2007, Ext JS, LLC.
16434 * Originally Released Under LGPL - original licence link has changed is not relivant.
16437 * <script type="text/javascript">
16443 * These classes are derivatives of the similarly named classes in the YUI Library.
16444 * The original license:
16445 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16446 * Code licensed under the BSD License:
16447 * http://developer.yahoo.net/yui/license.txt
16452 var Event=Roo.EventManager;
16453 var Dom=Roo.lib.Dom;
16456 * @class Roo.dd.DragDrop
16457 * @extends Roo.util.Observable
16458 * Defines the interface and base operation of items that that can be
16459 * dragged or can be drop targets. It was designed to be extended, overriding
16460 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16461 * Up to three html elements can be associated with a DragDrop instance:
16463 * <li>linked element: the element that is passed into the constructor.
16464 * This is the element which defines the boundaries for interaction with
16465 * other DragDrop objects.</li>
16466 * <li>handle element(s): The drag operation only occurs if the element that
16467 * was clicked matches a handle element. By default this is the linked
16468 * element, but there are times that you will want only a portion of the
16469 * linked element to initiate the drag operation, and the setHandleElId()
16470 * method provides a way to define this.</li>
16471 * <li>drag element: this represents the element that would be moved along
16472 * with the cursor during a drag operation. By default, this is the linked
16473 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16474 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16477 * This class should not be instantiated until the onload event to ensure that
16478 * the associated elements are available.
16479 * The following would define a DragDrop obj that would interact with any
16480 * other DragDrop obj in the "group1" group:
16482 * dd = new Roo.dd.DragDrop("div1", "group1");
16484 * Since none of the event handlers have been implemented, nothing would
16485 * actually happen if you were to run the code above. Normally you would
16486 * override this class or one of the default implementations, but you can
16487 * also override the methods you want on an instance of the class...
16489 * dd.onDragDrop = function(e, id) {
16490 * alert("dd was dropped on " + id);
16494 * @param {String} id of the element that is linked to this instance
16495 * @param {String} sGroup the group of related DragDrop objects
16496 * @param {object} config an object containing configurable attributes
16497 * Valid properties for DragDrop:
16498 * padding, isTarget, maintainOffset, primaryButtonOnly
16500 Roo.dd.DragDrop = function(id, sGroup, config) {
16502 this.init(id, sGroup, config);
16507 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16510 * The id of the element associated with this object. This is what we
16511 * refer to as the "linked element" because the size and position of
16512 * this element is used to determine when the drag and drop objects have
16520 * Configuration attributes passed into the constructor
16527 * The id of the element that will be dragged. By default this is same
16528 * as the linked element , but could be changed to another element. Ex:
16530 * @property dragElId
16537 * the id of the element that initiates the drag operation. By default
16538 * this is the linked element, but could be changed to be a child of this
16539 * element. This lets us do things like only starting the drag when the
16540 * header element within the linked html element is clicked.
16541 * @property handleElId
16548 * An associative array of HTML tags that will be ignored if clicked.
16549 * @property invalidHandleTypes
16550 * @type {string: string}
16552 invalidHandleTypes: null,
16555 * An associative array of ids for elements that will be ignored if clicked
16556 * @property invalidHandleIds
16557 * @type {string: string}
16559 invalidHandleIds: null,
16562 * An indexted array of css class names for elements that will be ignored
16564 * @property invalidHandleClasses
16567 invalidHandleClasses: null,
16570 * The linked element's absolute X position at the time the drag was
16572 * @property startPageX
16579 * The linked element's absolute X position at the time the drag was
16581 * @property startPageY
16588 * The group defines a logical collection of DragDrop objects that are
16589 * related. Instances only get events when interacting with other
16590 * DragDrop object in the same group. This lets us define multiple
16591 * groups using a single DragDrop subclass if we want.
16593 * @type {string: string}
16598 * Individual drag/drop instances can be locked. This will prevent
16599 * onmousedown start drag.
16607 * Lock this instance
16610 lock: function() { this.locked = true; },
16613 * Unlock this instace
16616 unlock: function() { this.locked = false; },
16619 * By default, all insances can be a drop target. This can be disabled by
16620 * setting isTarget to false.
16627 * The padding configured for this drag and drop object for calculating
16628 * the drop zone intersection with this object.
16635 * Cached reference to the linked element
16636 * @property _domRef
16642 * Internal typeof flag
16643 * @property __ygDragDrop
16646 __ygDragDrop: true,
16649 * Set to true when horizontal contraints are applied
16650 * @property constrainX
16657 * Set to true when vertical contraints are applied
16658 * @property constrainY
16665 * The left constraint
16673 * The right constraint
16681 * The up constraint
16690 * The down constraint
16698 * Maintain offsets when we resetconstraints. Set to true when you want
16699 * the position of the element relative to its parent to stay the same
16700 * when the page changes
16702 * @property maintainOffset
16705 maintainOffset: false,
16708 * Array of pixel locations the element will snap to if we specified a
16709 * horizontal graduation/interval. This array is generated automatically
16710 * when you define a tick interval.
16717 * Array of pixel locations the element will snap to if we specified a
16718 * vertical graduation/interval. This array is generated automatically
16719 * when you define a tick interval.
16726 * By default the drag and drop instance will only respond to the primary
16727 * button click (left button for a right-handed mouse). Set to true to
16728 * allow drag and drop to start with any mouse click that is propogated
16730 * @property primaryButtonOnly
16733 primaryButtonOnly: true,
16736 * The availabe property is false until the linked dom element is accessible.
16737 * @property available
16743 * By default, drags can only be initiated if the mousedown occurs in the
16744 * region the linked element is. This is done in part to work around a
16745 * bug in some browsers that mis-report the mousedown if the previous
16746 * mouseup happened outside of the window. This property is set to true
16747 * if outer handles are defined.
16749 * @property hasOuterHandles
16753 hasOuterHandles: false,
16756 * Code that executes immediately before the startDrag event
16757 * @method b4StartDrag
16760 b4StartDrag: function(x, y) { },
16763 * Abstract method called after a drag/drop object is clicked
16764 * and the drag or mousedown time thresholds have beeen met.
16765 * @method startDrag
16766 * @param {int} X click location
16767 * @param {int} Y click location
16769 startDrag: function(x, y) { /* override this */ },
16772 * Code that executes immediately before the onDrag event
16776 b4Drag: function(e) { },
16779 * Abstract method called during the onMouseMove event while dragging an
16782 * @param {Event} e the mousemove event
16784 onDrag: function(e) { /* override this */ },
16787 * Abstract method called when this element fist begins hovering over
16788 * another DragDrop obj
16789 * @method onDragEnter
16790 * @param {Event} e the mousemove event
16791 * @param {String|DragDrop[]} id In POINT mode, the element
16792 * id this is hovering over. In INTERSECT mode, an array of one or more
16793 * dragdrop items being hovered over.
16795 onDragEnter: function(e, id) { /* override this */ },
16798 * Code that executes immediately before the onDragOver event
16799 * @method b4DragOver
16802 b4DragOver: function(e) { },
16805 * Abstract method called when this element is hovering over another
16807 * @method onDragOver
16808 * @param {Event} e the mousemove event
16809 * @param {String|DragDrop[]} id In POINT mode, the element
16810 * id this is hovering over. In INTERSECT mode, an array of dd items
16811 * being hovered over.
16813 onDragOver: function(e, id) { /* override this */ },
16816 * Code that executes immediately before the onDragOut event
16817 * @method b4DragOut
16820 b4DragOut: function(e) { },
16823 * Abstract method called when we are no longer hovering over an element
16824 * @method onDragOut
16825 * @param {Event} e the mousemove event
16826 * @param {String|DragDrop[]} id In POINT mode, the element
16827 * id this was hovering over. In INTERSECT mode, an array of dd items
16828 * that the mouse is no longer over.
16830 onDragOut: function(e, id) { /* override this */ },
16833 * Code that executes immediately before the onDragDrop event
16834 * @method b4DragDrop
16837 b4DragDrop: function(e) { },
16840 * Abstract method called when this item is dropped on another DragDrop
16842 * @method onDragDrop
16843 * @param {Event} e the mouseup event
16844 * @param {String|DragDrop[]} id In POINT mode, the element
16845 * id this was dropped on. In INTERSECT mode, an array of dd items this
16848 onDragDrop: function(e, id) { /* override this */ },
16851 * Abstract method called when this item is dropped on an area with no
16853 * @method onInvalidDrop
16854 * @param {Event} e the mouseup event
16856 onInvalidDrop: function(e) { /* override this */ },
16859 * Code that executes immediately before the endDrag event
16860 * @method b4EndDrag
16863 b4EndDrag: function(e) { },
16866 * Fired when we are done dragging the object
16868 * @param {Event} e the mouseup event
16870 endDrag: function(e) { /* override this */ },
16873 * Code executed immediately before the onMouseDown event
16874 * @method b4MouseDown
16875 * @param {Event} e the mousedown event
16878 b4MouseDown: function(e) { },
16881 * Event handler that fires when a drag/drop obj gets a mousedown
16882 * @method onMouseDown
16883 * @param {Event} e the mousedown event
16885 onMouseDown: function(e) { /* override this */ },
16888 * Event handler that fires when a drag/drop obj gets a mouseup
16889 * @method onMouseUp
16890 * @param {Event} e the mouseup event
16892 onMouseUp: function(e) { /* override this */ },
16895 * Override the onAvailable method to do what is needed after the initial
16896 * position was determined.
16897 * @method onAvailable
16899 onAvailable: function () {
16903 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16906 defaultPadding : {left:0, right:0, top:0, bottom:0},
16909 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16913 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16914 { dragElId: "existingProxyDiv" });
16915 dd.startDrag = function(){
16916 this.constrainTo("parent-id");
16919 * Or you can initalize it using the {@link Roo.Element} object:
16921 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16922 startDrag : function(){
16923 this.constrainTo("parent-id");
16927 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16928 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16929 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16930 * an object containing the sides to pad. For example: {right:10, bottom:10}
16931 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16933 constrainTo : function(constrainTo, pad, inContent){
16934 if(typeof pad == "number"){
16935 pad = {left: pad, right:pad, top:pad, bottom:pad};
16937 pad = pad || this.defaultPadding;
16938 var b = Roo.get(this.getEl()).getBox();
16939 var ce = Roo.get(constrainTo);
16940 var s = ce.getScroll();
16941 var c, cd = ce.dom;
16942 if(cd == document.body){
16943 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16946 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16950 var topSpace = b.y - c.y;
16951 var leftSpace = b.x - c.x;
16953 this.resetConstraints();
16954 this.setXConstraint(leftSpace - (pad.left||0), // left
16955 c.width - leftSpace - b.width - (pad.right||0) //right
16957 this.setYConstraint(topSpace - (pad.top||0), //top
16958 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16963 * Returns a reference to the linked element
16965 * @return {HTMLElement} the html element
16967 getEl: function() {
16968 if (!this._domRef) {
16969 this._domRef = Roo.getDom(this.id);
16972 return this._domRef;
16976 * Returns a reference to the actual element to drag. By default this is
16977 * the same as the html element, but it can be assigned to another
16978 * element. An example of this can be found in Roo.dd.DDProxy
16979 * @method getDragEl
16980 * @return {HTMLElement} the html element
16982 getDragEl: function() {
16983 return Roo.getDom(this.dragElId);
16987 * Sets up the DragDrop object. Must be called in the constructor of any
16988 * Roo.dd.DragDrop subclass
16990 * @param id the id of the linked element
16991 * @param {String} sGroup the group of related items
16992 * @param {object} config configuration attributes
16994 init: function(id, sGroup, config) {
16995 this.initTarget(id, sGroup, config);
16996 if (!Roo.isTouch) {
16997 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16999 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17000 // Event.on(this.id, "selectstart", Event.preventDefault);
17004 * Initializes Targeting functionality only... the object does not
17005 * get a mousedown handler.
17006 * @method initTarget
17007 * @param id the id of the linked element
17008 * @param {String} sGroup the group of related items
17009 * @param {object} config configuration attributes
17011 initTarget: function(id, sGroup, config) {
17013 // configuration attributes
17014 this.config = config || {};
17016 // create a local reference to the drag and drop manager
17017 this.DDM = Roo.dd.DDM;
17018 // initialize the groups array
17021 // assume that we have an element reference instead of an id if the
17022 // parameter is not a string
17023 if (typeof id !== "string") {
17030 // add to an interaction group
17031 this.addToGroup((sGroup) ? sGroup : "default");
17033 // We don't want to register this as the handle with the manager
17034 // so we just set the id rather than calling the setter.
17035 this.handleElId = id;
17037 // the linked element is the element that gets dragged by default
17038 this.setDragElId(id);
17040 // by default, clicked anchors will not start drag operations.
17041 this.invalidHandleTypes = { A: "A" };
17042 this.invalidHandleIds = {};
17043 this.invalidHandleClasses = [];
17045 this.applyConfig();
17047 this.handleOnAvailable();
17051 * Applies the configuration parameters that were passed into the constructor.
17052 * This is supposed to happen at each level through the inheritance chain. So
17053 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17054 * DragDrop in order to get all of the parameters that are available in
17056 * @method applyConfig
17058 applyConfig: function() {
17060 // configurable properties:
17061 // padding, isTarget, maintainOffset, primaryButtonOnly
17062 this.padding = this.config.padding || [0, 0, 0, 0];
17063 this.isTarget = (this.config.isTarget !== false);
17064 this.maintainOffset = (this.config.maintainOffset);
17065 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17070 * Executed when the linked element is available
17071 * @method handleOnAvailable
17074 handleOnAvailable: function() {
17075 this.available = true;
17076 this.resetConstraints();
17077 this.onAvailable();
17081 * Configures the padding for the target zone in px. Effectively expands
17082 * (or reduces) the virtual object size for targeting calculations.
17083 * Supports css-style shorthand; if only one parameter is passed, all sides
17084 * will have that padding, and if only two are passed, the top and bottom
17085 * will have the first param, the left and right the second.
17086 * @method setPadding
17087 * @param {int} iTop Top pad
17088 * @param {int} iRight Right pad
17089 * @param {int} iBot Bot pad
17090 * @param {int} iLeft Left pad
17092 setPadding: function(iTop, iRight, iBot, iLeft) {
17093 // this.padding = [iLeft, iRight, iTop, iBot];
17094 if (!iRight && 0 !== iRight) {
17095 this.padding = [iTop, iTop, iTop, iTop];
17096 } else if (!iBot && 0 !== iBot) {
17097 this.padding = [iTop, iRight, iTop, iRight];
17099 this.padding = [iTop, iRight, iBot, iLeft];
17104 * Stores the initial placement of the linked element.
17105 * @method setInitialPosition
17106 * @param {int} diffX the X offset, default 0
17107 * @param {int} diffY the Y offset, default 0
17109 setInitPosition: function(diffX, diffY) {
17110 var el = this.getEl();
17112 if (!this.DDM.verifyEl(el)) {
17116 var dx = diffX || 0;
17117 var dy = diffY || 0;
17119 var p = Dom.getXY( el );
17121 this.initPageX = p[0] - dx;
17122 this.initPageY = p[1] - dy;
17124 this.lastPageX = p[0];
17125 this.lastPageY = p[1];
17128 this.setStartPosition(p);
17132 * Sets the start position of the element. This is set when the obj
17133 * is initialized, the reset when a drag is started.
17134 * @method setStartPosition
17135 * @param pos current position (from previous lookup)
17138 setStartPosition: function(pos) {
17139 var p = pos || Dom.getXY( this.getEl() );
17140 this.deltaSetXY = null;
17142 this.startPageX = p[0];
17143 this.startPageY = p[1];
17147 * Add this instance to a group of related drag/drop objects. All
17148 * instances belong to at least one group, and can belong to as many
17149 * groups as needed.
17150 * @method addToGroup
17151 * @param sGroup {string} the name of the group
17153 addToGroup: function(sGroup) {
17154 this.groups[sGroup] = true;
17155 this.DDM.regDragDrop(this, sGroup);
17159 * Remove's this instance from the supplied interaction group
17160 * @method removeFromGroup
17161 * @param {string} sGroup The group to drop
17163 removeFromGroup: function(sGroup) {
17164 if (this.groups[sGroup]) {
17165 delete this.groups[sGroup];
17168 this.DDM.removeDDFromGroup(this, sGroup);
17172 * Allows you to specify that an element other than the linked element
17173 * will be moved with the cursor during a drag
17174 * @method setDragElId
17175 * @param id {string} the id of the element that will be used to initiate the drag
17177 setDragElId: function(id) {
17178 this.dragElId = id;
17182 * Allows you to specify a child of the linked element that should be
17183 * used to initiate the drag operation. An example of this would be if
17184 * you have a content div with text and links. Clicking anywhere in the
17185 * content area would normally start the drag operation. Use this method
17186 * to specify that an element inside of the content div is the element
17187 * that starts the drag operation.
17188 * @method setHandleElId
17189 * @param id {string} the id of the element that will be used to
17190 * initiate the drag.
17192 setHandleElId: function(id) {
17193 if (typeof id !== "string") {
17196 this.handleElId = id;
17197 this.DDM.regHandle(this.id, id);
17201 * Allows you to set an element outside of the linked element as a drag
17203 * @method setOuterHandleElId
17204 * @param id the id of the element that will be used to initiate the drag
17206 setOuterHandleElId: function(id) {
17207 if (typeof id !== "string") {
17210 Event.on(id, "mousedown",
17211 this.handleMouseDown, this);
17212 this.setHandleElId(id);
17214 this.hasOuterHandles = true;
17218 * Remove all drag and drop hooks for this element
17221 unreg: function() {
17222 Event.un(this.id, "mousedown",
17223 this.handleMouseDown);
17224 Event.un(this.id, "touchstart",
17225 this.handleMouseDown);
17226 this._domRef = null;
17227 this.DDM._remove(this);
17230 destroy : function(){
17235 * Returns true if this instance is locked, or the drag drop mgr is locked
17236 * (meaning that all drag/drop is disabled on the page.)
17238 * @return {boolean} true if this obj or all drag/drop is locked, else
17241 isLocked: function() {
17242 return (this.DDM.isLocked() || this.locked);
17246 * Fired when this object is clicked
17247 * @method handleMouseDown
17249 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17252 handleMouseDown: function(e, oDD){
17254 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17255 //Roo.log('not touch/ button !=0');
17258 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17259 return; // double touch..
17263 if (this.isLocked()) {
17264 //Roo.log('locked');
17268 this.DDM.refreshCache(this.groups);
17269 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17270 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17271 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17272 //Roo.log('no outer handes or not over target');
17275 // Roo.log('check validator');
17276 if (this.clickValidator(e)) {
17277 // Roo.log('validate success');
17278 // set the initial element position
17279 this.setStartPosition();
17282 this.b4MouseDown(e);
17283 this.onMouseDown(e);
17285 this.DDM.handleMouseDown(e, this);
17287 this.DDM.stopEvent(e);
17295 clickValidator: function(e) {
17296 var target = e.getTarget();
17297 return ( this.isValidHandleChild(target) &&
17298 (this.id == this.handleElId ||
17299 this.DDM.handleWasClicked(target, this.id)) );
17303 * Allows you to specify a tag name that should not start a drag operation
17304 * when clicked. This is designed to facilitate embedding links within a
17305 * drag handle that do something other than start the drag.
17306 * @method addInvalidHandleType
17307 * @param {string} tagName the type of element to exclude
17309 addInvalidHandleType: function(tagName) {
17310 var type = tagName.toUpperCase();
17311 this.invalidHandleTypes[type] = type;
17315 * Lets you to specify an element id for a child of a drag handle
17316 * that should not initiate a drag
17317 * @method addInvalidHandleId
17318 * @param {string} id the element id of the element you wish to ignore
17320 addInvalidHandleId: function(id) {
17321 if (typeof id !== "string") {
17324 this.invalidHandleIds[id] = id;
17328 * Lets you specify a css class of elements that will not initiate a drag
17329 * @method addInvalidHandleClass
17330 * @param {string} cssClass the class of the elements you wish to ignore
17332 addInvalidHandleClass: function(cssClass) {
17333 this.invalidHandleClasses.push(cssClass);
17337 * Unsets an excluded tag name set by addInvalidHandleType
17338 * @method removeInvalidHandleType
17339 * @param {string} tagName the type of element to unexclude
17341 removeInvalidHandleType: function(tagName) {
17342 var type = tagName.toUpperCase();
17343 // this.invalidHandleTypes[type] = null;
17344 delete this.invalidHandleTypes[type];
17348 * Unsets an invalid handle id
17349 * @method removeInvalidHandleId
17350 * @param {string} id the id of the element to re-enable
17352 removeInvalidHandleId: function(id) {
17353 if (typeof id !== "string") {
17356 delete this.invalidHandleIds[id];
17360 * Unsets an invalid css class
17361 * @method removeInvalidHandleClass
17362 * @param {string} cssClass the class of the element(s) you wish to
17365 removeInvalidHandleClass: function(cssClass) {
17366 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17367 if (this.invalidHandleClasses[i] == cssClass) {
17368 delete this.invalidHandleClasses[i];
17374 * Checks the tag exclusion list to see if this click should be ignored
17375 * @method isValidHandleChild
17376 * @param {HTMLElement} node the HTMLElement to evaluate
17377 * @return {boolean} true if this is a valid tag type, false if not
17379 isValidHandleChild: function(node) {
17382 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17385 nodeName = node.nodeName.toUpperCase();
17387 nodeName = node.nodeName;
17389 valid = valid && !this.invalidHandleTypes[nodeName];
17390 valid = valid && !this.invalidHandleIds[node.id];
17392 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17393 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17402 * Create the array of horizontal tick marks if an interval was specified
17403 * in setXConstraint().
17404 * @method setXTicks
17407 setXTicks: function(iStartX, iTickSize) {
17409 this.xTickSize = iTickSize;
17413 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17415 this.xTicks[this.xTicks.length] = i;
17420 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17422 this.xTicks[this.xTicks.length] = i;
17427 this.xTicks.sort(this.DDM.numericSort) ;
17431 * Create the array of vertical tick marks if an interval was specified in
17432 * setYConstraint().
17433 * @method setYTicks
17436 setYTicks: function(iStartY, iTickSize) {
17438 this.yTickSize = iTickSize;
17442 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17444 this.yTicks[this.yTicks.length] = i;
17449 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17451 this.yTicks[this.yTicks.length] = i;
17456 this.yTicks.sort(this.DDM.numericSort) ;
17460 * By default, the element can be dragged any place on the screen. Use
17461 * this method to limit the horizontal travel of the element. Pass in
17462 * 0,0 for the parameters if you want to lock the drag to the y axis.
17463 * @method setXConstraint
17464 * @param {int} iLeft the number of pixels the element can move to the left
17465 * @param {int} iRight the number of pixels the element can move to the
17467 * @param {int} iTickSize optional parameter for specifying that the
17469 * should move iTickSize pixels at a time.
17471 setXConstraint: function(iLeft, iRight, iTickSize) {
17472 this.leftConstraint = iLeft;
17473 this.rightConstraint = iRight;
17475 this.minX = this.initPageX - iLeft;
17476 this.maxX = this.initPageX + iRight;
17477 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17479 this.constrainX = true;
17483 * Clears any constraints applied to this instance. Also clears ticks
17484 * since they can't exist independent of a constraint at this time.
17485 * @method clearConstraints
17487 clearConstraints: function() {
17488 this.constrainX = false;
17489 this.constrainY = false;
17494 * Clears any tick interval defined for this instance
17495 * @method clearTicks
17497 clearTicks: function() {
17498 this.xTicks = null;
17499 this.yTicks = null;
17500 this.xTickSize = 0;
17501 this.yTickSize = 0;
17505 * By default, the element can be dragged any place on the screen. Set
17506 * this to limit the vertical travel of the element. Pass in 0,0 for the
17507 * parameters if you want to lock the drag to the x axis.
17508 * @method setYConstraint
17509 * @param {int} iUp the number of pixels the element can move up
17510 * @param {int} iDown the number of pixels the element can move down
17511 * @param {int} iTickSize optional parameter for specifying that the
17512 * element should move iTickSize pixels at a time.
17514 setYConstraint: function(iUp, iDown, iTickSize) {
17515 this.topConstraint = iUp;
17516 this.bottomConstraint = iDown;
17518 this.minY = this.initPageY - iUp;
17519 this.maxY = this.initPageY + iDown;
17520 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17522 this.constrainY = true;
17527 * resetConstraints must be called if you manually reposition a dd element.
17528 * @method resetConstraints
17529 * @param {boolean} maintainOffset
17531 resetConstraints: function() {
17534 // Maintain offsets if necessary
17535 if (this.initPageX || this.initPageX === 0) {
17536 // figure out how much this thing has moved
17537 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17538 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17540 this.setInitPosition(dx, dy);
17542 // This is the first time we have detected the element's position
17544 this.setInitPosition();
17547 if (this.constrainX) {
17548 this.setXConstraint( this.leftConstraint,
17549 this.rightConstraint,
17553 if (this.constrainY) {
17554 this.setYConstraint( this.topConstraint,
17555 this.bottomConstraint,
17561 * Normally the drag element is moved pixel by pixel, but we can specify
17562 * that it move a number of pixels at a time. This method resolves the
17563 * location when we have it set up like this.
17565 * @param {int} val where we want to place the object
17566 * @param {int[]} tickArray sorted array of valid points
17567 * @return {int} the closest tick
17570 getTick: function(val, tickArray) {
17573 // If tick interval is not defined, it is effectively 1 pixel,
17574 // so we return the value passed to us.
17576 } else if (tickArray[0] >= val) {
17577 // The value is lower than the first tick, so we return the first
17579 return tickArray[0];
17581 for (var i=0, len=tickArray.length; i<len; ++i) {
17583 if (tickArray[next] && tickArray[next] >= val) {
17584 var diff1 = val - tickArray[i];
17585 var diff2 = tickArray[next] - val;
17586 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17590 // The value is larger than the last tick, so we return the last
17592 return tickArray[tickArray.length - 1];
17599 * @return {string} string representation of the dd obj
17601 toString: function() {
17602 return ("DragDrop " + this.id);
17610 * Ext JS Library 1.1.1
17611 * Copyright(c) 2006-2007, Ext JS, LLC.
17613 * Originally Released Under LGPL - original licence link has changed is not relivant.
17616 * <script type="text/javascript">
17621 * The drag and drop utility provides a framework for building drag and drop
17622 * applications. In addition to enabling drag and drop for specific elements,
17623 * the drag and drop elements are tracked by the manager class, and the
17624 * interactions between the various elements are tracked during the drag and
17625 * the implementing code is notified about these important moments.
17628 // Only load the library once. Rewriting the manager class would orphan
17629 // existing drag and drop instances.
17630 if (!Roo.dd.DragDropMgr) {
17633 * @class Roo.dd.DragDropMgr
17634 * DragDropMgr is a singleton that tracks the element interaction for
17635 * all DragDrop items in the window. Generally, you will not call
17636 * this class directly, but it does have helper methods that could
17637 * be useful in your DragDrop implementations.
17640 Roo.dd.DragDropMgr = function() {
17642 var Event = Roo.EventManager;
17647 * Two dimensional Array of registered DragDrop objects. The first
17648 * dimension is the DragDrop item group, the second the DragDrop
17651 * @type {string: string}
17658 * Array of element ids defined as drag handles. Used to determine
17659 * if the element that generated the mousedown event is actually the
17660 * handle and not the html element itself.
17661 * @property handleIds
17662 * @type {string: string}
17669 * the DragDrop object that is currently being dragged
17670 * @property dragCurrent
17678 * the DragDrop object(s) that are being hovered over
17679 * @property dragOvers
17687 * the X distance between the cursor and the object being dragged
17696 * the Y distance between the cursor and the object being dragged
17705 * Flag to determine if we should prevent the default behavior of the
17706 * events we define. By default this is true, but this can be set to
17707 * false if you need the default behavior (not recommended)
17708 * @property preventDefault
17712 preventDefault: true,
17715 * Flag to determine if we should stop the propagation of the events
17716 * we generate. This is true by default but you may want to set it to
17717 * false if the html element contains other features that require the
17719 * @property stopPropagation
17723 stopPropagation: true,
17726 * Internal flag that is set to true when drag and drop has been
17728 * @property initialized
17735 * All drag and drop can be disabled.
17743 * Called the first time an element is registered.
17749 this.initialized = true;
17753 * In point mode, drag and drop interaction is defined by the
17754 * location of the cursor during the drag/drop
17762 * In intersect mode, drag and drop interactio nis defined by the
17763 * overlap of two or more drag and drop objects.
17764 * @property INTERSECT
17771 * The current drag and drop mode. Default: POINT
17779 * Runs method on all drag and drop objects
17780 * @method _execOnAll
17784 _execOnAll: function(sMethod, args) {
17785 for (var i in this.ids) {
17786 for (var j in this.ids[i]) {
17787 var oDD = this.ids[i][j];
17788 if (! this.isTypeOfDD(oDD)) {
17791 oDD[sMethod].apply(oDD, args);
17797 * Drag and drop initialization. Sets up the global event handlers
17802 _onLoad: function() {
17806 if (!Roo.isTouch) {
17807 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17808 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17810 Event.on(document, "touchend", this.handleMouseUp, this, true);
17811 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17813 Event.on(window, "unload", this._onUnload, this, true);
17814 Event.on(window, "resize", this._onResize, this, true);
17815 // Event.on(window, "mouseout", this._test);
17820 * Reset constraints on all drag and drop objs
17821 * @method _onResize
17825 _onResize: function(e) {
17826 this._execOnAll("resetConstraints", []);
17830 * Lock all drag and drop functionality
17834 lock: function() { this.locked = true; },
17837 * Unlock all drag and drop functionality
17841 unlock: function() { this.locked = false; },
17844 * Is drag and drop locked?
17846 * @return {boolean} True if drag and drop is locked, false otherwise.
17849 isLocked: function() { return this.locked; },
17852 * Location cache that is set for all drag drop objects when a drag is
17853 * initiated, cleared when the drag is finished.
17854 * @property locationCache
17861 * Set useCache to false if you want to force object the lookup of each
17862 * drag and drop linked element constantly during a drag.
17863 * @property useCache
17870 * The number of pixels that the mouse needs to move after the
17871 * mousedown before the drag is initiated. Default=3;
17872 * @property clickPixelThresh
17876 clickPixelThresh: 3,
17879 * The number of milliseconds after the mousedown event to initiate the
17880 * drag if we don't get a mouseup event. Default=1000
17881 * @property clickTimeThresh
17885 clickTimeThresh: 350,
17888 * Flag that indicates that either the drag pixel threshold or the
17889 * mousdown time threshold has been met
17890 * @property dragThreshMet
17895 dragThreshMet: false,
17898 * Timeout used for the click time threshold
17899 * @property clickTimeout
17904 clickTimeout: null,
17907 * The X position of the mousedown event stored for later use when a
17908 * drag threshold is met.
17917 * The Y position of the mousedown event stored for later use when a
17918 * drag threshold is met.
17927 * Each DragDrop instance must be registered with the DragDropMgr.
17928 * This is executed in DragDrop.init()
17929 * @method regDragDrop
17930 * @param {DragDrop} oDD the DragDrop object to register
17931 * @param {String} sGroup the name of the group this element belongs to
17934 regDragDrop: function(oDD, sGroup) {
17935 if (!this.initialized) { this.init(); }
17937 if (!this.ids[sGroup]) {
17938 this.ids[sGroup] = {};
17940 this.ids[sGroup][oDD.id] = oDD;
17944 * Removes the supplied dd instance from the supplied group. Executed
17945 * by DragDrop.removeFromGroup, so don't call this function directly.
17946 * @method removeDDFromGroup
17950 removeDDFromGroup: function(oDD, sGroup) {
17951 if (!this.ids[sGroup]) {
17952 this.ids[sGroup] = {};
17955 var obj = this.ids[sGroup];
17956 if (obj && obj[oDD.id]) {
17957 delete obj[oDD.id];
17962 * Unregisters a drag and drop item. This is executed in
17963 * DragDrop.unreg, use that method instead of calling this directly.
17968 _remove: function(oDD) {
17969 for (var g in oDD.groups) {
17970 if (g && this.ids[g][oDD.id]) {
17971 delete this.ids[g][oDD.id];
17974 delete this.handleIds[oDD.id];
17978 * Each DragDrop handle element must be registered. This is done
17979 * automatically when executing DragDrop.setHandleElId()
17980 * @method regHandle
17981 * @param {String} sDDId the DragDrop id this element is a handle for
17982 * @param {String} sHandleId the id of the element that is the drag
17986 regHandle: function(sDDId, sHandleId) {
17987 if (!this.handleIds[sDDId]) {
17988 this.handleIds[sDDId] = {};
17990 this.handleIds[sDDId][sHandleId] = sHandleId;
17994 * Utility function to determine if a given element has been
17995 * registered as a drag drop item.
17996 * @method isDragDrop
17997 * @param {String} id the element id to check
17998 * @return {boolean} true if this element is a DragDrop item,
18002 isDragDrop: function(id) {
18003 return ( this.getDDById(id) ) ? true : false;
18007 * Returns the drag and drop instances that are in all groups the
18008 * passed in instance belongs to.
18009 * @method getRelated
18010 * @param {DragDrop} p_oDD the obj to get related data for
18011 * @param {boolean} bTargetsOnly if true, only return targetable objs
18012 * @return {DragDrop[]} the related instances
18015 getRelated: function(p_oDD, bTargetsOnly) {
18017 for (var i in p_oDD.groups) {
18018 for (j in this.ids[i]) {
18019 var dd = this.ids[i][j];
18020 if (! this.isTypeOfDD(dd)) {
18023 if (!bTargetsOnly || dd.isTarget) {
18024 oDDs[oDDs.length] = dd;
18033 * Returns true if the specified dd target is a legal target for
18034 * the specifice drag obj
18035 * @method isLegalTarget
18036 * @param {DragDrop} the drag obj
18037 * @param {DragDrop} the target
18038 * @return {boolean} true if the target is a legal target for the
18042 isLegalTarget: function (oDD, oTargetDD) {
18043 var targets = this.getRelated(oDD, true);
18044 for (var i=0, len=targets.length;i<len;++i) {
18045 if (targets[i].id == oTargetDD.id) {
18054 * My goal is to be able to transparently determine if an object is
18055 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18056 * returns "object", oDD.constructor.toString() always returns
18057 * "DragDrop" and not the name of the subclass. So for now it just
18058 * evaluates a well-known variable in DragDrop.
18059 * @method isTypeOfDD
18060 * @param {Object} the object to evaluate
18061 * @return {boolean} true if typeof oDD = DragDrop
18064 isTypeOfDD: function (oDD) {
18065 return (oDD && oDD.__ygDragDrop);
18069 * Utility function to determine if a given element has been
18070 * registered as a drag drop handle for the given Drag Drop object.
18072 * @param {String} id the element id to check
18073 * @return {boolean} true if this element is a DragDrop handle, false
18077 isHandle: function(sDDId, sHandleId) {
18078 return ( this.handleIds[sDDId] &&
18079 this.handleIds[sDDId][sHandleId] );
18083 * Returns the DragDrop instance for a given id
18084 * @method getDDById
18085 * @param {String} id the id of the DragDrop object
18086 * @return {DragDrop} the drag drop object, null if it is not found
18089 getDDById: function(id) {
18090 for (var i in this.ids) {
18091 if (this.ids[i][id]) {
18092 return this.ids[i][id];
18099 * Fired after a registered DragDrop object gets the mousedown event.
18100 * Sets up the events required to track the object being dragged
18101 * @method handleMouseDown
18102 * @param {Event} e the event
18103 * @param oDD the DragDrop object being dragged
18107 handleMouseDown: function(e, oDD) {
18109 Roo.QuickTips.disable();
18111 this.currentTarget = e.getTarget();
18113 this.dragCurrent = oDD;
18115 var el = oDD.getEl();
18117 // track start position
18118 this.startX = e.getPageX();
18119 this.startY = e.getPageY();
18121 this.deltaX = this.startX - el.offsetLeft;
18122 this.deltaY = this.startY - el.offsetTop;
18124 this.dragThreshMet = false;
18126 this.clickTimeout = setTimeout(
18128 var DDM = Roo.dd.DDM;
18129 DDM.startDrag(DDM.startX, DDM.startY);
18131 this.clickTimeThresh );
18135 * Fired when either the drag pixel threshol or the mousedown hold
18136 * time threshold has been met.
18137 * @method startDrag
18138 * @param x {int} the X position of the original mousedown
18139 * @param y {int} the Y position of the original mousedown
18142 startDrag: function(x, y) {
18143 clearTimeout(this.clickTimeout);
18144 if (this.dragCurrent) {
18145 this.dragCurrent.b4StartDrag(x, y);
18146 this.dragCurrent.startDrag(x, y);
18148 this.dragThreshMet = true;
18152 * Internal function to handle the mouseup event. Will be invoked
18153 * from the context of the document.
18154 * @method handleMouseUp
18155 * @param {Event} e the event
18159 handleMouseUp: function(e) {
18162 Roo.QuickTips.enable();
18164 if (! this.dragCurrent) {
18168 clearTimeout(this.clickTimeout);
18170 if (this.dragThreshMet) {
18171 this.fireEvents(e, true);
18181 * Utility to stop event propagation and event default, if these
18182 * features are turned on.
18183 * @method stopEvent
18184 * @param {Event} e the event as returned by this.getEvent()
18187 stopEvent: function(e){
18188 if(this.stopPropagation) {
18189 e.stopPropagation();
18192 if (this.preventDefault) {
18193 e.preventDefault();
18198 * Internal function to clean up event handlers after the drag
18199 * operation is complete
18201 * @param {Event} e the event
18205 stopDrag: function(e) {
18206 // Fire the drag end event for the item that was dragged
18207 if (this.dragCurrent) {
18208 if (this.dragThreshMet) {
18209 this.dragCurrent.b4EndDrag(e);
18210 this.dragCurrent.endDrag(e);
18213 this.dragCurrent.onMouseUp(e);
18216 this.dragCurrent = null;
18217 this.dragOvers = {};
18221 * Internal function to handle the mousemove event. Will be invoked
18222 * from the context of the html element.
18224 * @TODO figure out what we can do about mouse events lost when the
18225 * user drags objects beyond the window boundary. Currently we can
18226 * detect this in internet explorer by verifying that the mouse is
18227 * down during the mousemove event. Firefox doesn't give us the
18228 * button state on the mousemove event.
18229 * @method handleMouseMove
18230 * @param {Event} e the event
18234 handleMouseMove: function(e) {
18235 if (! this.dragCurrent) {
18239 // var button = e.which || e.button;
18241 // check for IE mouseup outside of page boundary
18242 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18244 return this.handleMouseUp(e);
18247 if (!this.dragThreshMet) {
18248 var diffX = Math.abs(this.startX - e.getPageX());
18249 var diffY = Math.abs(this.startY - e.getPageY());
18250 if (diffX > this.clickPixelThresh ||
18251 diffY > this.clickPixelThresh) {
18252 this.startDrag(this.startX, this.startY);
18256 if (this.dragThreshMet) {
18257 this.dragCurrent.b4Drag(e);
18258 this.dragCurrent.onDrag(e);
18259 if(!this.dragCurrent.moveOnly){
18260 this.fireEvents(e, false);
18270 * Iterates over all of the DragDrop elements to find ones we are
18271 * hovering over or dropping on
18272 * @method fireEvents
18273 * @param {Event} e the event
18274 * @param {boolean} isDrop is this a drop op or a mouseover op?
18278 fireEvents: function(e, isDrop) {
18279 var dc = this.dragCurrent;
18281 // If the user did the mouse up outside of the window, we could
18282 // get here even though we have ended the drag.
18283 if (!dc || dc.isLocked()) {
18287 var pt = e.getPoint();
18289 // cache the previous dragOver array
18295 var enterEvts = [];
18297 // Check to see if the object(s) we were hovering over is no longer
18298 // being hovered over so we can fire the onDragOut event
18299 for (var i in this.dragOvers) {
18301 var ddo = this.dragOvers[i];
18303 if (! this.isTypeOfDD(ddo)) {
18307 if (! this.isOverTarget(pt, ddo, this.mode)) {
18308 outEvts.push( ddo );
18311 oldOvers[i] = true;
18312 delete this.dragOvers[i];
18315 for (var sGroup in dc.groups) {
18317 if ("string" != typeof sGroup) {
18321 for (i in this.ids[sGroup]) {
18322 var oDD = this.ids[sGroup][i];
18323 if (! this.isTypeOfDD(oDD)) {
18327 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18328 if (this.isOverTarget(pt, oDD, this.mode)) {
18329 // look for drop interactions
18331 dropEvts.push( oDD );
18332 // look for drag enter and drag over interactions
18335 // initial drag over: dragEnter fires
18336 if (!oldOvers[oDD.id]) {
18337 enterEvts.push( oDD );
18338 // subsequent drag overs: dragOver fires
18340 overEvts.push( oDD );
18343 this.dragOvers[oDD.id] = oDD;
18351 if (outEvts.length) {
18352 dc.b4DragOut(e, outEvts);
18353 dc.onDragOut(e, outEvts);
18356 if (enterEvts.length) {
18357 dc.onDragEnter(e, enterEvts);
18360 if (overEvts.length) {
18361 dc.b4DragOver(e, overEvts);
18362 dc.onDragOver(e, overEvts);
18365 if (dropEvts.length) {
18366 dc.b4DragDrop(e, dropEvts);
18367 dc.onDragDrop(e, dropEvts);
18371 // fire dragout events
18373 for (i=0, len=outEvts.length; i<len; ++i) {
18374 dc.b4DragOut(e, outEvts[i].id);
18375 dc.onDragOut(e, outEvts[i].id);
18378 // fire enter events
18379 for (i=0,len=enterEvts.length; i<len; ++i) {
18380 // dc.b4DragEnter(e, oDD.id);
18381 dc.onDragEnter(e, enterEvts[i].id);
18384 // fire over events
18385 for (i=0,len=overEvts.length; i<len; ++i) {
18386 dc.b4DragOver(e, overEvts[i].id);
18387 dc.onDragOver(e, overEvts[i].id);
18390 // fire drop events
18391 for (i=0, len=dropEvts.length; i<len; ++i) {
18392 dc.b4DragDrop(e, dropEvts[i].id);
18393 dc.onDragDrop(e, dropEvts[i].id);
18398 // notify about a drop that did not find a target
18399 if (isDrop && !dropEvts.length) {
18400 dc.onInvalidDrop(e);
18406 * Helper function for getting the best match from the list of drag
18407 * and drop objects returned by the drag and drop events when we are
18408 * in INTERSECT mode. It returns either the first object that the
18409 * cursor is over, or the object that has the greatest overlap with
18410 * the dragged element.
18411 * @method getBestMatch
18412 * @param {DragDrop[]} dds The array of drag and drop objects
18414 * @return {DragDrop} The best single match
18417 getBestMatch: function(dds) {
18419 // Return null if the input is not what we expect
18420 //if (!dds || !dds.length || dds.length == 0) {
18422 // If there is only one item, it wins
18423 //} else if (dds.length == 1) {
18425 var len = dds.length;
18430 // Loop through the targeted items
18431 for (var i=0; i<len; ++i) {
18433 // If the cursor is over the object, it wins. If the
18434 // cursor is over multiple matches, the first one we come
18436 if (dd.cursorIsOver) {
18439 // Otherwise the object with the most overlap wins
18442 winner.overlap.getArea() < dd.overlap.getArea()) {
18453 * Refreshes the cache of the top-left and bottom-right points of the
18454 * drag and drop objects in the specified group(s). This is in the
18455 * format that is stored in the drag and drop instance, so typical
18458 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18462 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18464 * @TODO this really should be an indexed array. Alternatively this
18465 * method could accept both.
18466 * @method refreshCache
18467 * @param {Object} groups an associative array of groups to refresh
18470 refreshCache: function(groups) {
18471 for (var sGroup in groups) {
18472 if ("string" != typeof sGroup) {
18475 for (var i in this.ids[sGroup]) {
18476 var oDD = this.ids[sGroup][i];
18478 if (this.isTypeOfDD(oDD)) {
18479 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18480 var loc = this.getLocation(oDD);
18482 this.locationCache[oDD.id] = loc;
18484 delete this.locationCache[oDD.id];
18485 // this will unregister the drag and drop object if
18486 // the element is not in a usable state
18495 * This checks to make sure an element exists and is in the DOM. The
18496 * main purpose is to handle cases where innerHTML is used to remove
18497 * drag and drop objects from the DOM. IE provides an 'unspecified
18498 * error' when trying to access the offsetParent of such an element
18500 * @param {HTMLElement} el the element to check
18501 * @return {boolean} true if the element looks usable
18504 verifyEl: function(el) {
18509 parent = el.offsetParent;
18512 parent = el.offsetParent;
18523 * Returns a Region object containing the drag and drop element's position
18524 * and size, including the padding configured for it
18525 * @method getLocation
18526 * @param {DragDrop} oDD the drag and drop object to get the
18528 * @return {Roo.lib.Region} a Region object representing the total area
18529 * the element occupies, including any padding
18530 * the instance is configured for.
18533 getLocation: function(oDD) {
18534 if (! this.isTypeOfDD(oDD)) {
18538 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18541 pos= Roo.lib.Dom.getXY(el);
18549 x2 = x1 + el.offsetWidth;
18551 y2 = y1 + el.offsetHeight;
18553 t = y1 - oDD.padding[0];
18554 r = x2 + oDD.padding[1];
18555 b = y2 + oDD.padding[2];
18556 l = x1 - oDD.padding[3];
18558 return new Roo.lib.Region( t, r, b, l );
18562 * Checks the cursor location to see if it over the target
18563 * @method isOverTarget
18564 * @param {Roo.lib.Point} pt The point to evaluate
18565 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18566 * @return {boolean} true if the mouse is over the target
18570 isOverTarget: function(pt, oTarget, intersect) {
18571 // use cache if available
18572 var loc = this.locationCache[oTarget.id];
18573 if (!loc || !this.useCache) {
18574 loc = this.getLocation(oTarget);
18575 this.locationCache[oTarget.id] = loc;
18583 oTarget.cursorIsOver = loc.contains( pt );
18585 // DragDrop is using this as a sanity check for the initial mousedown
18586 // in this case we are done. In POINT mode, if the drag obj has no
18587 // contraints, we are also done. Otherwise we need to evaluate the
18588 // location of the target as related to the actual location of the
18589 // dragged element.
18590 var dc = this.dragCurrent;
18591 if (!dc || !dc.getTargetCoord ||
18592 (!intersect && !dc.constrainX && !dc.constrainY)) {
18593 return oTarget.cursorIsOver;
18596 oTarget.overlap = null;
18598 // Get the current location of the drag element, this is the
18599 // location of the mouse event less the delta that represents
18600 // where the original mousedown happened on the element. We
18601 // need to consider constraints and ticks as well.
18602 var pos = dc.getTargetCoord(pt.x, pt.y);
18604 var el = dc.getDragEl();
18605 var curRegion = new Roo.lib.Region( pos.y,
18606 pos.x + el.offsetWidth,
18607 pos.y + el.offsetHeight,
18610 var overlap = curRegion.intersect(loc);
18613 oTarget.overlap = overlap;
18614 return (intersect) ? true : oTarget.cursorIsOver;
18621 * unload event handler
18622 * @method _onUnload
18626 _onUnload: function(e, me) {
18627 Roo.dd.DragDropMgr.unregAll();
18631 * Cleans up the drag and drop events and objects.
18636 unregAll: function() {
18638 if (this.dragCurrent) {
18640 this.dragCurrent = null;
18643 this._execOnAll("unreg", []);
18645 for (i in this.elementCache) {
18646 delete this.elementCache[i];
18649 this.elementCache = {};
18654 * A cache of DOM elements
18655 * @property elementCache
18662 * Get the wrapper for the DOM element specified
18663 * @method getElWrapper
18664 * @param {String} id the id of the element to get
18665 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18667 * @deprecated This wrapper isn't that useful
18670 getElWrapper: function(id) {
18671 var oWrapper = this.elementCache[id];
18672 if (!oWrapper || !oWrapper.el) {
18673 oWrapper = this.elementCache[id] =
18674 new this.ElementWrapper(Roo.getDom(id));
18680 * Returns the actual DOM element
18681 * @method getElement
18682 * @param {String} id the id of the elment to get
18683 * @return {Object} The element
18684 * @deprecated use Roo.getDom instead
18687 getElement: function(id) {
18688 return Roo.getDom(id);
18692 * Returns the style property for the DOM element (i.e.,
18693 * document.getElById(id).style)
18695 * @param {String} id the id of the elment to get
18696 * @return {Object} The style property of the element
18697 * @deprecated use Roo.getDom instead
18700 getCss: function(id) {
18701 var el = Roo.getDom(id);
18702 return (el) ? el.style : null;
18706 * Inner class for cached elements
18707 * @class DragDropMgr.ElementWrapper
18712 ElementWrapper: function(el) {
18717 this.el = el || null;
18722 this.id = this.el && el.id;
18724 * A reference to the style property
18727 this.css = this.el && el.style;
18731 * Returns the X position of an html element
18733 * @param el the element for which to get the position
18734 * @return {int} the X coordinate
18736 * @deprecated use Roo.lib.Dom.getX instead
18739 getPosX: function(el) {
18740 return Roo.lib.Dom.getX(el);
18744 * Returns the Y position of an html element
18746 * @param el the element for which to get the position
18747 * @return {int} the Y coordinate
18748 * @deprecated use Roo.lib.Dom.getY instead
18751 getPosY: function(el) {
18752 return Roo.lib.Dom.getY(el);
18756 * Swap two nodes. In IE, we use the native method, for others we
18757 * emulate the IE behavior
18759 * @param n1 the first node to swap
18760 * @param n2 the other node to swap
18763 swapNode: function(n1, n2) {
18767 var p = n2.parentNode;
18768 var s = n2.nextSibling;
18771 p.insertBefore(n1, n2);
18772 } else if (n2 == n1.nextSibling) {
18773 p.insertBefore(n2, n1);
18775 n1.parentNode.replaceChild(n2, n1);
18776 p.insertBefore(n1, s);
18782 * Returns the current scroll position
18783 * @method getScroll
18787 getScroll: function () {
18788 var t, l, dde=document.documentElement, db=document.body;
18789 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18791 l = dde.scrollLeft;
18798 return { top: t, left: l };
18802 * Returns the specified element style property
18804 * @param {HTMLElement} el the element
18805 * @param {string} styleProp the style property
18806 * @return {string} The value of the style property
18807 * @deprecated use Roo.lib.Dom.getStyle
18810 getStyle: function(el, styleProp) {
18811 return Roo.fly(el).getStyle(styleProp);
18815 * Gets the scrollTop
18816 * @method getScrollTop
18817 * @return {int} the document's scrollTop
18820 getScrollTop: function () { return this.getScroll().top; },
18823 * Gets the scrollLeft
18824 * @method getScrollLeft
18825 * @return {int} the document's scrollTop
18828 getScrollLeft: function () { return this.getScroll().left; },
18831 * Sets the x/y position of an element to the location of the
18834 * @param {HTMLElement} moveEl The element to move
18835 * @param {HTMLElement} targetEl The position reference element
18838 moveToEl: function (moveEl, targetEl) {
18839 var aCoord = Roo.lib.Dom.getXY(targetEl);
18840 Roo.lib.Dom.setXY(moveEl, aCoord);
18844 * Numeric array sort function
18845 * @method numericSort
18848 numericSort: function(a, b) { return (a - b); },
18852 * @property _timeoutCount
18859 * Trying to make the load order less important. Without this we get
18860 * an error if this file is loaded before the Event Utility.
18861 * @method _addListeners
18865 _addListeners: function() {
18866 var DDM = Roo.dd.DDM;
18867 if ( Roo.lib.Event && document ) {
18870 if (DDM._timeoutCount > 2000) {
18872 setTimeout(DDM._addListeners, 10);
18873 if (document && document.body) {
18874 DDM._timeoutCount += 1;
18881 * Recursively searches the immediate parent and all child nodes for
18882 * the handle element in order to determine wheter or not it was
18884 * @method handleWasClicked
18885 * @param node the html element to inspect
18888 handleWasClicked: function(node, id) {
18889 if (this.isHandle(id, node.id)) {
18892 // check to see if this is a text node child of the one we want
18893 var p = node.parentNode;
18896 if (this.isHandle(id, p.id)) {
18911 // shorter alias, save a few bytes
18912 Roo.dd.DDM = Roo.dd.DragDropMgr;
18913 Roo.dd.DDM._addListeners();
18917 * Ext JS Library 1.1.1
18918 * Copyright(c) 2006-2007, Ext JS, LLC.
18920 * Originally Released Under LGPL - original licence link has changed is not relivant.
18923 * <script type="text/javascript">
18928 * A DragDrop implementation where the linked element follows the
18929 * mouse cursor during a drag.
18930 * @extends Roo.dd.DragDrop
18932 * @param {String} id the id of the linked element
18933 * @param {String} sGroup the group of related DragDrop items
18934 * @param {object} config an object containing configurable attributes
18935 * Valid properties for DD:
18938 Roo.dd.DD = function(id, sGroup, config) {
18940 this.init(id, sGroup, config);
18944 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18947 * When set to true, the utility automatically tries to scroll the browser
18948 * window wehn a drag and drop element is dragged near the viewport boundary.
18949 * Defaults to true.
18956 * Sets the pointer offset to the distance between the linked element's top
18957 * left corner and the location the element was clicked
18958 * @method autoOffset
18959 * @param {int} iPageX the X coordinate of the click
18960 * @param {int} iPageY the Y coordinate of the click
18962 autoOffset: function(iPageX, iPageY) {
18963 var x = iPageX - this.startPageX;
18964 var y = iPageY - this.startPageY;
18965 this.setDelta(x, y);
18969 * Sets the pointer offset. You can call this directly to force the
18970 * offset to be in a particular location (e.g., pass in 0,0 to set it
18971 * to the center of the object)
18973 * @param {int} iDeltaX the distance from the left
18974 * @param {int} iDeltaY the distance from the top
18976 setDelta: function(iDeltaX, iDeltaY) {
18977 this.deltaX = iDeltaX;
18978 this.deltaY = iDeltaY;
18982 * Sets the drag element to the location of the mousedown or click event,
18983 * maintaining the cursor location relative to the location on the element
18984 * that was clicked. Override this if you want to place the element in a
18985 * location other than where the cursor is.
18986 * @method setDragElPos
18987 * @param {int} iPageX the X coordinate of the mousedown or drag event
18988 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18990 setDragElPos: function(iPageX, iPageY) {
18991 // the first time we do this, we are going to check to make sure
18992 // the element has css positioning
18994 var el = this.getDragEl();
18995 this.alignElWithMouse(el, iPageX, iPageY);
18999 * Sets the element to the location of the mousedown or click event,
19000 * maintaining the cursor location relative to the location on the element
19001 * that was clicked. Override this if you want to place the element in a
19002 * location other than where the cursor is.
19003 * @method alignElWithMouse
19004 * @param {HTMLElement} el the element to move
19005 * @param {int} iPageX the X coordinate of the mousedown or drag event
19006 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19008 alignElWithMouse: function(el, iPageX, iPageY) {
19009 var oCoord = this.getTargetCoord(iPageX, iPageY);
19010 var fly = el.dom ? el : Roo.fly(el);
19011 if (!this.deltaSetXY) {
19012 var aCoord = [oCoord.x, oCoord.y];
19014 var newLeft = fly.getLeft(true);
19015 var newTop = fly.getTop(true);
19016 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19018 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19021 this.cachePosition(oCoord.x, oCoord.y);
19022 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19027 * Saves the most recent position so that we can reset the constraints and
19028 * tick marks on-demand. We need to know this so that we can calculate the
19029 * number of pixels the element is offset from its original position.
19030 * @method cachePosition
19031 * @param iPageX the current x position (optional, this just makes it so we
19032 * don't have to look it up again)
19033 * @param iPageY the current y position (optional, this just makes it so we
19034 * don't have to look it up again)
19036 cachePosition: function(iPageX, iPageY) {
19038 this.lastPageX = iPageX;
19039 this.lastPageY = iPageY;
19041 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19042 this.lastPageX = aCoord[0];
19043 this.lastPageY = aCoord[1];
19048 * Auto-scroll the window if the dragged object has been moved beyond the
19049 * visible window boundary.
19050 * @method autoScroll
19051 * @param {int} x the drag element's x position
19052 * @param {int} y the drag element's y position
19053 * @param {int} h the height of the drag element
19054 * @param {int} w the width of the drag element
19057 autoScroll: function(x, y, h, w) {
19060 // The client height
19061 var clientH = Roo.lib.Dom.getViewWidth();
19063 // The client width
19064 var clientW = Roo.lib.Dom.getViewHeight();
19066 // The amt scrolled down
19067 var st = this.DDM.getScrollTop();
19069 // The amt scrolled right
19070 var sl = this.DDM.getScrollLeft();
19072 // Location of the bottom of the element
19075 // Location of the right of the element
19078 // The distance from the cursor to the bottom of the visible area,
19079 // adjusted so that we don't scroll if the cursor is beyond the
19080 // element drag constraints
19081 var toBot = (clientH + st - y - this.deltaY);
19083 // The distance from the cursor to the right of the visible area
19084 var toRight = (clientW + sl - x - this.deltaX);
19087 // How close to the edge the cursor must be before we scroll
19088 // var thresh = (document.all) ? 100 : 40;
19091 // How many pixels to scroll per autoscroll op. This helps to reduce
19092 // clunky scrolling. IE is more sensitive about this ... it needs this
19093 // value to be higher.
19094 var scrAmt = (document.all) ? 80 : 30;
19096 // Scroll down if we are near the bottom of the visible page and the
19097 // obj extends below the crease
19098 if ( bot > clientH && toBot < thresh ) {
19099 window.scrollTo(sl, st + scrAmt);
19102 // Scroll up if the window is scrolled down and the top of the object
19103 // goes above the top border
19104 if ( y < st && st > 0 && y - st < thresh ) {
19105 window.scrollTo(sl, st - scrAmt);
19108 // Scroll right if the obj is beyond the right border and the cursor is
19109 // near the border.
19110 if ( right > clientW && toRight < thresh ) {
19111 window.scrollTo(sl + scrAmt, st);
19114 // Scroll left if the window has been scrolled to the right and the obj
19115 // extends past the left border
19116 if ( x < sl && sl > 0 && x - sl < thresh ) {
19117 window.scrollTo(sl - scrAmt, st);
19123 * Finds the location the element should be placed if we want to move
19124 * it to where the mouse location less the click offset would place us.
19125 * @method getTargetCoord
19126 * @param {int} iPageX the X coordinate of the click
19127 * @param {int} iPageY the Y coordinate of the click
19128 * @return an object that contains the coordinates (Object.x and Object.y)
19131 getTargetCoord: function(iPageX, iPageY) {
19134 var x = iPageX - this.deltaX;
19135 var y = iPageY - this.deltaY;
19137 if (this.constrainX) {
19138 if (x < this.minX) { x = this.minX; }
19139 if (x > this.maxX) { x = this.maxX; }
19142 if (this.constrainY) {
19143 if (y < this.minY) { y = this.minY; }
19144 if (y > this.maxY) { y = this.maxY; }
19147 x = this.getTick(x, this.xTicks);
19148 y = this.getTick(y, this.yTicks);
19155 * Sets up config options specific to this class. Overrides
19156 * Roo.dd.DragDrop, but all versions of this method through the
19157 * inheritance chain are called
19159 applyConfig: function() {
19160 Roo.dd.DD.superclass.applyConfig.call(this);
19161 this.scroll = (this.config.scroll !== false);
19165 * Event that fires prior to the onMouseDown event. Overrides
19168 b4MouseDown: function(e) {
19169 // this.resetConstraints();
19170 this.autoOffset(e.getPageX(),
19175 * Event that fires prior to the onDrag event. Overrides
19178 b4Drag: function(e) {
19179 this.setDragElPos(e.getPageX(),
19183 toString: function() {
19184 return ("DD " + this.id);
19187 //////////////////////////////////////////////////////////////////////////
19188 // Debugging ygDragDrop events that can be overridden
19189 //////////////////////////////////////////////////////////////////////////
19191 startDrag: function(x, y) {
19194 onDrag: function(e) {
19197 onDragEnter: function(e, id) {
19200 onDragOver: function(e, id) {
19203 onDragOut: function(e, id) {
19206 onDragDrop: function(e, id) {
19209 endDrag: function(e) {
19216 * Ext JS Library 1.1.1
19217 * Copyright(c) 2006-2007, Ext JS, LLC.
19219 * Originally Released Under LGPL - original licence link has changed is not relivant.
19222 * <script type="text/javascript">
19226 * @class Roo.dd.DDProxy
19227 * A DragDrop implementation that inserts an empty, bordered div into
19228 * the document that follows the cursor during drag operations. At the time of
19229 * the click, the frame div is resized to the dimensions of the linked html
19230 * element, and moved to the exact location of the linked element.
19232 * References to the "frame" element refer to the single proxy element that
19233 * was created to be dragged in place of all DDProxy elements on the
19236 * @extends Roo.dd.DD
19238 * @param {String} id the id of the linked html element
19239 * @param {String} sGroup the group of related DragDrop objects
19240 * @param {object} config an object containing configurable attributes
19241 * Valid properties for DDProxy in addition to those in DragDrop:
19242 * resizeFrame, centerFrame, dragElId
19244 Roo.dd.DDProxy = function(id, sGroup, config) {
19246 this.init(id, sGroup, config);
19252 * The default drag frame div id
19253 * @property Roo.dd.DDProxy.dragElId
19257 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19259 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19262 * By default we resize the drag frame to be the same size as the element
19263 * we want to drag (this is to get the frame effect). We can turn it off
19264 * if we want a different behavior.
19265 * @property resizeFrame
19271 * By default the frame is positioned exactly where the drag element is, so
19272 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19273 * you do not have constraints on the obj is to have the drag frame centered
19274 * around the cursor. Set centerFrame to true for this effect.
19275 * @property centerFrame
19278 centerFrame: false,
19281 * Creates the proxy element if it does not yet exist
19282 * @method createFrame
19284 createFrame: function() {
19286 var body = document.body;
19288 if (!body || !body.firstChild) {
19289 setTimeout( function() { self.createFrame(); }, 50 );
19293 var div = this.getDragEl();
19296 div = document.createElement("div");
19297 div.id = this.dragElId;
19300 s.position = "absolute";
19301 s.visibility = "hidden";
19303 s.border = "2px solid #aaa";
19306 // appendChild can blow up IE if invoked prior to the window load event
19307 // while rendering a table. It is possible there are other scenarios
19308 // that would cause this to happen as well.
19309 body.insertBefore(div, body.firstChild);
19314 * Initialization for the drag frame element. Must be called in the
19315 * constructor of all subclasses
19316 * @method initFrame
19318 initFrame: function() {
19319 this.createFrame();
19322 applyConfig: function() {
19323 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19325 this.resizeFrame = (this.config.resizeFrame !== false);
19326 this.centerFrame = (this.config.centerFrame);
19327 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19331 * Resizes the drag frame to the dimensions of the clicked object, positions
19332 * it over the object, and finally displays it
19333 * @method showFrame
19334 * @param {int} iPageX X click position
19335 * @param {int} iPageY Y click position
19338 showFrame: function(iPageX, iPageY) {
19339 var el = this.getEl();
19340 var dragEl = this.getDragEl();
19341 var s = dragEl.style;
19343 this._resizeProxy();
19345 if (this.centerFrame) {
19346 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19347 Math.round(parseInt(s.height, 10)/2) );
19350 this.setDragElPos(iPageX, iPageY);
19352 Roo.fly(dragEl).show();
19356 * The proxy is automatically resized to the dimensions of the linked
19357 * element when a drag is initiated, unless resizeFrame is set to false
19358 * @method _resizeProxy
19361 _resizeProxy: function() {
19362 if (this.resizeFrame) {
19363 var el = this.getEl();
19364 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19368 // overrides Roo.dd.DragDrop
19369 b4MouseDown: function(e) {
19370 var x = e.getPageX();
19371 var y = e.getPageY();
19372 this.autoOffset(x, y);
19373 this.setDragElPos(x, y);
19376 // overrides Roo.dd.DragDrop
19377 b4StartDrag: function(x, y) {
19378 // show the drag frame
19379 this.showFrame(x, y);
19382 // overrides Roo.dd.DragDrop
19383 b4EndDrag: function(e) {
19384 Roo.fly(this.getDragEl()).hide();
19387 // overrides Roo.dd.DragDrop
19388 // By default we try to move the element to the last location of the frame.
19389 // This is so that the default behavior mirrors that of Roo.dd.DD.
19390 endDrag: function(e) {
19392 var lel = this.getEl();
19393 var del = this.getDragEl();
19395 // Show the drag frame briefly so we can get its position
19396 del.style.visibility = "";
19399 // Hide the linked element before the move to get around a Safari
19401 lel.style.visibility = "hidden";
19402 Roo.dd.DDM.moveToEl(lel, del);
19403 del.style.visibility = "hidden";
19404 lel.style.visibility = "";
19409 beforeMove : function(){
19413 afterDrag : function(){
19417 toString: function() {
19418 return ("DDProxy " + this.id);
19424 * Ext JS Library 1.1.1
19425 * Copyright(c) 2006-2007, Ext JS, LLC.
19427 * Originally Released Under LGPL - original licence link has changed is not relivant.
19430 * <script type="text/javascript">
19434 * @class Roo.dd.DDTarget
19435 * A DragDrop implementation that does not move, but can be a drop
19436 * target. You would get the same result by simply omitting implementation
19437 * for the event callbacks, but this way we reduce the processing cost of the
19438 * event listener and the callbacks.
19439 * @extends Roo.dd.DragDrop
19441 * @param {String} id the id of the element that is a drop target
19442 * @param {String} sGroup the group of related DragDrop objects
19443 * @param {object} config an object containing configurable attributes
19444 * Valid properties for DDTarget in addition to those in
19448 Roo.dd.DDTarget = function(id, sGroup, config) {
19450 this.initTarget(id, sGroup, config);
19452 if (config.listeners || config.events) {
19453 Roo.dd.DragDrop.superclass.constructor.call(this, {
19454 listeners : config.listeners || {},
19455 events : config.events || {}
19460 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19461 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19462 toString: function() {
19463 return ("DDTarget " + this.id);
19468 * Ext JS Library 1.1.1
19469 * Copyright(c) 2006-2007, Ext JS, LLC.
19471 * Originally Released Under LGPL - original licence link has changed is not relivant.
19474 * <script type="text/javascript">
19479 * @class Roo.dd.ScrollManager
19480 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19481 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19484 Roo.dd.ScrollManager = function(){
19485 var ddm = Roo.dd.DragDropMgr;
19492 var onStop = function(e){
19497 var triggerRefresh = function(){
19498 if(ddm.dragCurrent){
19499 ddm.refreshCache(ddm.dragCurrent.groups);
19503 var doScroll = function(){
19504 if(ddm.dragCurrent){
19505 var dds = Roo.dd.ScrollManager;
19507 if(proc.el.scroll(proc.dir, dds.increment)){
19511 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19516 var clearProc = function(){
19518 clearInterval(proc.id);
19525 var startProc = function(el, dir){
19526 Roo.log('scroll startproc');
19530 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19533 var onFire = function(e, isDrop){
19535 if(isDrop || !ddm.dragCurrent){ return; }
19536 var dds = Roo.dd.ScrollManager;
19537 if(!dragEl || dragEl != ddm.dragCurrent){
19538 dragEl = ddm.dragCurrent;
19539 // refresh regions on drag start
19540 dds.refreshCache();
19543 var xy = Roo.lib.Event.getXY(e);
19544 var pt = new Roo.lib.Point(xy[0], xy[1]);
19545 for(var id in els){
19546 var el = els[id], r = el._region;
19547 if(r && r.contains(pt) && el.isScrollable()){
19548 if(r.bottom - pt.y <= dds.thresh){
19550 startProc(el, "down");
19553 }else if(r.right - pt.x <= dds.thresh){
19555 startProc(el, "left");
19558 }else if(pt.y - r.top <= dds.thresh){
19560 startProc(el, "up");
19563 }else if(pt.x - r.left <= dds.thresh){
19565 startProc(el, "right");
19574 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19575 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19579 * Registers new overflow element(s) to auto scroll
19580 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19582 register : function(el){
19583 if(el instanceof Array){
19584 for(var i = 0, len = el.length; i < len; i++) {
19585 this.register(el[i]);
19591 Roo.dd.ScrollManager.els = els;
19595 * Unregisters overflow element(s) so they are no longer scrolled
19596 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19598 unregister : function(el){
19599 if(el instanceof Array){
19600 for(var i = 0, len = el.length; i < len; i++) {
19601 this.unregister(el[i]);
19610 * The number of pixels from the edge of a container the pointer needs to be to
19611 * trigger scrolling (defaults to 25)
19617 * The number of pixels to scroll in each scroll increment (defaults to 50)
19623 * The frequency of scrolls in milliseconds (defaults to 500)
19629 * True to animate the scroll (defaults to true)
19635 * The animation duration in seconds -
19636 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19642 * Manually trigger a cache refresh.
19644 refreshCache : function(){
19645 for(var id in els){
19646 if(typeof els[id] == 'object'){ // for people extending the object prototype
19647 els[id]._region = els[id].getRegion();
19654 * Ext JS Library 1.1.1
19655 * Copyright(c) 2006-2007, Ext JS, LLC.
19657 * Originally Released Under LGPL - original licence link has changed is not relivant.
19660 * <script type="text/javascript">
19665 * @class Roo.dd.Registry
19666 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19667 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19670 Roo.dd.Registry = function(){
19673 var autoIdSeed = 0;
19675 var getId = function(el, autogen){
19676 if(typeof el == "string"){
19680 if(!id && autogen !== false){
19681 id = "roodd-" + (++autoIdSeed);
19689 * Register a drag drop element
19690 * @param {String|HTMLElement} element The id or DOM node to register
19691 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19692 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19693 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19694 * populated in the data object (if applicable):
19696 Value Description<br />
19697 --------- ------------------------------------------<br />
19698 handles Array of DOM nodes that trigger dragging<br />
19699 for the element being registered<br />
19700 isHandle True if the element passed in triggers<br />
19701 dragging itself, else false
19704 register : function(el, data){
19706 if(typeof el == "string"){
19707 el = document.getElementById(el);
19710 elements[getId(el)] = data;
19711 if(data.isHandle !== false){
19712 handles[data.ddel.id] = data;
19715 var hs = data.handles;
19716 for(var i = 0, len = hs.length; i < len; i++){
19717 handles[getId(hs[i])] = data;
19723 * Unregister a drag drop element
19724 * @param {String|HTMLElement} element The id or DOM node to unregister
19726 unregister : function(el){
19727 var id = getId(el, false);
19728 var data = elements[id];
19730 delete elements[id];
19732 var hs = data.handles;
19733 for(var i = 0, len = hs.length; i < len; i++){
19734 delete handles[getId(hs[i], false)];
19741 * Returns the handle registered for a DOM Node by id
19742 * @param {String|HTMLElement} id The DOM node or id to look up
19743 * @return {Object} handle The custom handle data
19745 getHandle : function(id){
19746 if(typeof id != "string"){ // must be element?
19749 return handles[id];
19753 * Returns the handle that is registered for the DOM node that is the target of the event
19754 * @param {Event} e The event
19755 * @return {Object} handle The custom handle data
19757 getHandleFromEvent : function(e){
19758 var t = Roo.lib.Event.getTarget(e);
19759 return t ? handles[t.id] : null;
19763 * Returns a custom data object that is registered for a DOM node by id
19764 * @param {String|HTMLElement} id The DOM node or id to look up
19765 * @return {Object} data The custom data
19767 getTarget : function(id){
19768 if(typeof id != "string"){ // must be element?
19771 return elements[id];
19775 * Returns a custom data object that is registered for the DOM node that is the target of the event
19776 * @param {Event} e The event
19777 * @return {Object} data The custom data
19779 getTargetFromEvent : function(e){
19780 var t = Roo.lib.Event.getTarget(e);
19781 return t ? elements[t.id] || handles[t.id] : null;
19786 * Ext JS Library 1.1.1
19787 * Copyright(c) 2006-2007, Ext JS, LLC.
19789 * Originally Released Under LGPL - original licence link has changed is not relivant.
19792 * <script type="text/javascript">
19797 * @class Roo.dd.StatusProxy
19798 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19799 * default drag proxy used by all Roo.dd components.
19801 * @param {Object} config
19803 Roo.dd.StatusProxy = function(config){
19804 Roo.apply(this, config);
19805 this.id = this.id || Roo.id();
19806 this.el = new Roo.Layer({
19808 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19809 {tag: "div", cls: "x-dd-drop-icon"},
19810 {tag: "div", cls: "x-dd-drag-ghost"}
19813 shadow: !config || config.shadow !== false
19815 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19816 this.dropStatus = this.dropNotAllowed;
19819 Roo.dd.StatusProxy.prototype = {
19821 * @cfg {String} dropAllowed
19822 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19824 dropAllowed : "x-dd-drop-ok",
19826 * @cfg {String} dropNotAllowed
19827 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19829 dropNotAllowed : "x-dd-drop-nodrop",
19832 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19833 * over the current target element.
19834 * @param {String} cssClass The css class for the new drop status indicator image
19836 setStatus : function(cssClass){
19837 cssClass = cssClass || this.dropNotAllowed;
19838 if(this.dropStatus != cssClass){
19839 this.el.replaceClass(this.dropStatus, cssClass);
19840 this.dropStatus = cssClass;
19845 * Resets the status indicator to the default dropNotAllowed value
19846 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19848 reset : function(clearGhost){
19849 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19850 this.dropStatus = this.dropNotAllowed;
19852 this.ghost.update("");
19857 * Updates the contents of the ghost element
19858 * @param {String} html The html that will replace the current innerHTML of the ghost element
19860 update : function(html){
19861 if(typeof html == "string"){
19862 this.ghost.update(html);
19864 this.ghost.update("");
19865 html.style.margin = "0";
19866 this.ghost.dom.appendChild(html);
19868 // ensure float = none set?? cant remember why though.
19869 var el = this.ghost.dom.firstChild;
19871 Roo.fly(el).setStyle('float', 'none');
19876 * Returns the underlying proxy {@link Roo.Layer}
19877 * @return {Roo.Layer} el
19879 getEl : function(){
19884 * Returns the ghost element
19885 * @return {Roo.Element} el
19887 getGhost : function(){
19893 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19895 hide : function(clear){
19903 * Stops the repair animation if it's currently running
19906 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19912 * Displays this proxy
19919 * Force the Layer to sync its shadow and shim positions to the element
19926 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19927 * invalid drop operation by the item being dragged.
19928 * @param {Array} xy The XY position of the element ([x, y])
19929 * @param {Function} callback The function to call after the repair is complete
19930 * @param {Object} scope The scope in which to execute the callback
19932 repair : function(xy, callback, scope){
19933 this.callback = callback;
19934 this.scope = scope;
19935 if(xy && this.animRepair !== false){
19936 this.el.addClass("x-dd-drag-repair");
19937 this.el.hideUnders(true);
19938 this.anim = this.el.shift({
19939 duration: this.repairDuration || .5,
19943 callback: this.afterRepair,
19947 this.afterRepair();
19952 afterRepair : function(){
19954 if(typeof this.callback == "function"){
19955 this.callback.call(this.scope || this);
19957 this.callback = null;
19962 * Ext JS Library 1.1.1
19963 * Copyright(c) 2006-2007, Ext JS, LLC.
19965 * Originally Released Under LGPL - original licence link has changed is not relivant.
19968 * <script type="text/javascript">
19972 * @class Roo.dd.DragSource
19973 * @extends Roo.dd.DDProxy
19974 * A simple class that provides the basic implementation needed to make any element draggable.
19976 * @param {String/HTMLElement/Element} el The container element
19977 * @param {Object} config
19979 Roo.dd.DragSource = function(el, config){
19980 this.el = Roo.get(el);
19981 this.dragData = {};
19983 Roo.apply(this, config);
19986 this.proxy = new Roo.dd.StatusProxy();
19989 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19990 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19992 this.dragging = false;
19995 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19997 * @cfg {String} dropAllowed
19998 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20000 dropAllowed : "x-dd-drop-ok",
20002 * @cfg {String} dropNotAllowed
20003 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20005 dropNotAllowed : "x-dd-drop-nodrop",
20008 * Returns the data object associated with this drag source
20009 * @return {Object} data An object containing arbitrary data
20011 getDragData : function(e){
20012 return this.dragData;
20016 onDragEnter : function(e, id){
20017 var target = Roo.dd.DragDropMgr.getDDById(id);
20018 this.cachedTarget = target;
20019 if(this.beforeDragEnter(target, e, id) !== false){
20020 if(target.isNotifyTarget){
20021 var status = target.notifyEnter(this, e, this.dragData);
20022 this.proxy.setStatus(status);
20024 this.proxy.setStatus(this.dropAllowed);
20027 if(this.afterDragEnter){
20029 * An empty function by default, but provided so that you can perform a custom action
20030 * when the dragged item enters the drop target by providing an implementation.
20031 * @param {Roo.dd.DragDrop} target The drop target
20032 * @param {Event} e The event object
20033 * @param {String} id The id of the dragged element
20034 * @method afterDragEnter
20036 this.afterDragEnter(target, e, id);
20042 * An empty function by default, but provided so that you can perform a custom action
20043 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20044 * @param {Roo.dd.DragDrop} target The drop target
20045 * @param {Event} e The event object
20046 * @param {String} id The id of the dragged element
20047 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20049 beforeDragEnter : function(target, e, id){
20054 alignElWithMouse: function() {
20055 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20060 onDragOver : function(e, id){
20061 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20062 if(this.beforeDragOver(target, e, id) !== false){
20063 if(target.isNotifyTarget){
20064 var status = target.notifyOver(this, e, this.dragData);
20065 this.proxy.setStatus(status);
20068 if(this.afterDragOver){
20070 * An empty function by default, but provided so that you can perform a custom action
20071 * while the dragged item is over the drop target by providing an implementation.
20072 * @param {Roo.dd.DragDrop} target The drop target
20073 * @param {Event} e The event object
20074 * @param {String} id The id of the dragged element
20075 * @method afterDragOver
20077 this.afterDragOver(target, e, id);
20083 * An empty function by default, but provided so that you can perform a custom action
20084 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20085 * @param {Roo.dd.DragDrop} target The drop target
20086 * @param {Event} e The event object
20087 * @param {String} id The id of the dragged element
20088 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20090 beforeDragOver : function(target, e, id){
20095 onDragOut : function(e, id){
20096 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20097 if(this.beforeDragOut(target, e, id) !== false){
20098 if(target.isNotifyTarget){
20099 target.notifyOut(this, e, this.dragData);
20101 this.proxy.reset();
20102 if(this.afterDragOut){
20104 * An empty function by default, but provided so that you can perform a custom action
20105 * after the dragged item is dragged out of the target without dropping.
20106 * @param {Roo.dd.DragDrop} target The drop target
20107 * @param {Event} e The event object
20108 * @param {String} id The id of the dragged element
20109 * @method afterDragOut
20111 this.afterDragOut(target, e, id);
20114 this.cachedTarget = null;
20118 * An empty function by default, but provided so that you can perform a custom action before the dragged
20119 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20120 * @param {Roo.dd.DragDrop} target The drop target
20121 * @param {Event} e The event object
20122 * @param {String} id The id of the dragged element
20123 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20125 beforeDragOut : function(target, e, id){
20130 onDragDrop : function(e, id){
20131 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20132 if(this.beforeDragDrop(target, e, id) !== false){
20133 if(target.isNotifyTarget){
20134 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20135 this.onValidDrop(target, e, id);
20137 this.onInvalidDrop(target, e, id);
20140 this.onValidDrop(target, e, id);
20143 if(this.afterDragDrop){
20145 * An empty function by default, but provided so that you can perform a custom action
20146 * after a valid drag drop has occurred by providing an implementation.
20147 * @param {Roo.dd.DragDrop} target The drop target
20148 * @param {Event} e The event object
20149 * @param {String} id The id of the dropped element
20150 * @method afterDragDrop
20152 this.afterDragDrop(target, e, id);
20155 delete this.cachedTarget;
20159 * An empty function by default, but provided so that you can perform a custom action before the dragged
20160 * item is dropped onto the target and optionally cancel the onDragDrop.
20161 * @param {Roo.dd.DragDrop} target The drop target
20162 * @param {Event} e The event object
20163 * @param {String} id The id of the dragged element
20164 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20166 beforeDragDrop : function(target, e, id){
20171 onValidDrop : function(target, e, id){
20173 if(this.afterValidDrop){
20175 * An empty function by default, but provided so that you can perform a custom action
20176 * after a valid drop has occurred by providing an implementation.
20177 * @param {Object} target The target DD
20178 * @param {Event} e The event object
20179 * @param {String} id The id of the dropped element
20180 * @method afterInvalidDrop
20182 this.afterValidDrop(target, e, id);
20187 getRepairXY : function(e, data){
20188 return this.el.getXY();
20192 onInvalidDrop : function(target, e, id){
20193 this.beforeInvalidDrop(target, e, id);
20194 if(this.cachedTarget){
20195 if(this.cachedTarget.isNotifyTarget){
20196 this.cachedTarget.notifyOut(this, e, this.dragData);
20198 this.cacheTarget = null;
20200 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20202 if(this.afterInvalidDrop){
20204 * An empty function by default, but provided so that you can perform a custom action
20205 * after an invalid drop has occurred by providing an implementation.
20206 * @param {Event} e The event object
20207 * @param {String} id The id of the dropped element
20208 * @method afterInvalidDrop
20210 this.afterInvalidDrop(e, id);
20215 afterRepair : function(){
20217 this.el.highlight(this.hlColor || "c3daf9");
20219 this.dragging = false;
20223 * An empty function by default, but provided so that you can perform a custom action after an invalid
20224 * drop has occurred.
20225 * @param {Roo.dd.DragDrop} target The drop target
20226 * @param {Event} e The event object
20227 * @param {String} id The id of the dragged element
20228 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20230 beforeInvalidDrop : function(target, e, id){
20235 handleMouseDown : function(e){
20236 if(this.dragging) {
20239 var data = this.getDragData(e);
20240 if(data && this.onBeforeDrag(data, e) !== false){
20241 this.dragData = data;
20243 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20248 * An empty function by default, but provided so that you can perform a custom action before the initial
20249 * drag event begins and optionally cancel it.
20250 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20251 * @param {Event} e The event object
20252 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20254 onBeforeDrag : function(data, e){
20259 * An empty function by default, but provided so that you can perform a custom action once the initial
20260 * drag event has begun. The drag cannot be canceled from this function.
20261 * @param {Number} x The x position of the click on the dragged object
20262 * @param {Number} y The y position of the click on the dragged object
20264 onStartDrag : Roo.emptyFn,
20266 // private - YUI override
20267 startDrag : function(x, y){
20268 this.proxy.reset();
20269 this.dragging = true;
20270 this.proxy.update("");
20271 this.onInitDrag(x, y);
20276 onInitDrag : function(x, y){
20277 var clone = this.el.dom.cloneNode(true);
20278 clone.id = Roo.id(); // prevent duplicate ids
20279 this.proxy.update(clone);
20280 this.onStartDrag(x, y);
20285 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20286 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20288 getProxy : function(){
20293 * Hides the drag source's {@link Roo.dd.StatusProxy}
20295 hideProxy : function(){
20297 this.proxy.reset(true);
20298 this.dragging = false;
20302 triggerCacheRefresh : function(){
20303 Roo.dd.DDM.refreshCache(this.groups);
20306 // private - override to prevent hiding
20307 b4EndDrag: function(e) {
20310 // private - override to prevent moving
20311 endDrag : function(e){
20312 this.onEndDrag(this.dragData, e);
20316 onEndDrag : function(data, e){
20319 // private - pin to cursor
20320 autoOffset : function(x, y) {
20321 this.setDelta(-12, -20);
20325 * Ext JS Library 1.1.1
20326 * Copyright(c) 2006-2007, Ext JS, LLC.
20328 * Originally Released Under LGPL - original licence link has changed is not relivant.
20331 * <script type="text/javascript">
20336 * @class Roo.dd.DropTarget
20337 * @extends Roo.dd.DDTarget
20338 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20339 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20341 * @param {String/HTMLElement/Element} el The container element
20342 * @param {Object} config
20344 Roo.dd.DropTarget = function(el, config){
20345 this.el = Roo.get(el);
20347 var listeners = false; ;
20348 if (config && config.listeners) {
20349 listeners= config.listeners;
20350 delete config.listeners;
20352 Roo.apply(this, config);
20354 if(this.containerScroll){
20355 Roo.dd.ScrollManager.register(this.el);
20359 * @scope Roo.dd.DropTarget
20364 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20365 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20366 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20368 * IMPORTANT : it should set this.overClass and this.dropAllowed
20370 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20371 * @param {Event} e The event
20372 * @param {Object} data An object containing arbitrary data supplied by the drag source
20378 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20379 * This method will be called on every mouse movement while the drag source is over the drop target.
20380 * This default implementation simply returns the dropAllowed config value.
20382 * IMPORTANT : it should set this.dropAllowed
20384 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20385 * @param {Event} e The event
20386 * @param {Object} data An object containing arbitrary data supplied by the drag source
20392 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20393 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20394 * overClass (if any) from the drop element.
20396 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20397 * @param {Event} e The event
20398 * @param {Object} data An object containing arbitrary data supplied by the drag source
20404 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20405 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20406 * implementation that does something to process the drop event and returns true so that the drag source's
20407 * repair action does not run.
20409 * IMPORTANT : it should set this.success
20411 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20412 * @param {Event} e The event
20413 * @param {Object} data An object containing arbitrary data supplied by the drag source
20419 Roo.dd.DropTarget.superclass.constructor.call( this,
20421 this.ddGroup || this.group,
20424 listeners : listeners || {}
20432 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20434 * @cfg {String} overClass
20435 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20438 * @cfg {String} ddGroup
20439 * The drag drop group to handle drop events for
20443 * @cfg {String} dropAllowed
20444 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20446 dropAllowed : "x-dd-drop-ok",
20448 * @cfg {String} dropNotAllowed
20449 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20451 dropNotAllowed : "x-dd-drop-nodrop",
20453 * @cfg {boolean} success
20454 * set this after drop listener..
20458 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20459 * if the drop point is valid for over/enter..
20466 isNotifyTarget : true,
20471 notifyEnter : function(dd, e, data)
20474 this.fireEvent('enter', dd, e, data);
20475 if(this.overClass){
20476 this.el.addClass(this.overClass);
20478 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20479 this.valid ? this.dropAllowed : this.dropNotAllowed
20486 notifyOver : function(dd, e, data)
20489 this.fireEvent('over', dd, e, data);
20490 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20491 this.valid ? this.dropAllowed : this.dropNotAllowed
20498 notifyOut : function(dd, e, data)
20500 this.fireEvent('out', dd, e, data);
20501 if(this.overClass){
20502 this.el.removeClass(this.overClass);
20509 notifyDrop : function(dd, e, data)
20511 this.success = false;
20512 this.fireEvent('drop', dd, e, data);
20513 return this.success;
20517 * Ext JS Library 1.1.1
20518 * Copyright(c) 2006-2007, Ext JS, LLC.
20520 * Originally Released Under LGPL - original licence link has changed is not relivant.
20523 * <script type="text/javascript">
20528 * @class Roo.dd.DragZone
20529 * @extends Roo.dd.DragSource
20530 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20531 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20533 * @param {String/HTMLElement/Element} el The container element
20534 * @param {Object} config
20536 Roo.dd.DragZone = function(el, config){
20537 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20538 if(this.containerScroll){
20539 Roo.dd.ScrollManager.register(this.el);
20543 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20545 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20546 * for auto scrolling during drag operations.
20549 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20550 * method after a failed drop (defaults to "c3daf9" - light blue)
20554 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20555 * for a valid target to drag based on the mouse down. Override this method
20556 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20557 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20558 * @param {EventObject} e The mouse down event
20559 * @return {Object} The dragData
20561 getDragData : function(e){
20562 return Roo.dd.Registry.getHandleFromEvent(e);
20566 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20567 * this.dragData.ddel
20568 * @param {Number} x The x position of the click on the dragged object
20569 * @param {Number} y The y position of the click on the dragged object
20570 * @return {Boolean} true to continue the drag, false to cancel
20572 onInitDrag : function(x, y){
20573 this.proxy.update(this.dragData.ddel.cloneNode(true));
20574 this.onStartDrag(x, y);
20579 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20581 afterRepair : function(){
20583 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20585 this.dragging = false;
20589 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20590 * the XY of this.dragData.ddel
20591 * @param {EventObject} e The mouse up event
20592 * @return {Array} The xy location (e.g. [100, 200])
20594 getRepairXY : function(e){
20595 return Roo.Element.fly(this.dragData.ddel).getXY();
20599 * Ext JS Library 1.1.1
20600 * Copyright(c) 2006-2007, Ext JS, LLC.
20602 * Originally Released Under LGPL - original licence link has changed is not relivant.
20605 * <script type="text/javascript">
20608 * @class Roo.dd.DropZone
20609 * @extends Roo.dd.DropTarget
20610 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20611 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20613 * @param {String/HTMLElement/Element} el The container element
20614 * @param {Object} config
20616 Roo.dd.DropZone = function(el, config){
20617 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20620 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20622 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20623 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20624 * provide your own custom lookup.
20625 * @param {Event} e The event
20626 * @return {Object} data The custom data
20628 getTargetFromEvent : function(e){
20629 return Roo.dd.Registry.getTargetFromEvent(e);
20633 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20634 * that it has registered. This method has no default implementation and should be overridden to provide
20635 * node-specific processing if necessary.
20636 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20637 * {@link #getTargetFromEvent} for this node)
20638 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20639 * @param {Event} e The event
20640 * @param {Object} data An object containing arbitrary data supplied by the drag source
20642 onNodeEnter : function(n, dd, e, data){
20647 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20648 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20649 * overridden to provide the proper feedback.
20650 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20651 * {@link #getTargetFromEvent} for this node)
20652 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20653 * @param {Event} e The event
20654 * @param {Object} data An object containing arbitrary data supplied by the drag source
20655 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20656 * underlying {@link Roo.dd.StatusProxy} can be updated
20658 onNodeOver : function(n, dd, e, data){
20659 return this.dropAllowed;
20663 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20664 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20665 * node-specific processing if necessary.
20666 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20667 * {@link #getTargetFromEvent} for this node)
20668 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20669 * @param {Event} e The event
20670 * @param {Object} data An object containing arbitrary data supplied by the drag source
20672 onNodeOut : function(n, dd, e, data){
20677 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20678 * the drop node. The default implementation returns false, so it should be overridden to provide the
20679 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20680 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20681 * {@link #getTargetFromEvent} for this node)
20682 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20683 * @param {Event} e The event
20684 * @param {Object} data An object containing arbitrary data supplied by the drag source
20685 * @return {Boolean} True if the drop was valid, else false
20687 onNodeDrop : function(n, dd, e, data){
20692 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20693 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20694 * it should be overridden to provide the proper feedback if necessary.
20695 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20696 * @param {Event} e The event
20697 * @param {Object} data An object containing arbitrary data supplied by the drag source
20698 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20699 * underlying {@link Roo.dd.StatusProxy} can be updated
20701 onContainerOver : function(dd, e, data){
20702 return this.dropNotAllowed;
20706 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20707 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20708 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20709 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20710 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20711 * @param {Event} e The event
20712 * @param {Object} data An object containing arbitrary data supplied by the drag source
20713 * @return {Boolean} True if the drop was valid, else false
20715 onContainerDrop : function(dd, e, data){
20720 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20721 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20722 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20723 * you should override this method and provide a custom implementation.
20724 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20725 * @param {Event} e The event
20726 * @param {Object} data An object containing arbitrary data supplied by the drag source
20727 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20728 * underlying {@link Roo.dd.StatusProxy} can be updated
20730 notifyEnter : function(dd, e, data){
20731 return this.dropNotAllowed;
20735 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20736 * This method will be called on every mouse movement while the drag source is over the drop zone.
20737 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20738 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20739 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20740 * registered node, it will call {@link #onContainerOver}.
20741 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20742 * @param {Event} e The event
20743 * @param {Object} data An object containing arbitrary data supplied by the drag source
20744 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20745 * underlying {@link Roo.dd.StatusProxy} can be updated
20747 notifyOver : function(dd, e, data){
20748 var n = this.getTargetFromEvent(e);
20749 if(!n){ // not over valid drop target
20750 if(this.lastOverNode){
20751 this.onNodeOut(this.lastOverNode, dd, e, data);
20752 this.lastOverNode = null;
20754 return this.onContainerOver(dd, e, data);
20756 if(this.lastOverNode != n){
20757 if(this.lastOverNode){
20758 this.onNodeOut(this.lastOverNode, dd, e, data);
20760 this.onNodeEnter(n, dd, e, data);
20761 this.lastOverNode = n;
20763 return this.onNodeOver(n, dd, e, data);
20767 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20768 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20769 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20770 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20771 * @param {Event} e The event
20772 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20774 notifyOut : function(dd, e, data){
20775 if(this.lastOverNode){
20776 this.onNodeOut(this.lastOverNode, dd, e, data);
20777 this.lastOverNode = null;
20782 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20783 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20784 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20785 * otherwise it will call {@link #onContainerDrop}.
20786 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20787 * @param {Event} e The event
20788 * @param {Object} data An object containing arbitrary data supplied by the drag source
20789 * @return {Boolean} True if the drop was valid, else false
20791 notifyDrop : function(dd, e, data){
20792 if(this.lastOverNode){
20793 this.onNodeOut(this.lastOverNode, dd, e, data);
20794 this.lastOverNode = null;
20796 var n = this.getTargetFromEvent(e);
20798 this.onNodeDrop(n, dd, e, data) :
20799 this.onContainerDrop(dd, e, data);
20803 triggerCacheRefresh : function(){
20804 Roo.dd.DDM.refreshCache(this.groups);
20808 * Ext JS Library 1.1.1
20809 * Copyright(c) 2006-2007, Ext JS, LLC.
20811 * Originally Released Under LGPL - original licence link has changed is not relivant.
20814 * <script type="text/javascript">
20819 * @class Roo.data.SortTypes
20821 * Defines the default sorting (casting?) comparison functions used when sorting data.
20823 Roo.data.SortTypes = {
20825 * Default sort that does nothing
20826 * @param {Mixed} s The value being converted
20827 * @return {Mixed} The comparison value
20829 none : function(s){
20834 * The regular expression used to strip tags
20838 stripTagsRE : /<\/?[^>]+>/gi,
20841 * Strips all HTML tags to sort on text only
20842 * @param {Mixed} s The value being converted
20843 * @return {String} The comparison value
20845 asText : function(s){
20846 return String(s).replace(this.stripTagsRE, "");
20850 * Strips all HTML tags to sort on text only - Case insensitive
20851 * @param {Mixed} s The value being converted
20852 * @return {String} The comparison value
20854 asUCText : function(s){
20855 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20859 * Case insensitive string
20860 * @param {Mixed} s The value being converted
20861 * @return {String} The comparison value
20863 asUCString : function(s) {
20864 return String(s).toUpperCase();
20869 * @param {Mixed} s The value being converted
20870 * @return {Number} The comparison value
20872 asDate : function(s) {
20876 if(s instanceof Date){
20877 return s.getTime();
20879 return Date.parse(String(s));
20884 * @param {Mixed} s The value being converted
20885 * @return {Float} The comparison value
20887 asFloat : function(s) {
20888 var val = parseFloat(String(s).replace(/,/g, ""));
20889 if(isNaN(val)) val = 0;
20895 * @param {Mixed} s The value being converted
20896 * @return {Number} The comparison value
20898 asInt : function(s) {
20899 var val = parseInt(String(s).replace(/,/g, ""));
20900 if(isNaN(val)) val = 0;
20905 * Ext JS Library 1.1.1
20906 * Copyright(c) 2006-2007, Ext JS, LLC.
20908 * Originally Released Under LGPL - original licence link has changed is not relivant.
20911 * <script type="text/javascript">
20915 * @class Roo.data.Record
20916 * Instances of this class encapsulate both record <em>definition</em> information, and record
20917 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20918 * to access Records cached in an {@link Roo.data.Store} object.<br>
20920 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20921 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20924 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20926 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20927 * {@link #create}. The parameters are the same.
20928 * @param {Array} data An associative Array of data values keyed by the field name.
20929 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20930 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20931 * not specified an integer id is generated.
20933 Roo.data.Record = function(data, id){
20934 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20939 * Generate a constructor for a specific record layout.
20940 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20941 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20942 * Each field definition object may contain the following properties: <ul>
20943 * <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,
20944 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20945 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20946 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20947 * is being used, then this is a string containing the javascript expression to reference the data relative to
20948 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20949 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20950 * this may be omitted.</p></li>
20951 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20952 * <ul><li>auto (Default, implies no conversion)</li>
20957 * <li>date</li></ul></p></li>
20958 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20959 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20960 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20961 * by the Reader into an object that will be stored in the Record. It is passed the
20962 * following parameters:<ul>
20963 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20965 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20967 * <br>usage:<br><pre><code>
20968 var TopicRecord = Roo.data.Record.create(
20969 {name: 'title', mapping: 'topic_title'},
20970 {name: 'author', mapping: 'username'},
20971 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20972 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20973 {name: 'lastPoster', mapping: 'user2'},
20974 {name: 'excerpt', mapping: 'post_text'}
20977 var myNewRecord = new TopicRecord({
20978 title: 'Do my job please',
20981 lastPost: new Date(),
20982 lastPoster: 'Animal',
20983 excerpt: 'No way dude!'
20985 myStore.add(myNewRecord);
20990 Roo.data.Record.create = function(o){
20991 var f = function(){
20992 f.superclass.constructor.apply(this, arguments);
20994 Roo.extend(f, Roo.data.Record);
20995 var p = f.prototype;
20996 p.fields = new Roo.util.MixedCollection(false, function(field){
20999 for(var i = 0, len = o.length; i < len; i++){
21000 p.fields.add(new Roo.data.Field(o[i]));
21002 f.getField = function(name){
21003 return p.fields.get(name);
21008 Roo.data.Record.AUTO_ID = 1000;
21009 Roo.data.Record.EDIT = 'edit';
21010 Roo.data.Record.REJECT = 'reject';
21011 Roo.data.Record.COMMIT = 'commit';
21013 Roo.data.Record.prototype = {
21015 * Readonly flag - true if this record has been modified.
21024 join : function(store){
21025 this.store = store;
21029 * Set the named field to the specified value.
21030 * @param {String} name The name of the field to set.
21031 * @param {Object} value The value to set the field to.
21033 set : function(name, value){
21034 if(this.data[name] == value){
21038 if(!this.modified){
21039 this.modified = {};
21041 if(typeof this.modified[name] == 'undefined'){
21042 this.modified[name] = this.data[name];
21044 this.data[name] = value;
21045 if(!this.editing && this.store){
21046 this.store.afterEdit(this);
21051 * Get the value of the named field.
21052 * @param {String} name The name of the field to get the value of.
21053 * @return {Object} The value of the field.
21055 get : function(name){
21056 return this.data[name];
21060 beginEdit : function(){
21061 this.editing = true;
21062 this.modified = {};
21066 cancelEdit : function(){
21067 this.editing = false;
21068 delete this.modified;
21072 endEdit : function(){
21073 this.editing = false;
21074 if(this.dirty && this.store){
21075 this.store.afterEdit(this);
21080 * Usually called by the {@link Roo.data.Store} which owns the Record.
21081 * Rejects all changes made to the Record since either creation, or the last commit operation.
21082 * Modified fields are reverted to their original values.
21084 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21085 * of reject operations.
21087 reject : function(){
21088 var m = this.modified;
21090 if(typeof m[n] != "function"){
21091 this.data[n] = m[n];
21094 this.dirty = false;
21095 delete this.modified;
21096 this.editing = false;
21098 this.store.afterReject(this);
21103 * Usually called by the {@link Roo.data.Store} which owns the Record.
21104 * Commits all changes made to the Record since either creation, or the last commit operation.
21106 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21107 * of commit operations.
21109 commit : function(){
21110 this.dirty = false;
21111 delete this.modified;
21112 this.editing = false;
21114 this.store.afterCommit(this);
21119 hasError : function(){
21120 return this.error != null;
21124 clearError : function(){
21129 * Creates a copy of this record.
21130 * @param {String} id (optional) A new record id if you don't want to use this record's id
21133 copy : function(newId) {
21134 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21138 * Ext JS Library 1.1.1
21139 * Copyright(c) 2006-2007, Ext JS, LLC.
21141 * Originally Released Under LGPL - original licence link has changed is not relivant.
21144 * <script type="text/javascript">
21150 * @class Roo.data.Store
21151 * @extends Roo.util.Observable
21152 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21153 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21155 * 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
21156 * has no knowledge of the format of the data returned by the Proxy.<br>
21158 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21159 * instances from the data object. These records are cached and made available through accessor functions.
21161 * Creates a new Store.
21162 * @param {Object} config A config object containing the objects needed for the Store to access data,
21163 * and read the data into Records.
21165 Roo.data.Store = function(config){
21166 this.data = new Roo.util.MixedCollection(false);
21167 this.data.getKey = function(o){
21170 this.baseParams = {};
21172 this.paramNames = {
21177 "multisort" : "_multisort"
21180 if(config && config.data){
21181 this.inlineData = config.data;
21182 delete config.data;
21185 Roo.apply(this, config);
21187 if(this.reader){ // reader passed
21188 this.reader = Roo.factory(this.reader, Roo.data);
21189 this.reader.xmodule = this.xmodule || false;
21190 if(!this.recordType){
21191 this.recordType = this.reader.recordType;
21193 if(this.reader.onMetaChange){
21194 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21198 if(this.recordType){
21199 this.fields = this.recordType.prototype.fields;
21201 this.modified = [];
21205 * @event datachanged
21206 * Fires when the data cache has changed, and a widget which is using this Store
21207 * as a Record cache should refresh its view.
21208 * @param {Store} this
21210 datachanged : true,
21212 * @event metachange
21213 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21214 * @param {Store} this
21215 * @param {Object} meta The JSON metadata
21220 * Fires when Records have been added to the Store
21221 * @param {Store} this
21222 * @param {Roo.data.Record[]} records The array of Records added
21223 * @param {Number} index The index at which the record(s) were added
21228 * Fires when a Record has been removed from the Store
21229 * @param {Store} this
21230 * @param {Roo.data.Record} record The Record that was removed
21231 * @param {Number} index The index at which the record was removed
21236 * Fires when a Record has been updated
21237 * @param {Store} this
21238 * @param {Roo.data.Record} record The Record that was updated
21239 * @param {String} operation The update operation being performed. Value may be one of:
21241 Roo.data.Record.EDIT
21242 Roo.data.Record.REJECT
21243 Roo.data.Record.COMMIT
21249 * Fires when the data cache has been cleared.
21250 * @param {Store} this
21254 * @event beforeload
21255 * Fires before a request is made for a new data object. If the beforeload handler returns false
21256 * the load action will be canceled.
21257 * @param {Store} this
21258 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21262 * @event beforeloadadd
21263 * Fires after a new set of Records has been loaded.
21264 * @param {Store} this
21265 * @param {Roo.data.Record[]} records The Records that were loaded
21266 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21268 beforeloadadd : true,
21271 * Fires after a new set of Records has been loaded, before they are added to the store.
21272 * @param {Store} this
21273 * @param {Roo.data.Record[]} records The Records that were loaded
21274 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21275 * @params {Object} return from reader
21279 * @event loadexception
21280 * Fires if an exception occurs in the Proxy during loading.
21281 * Called with the signature of the Proxy's "loadexception" event.
21282 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21285 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21286 * @param {Object} load options
21287 * @param {Object} jsonData from your request (normally this contains the Exception)
21289 loadexception : true
21293 this.proxy = Roo.factory(this.proxy, Roo.data);
21294 this.proxy.xmodule = this.xmodule || false;
21295 this.relayEvents(this.proxy, ["loadexception"]);
21297 this.sortToggle = {};
21298 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21300 Roo.data.Store.superclass.constructor.call(this);
21302 if(this.inlineData){
21303 this.loadData(this.inlineData);
21304 delete this.inlineData;
21308 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21310 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21311 * without a remote query - used by combo/forms at present.
21315 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21318 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21321 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21322 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21325 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21326 * on any HTTP request
21329 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21332 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21336 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21337 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21339 remoteSort : false,
21342 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21343 * loaded or when a record is removed. (defaults to false).
21345 pruneModifiedRecords : false,
21348 lastOptions : null,
21351 * Add Records to the Store and fires the add event.
21352 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21354 add : function(records){
21355 records = [].concat(records);
21356 for(var i = 0, len = records.length; i < len; i++){
21357 records[i].join(this);
21359 var index = this.data.length;
21360 this.data.addAll(records);
21361 this.fireEvent("add", this, records, index);
21365 * Remove a Record from the Store and fires the remove event.
21366 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21368 remove : function(record){
21369 var index = this.data.indexOf(record);
21370 this.data.removeAt(index);
21371 if(this.pruneModifiedRecords){
21372 this.modified.remove(record);
21374 this.fireEvent("remove", this, record, index);
21378 * Remove all Records from the Store and fires the clear event.
21380 removeAll : function(){
21382 if(this.pruneModifiedRecords){
21383 this.modified = [];
21385 this.fireEvent("clear", this);
21389 * Inserts Records to the Store at the given index and fires the add event.
21390 * @param {Number} index The start index at which to insert the passed Records.
21391 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21393 insert : function(index, records){
21394 records = [].concat(records);
21395 for(var i = 0, len = records.length; i < len; i++){
21396 this.data.insert(index, records[i]);
21397 records[i].join(this);
21399 this.fireEvent("add", this, records, index);
21403 * Get the index within the cache of the passed Record.
21404 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21405 * @return {Number} The index of the passed Record. Returns -1 if not found.
21407 indexOf : function(record){
21408 return this.data.indexOf(record);
21412 * Get the index within the cache of the Record with the passed id.
21413 * @param {String} id The id of the Record to find.
21414 * @return {Number} The index of the Record. Returns -1 if not found.
21416 indexOfId : function(id){
21417 return this.data.indexOfKey(id);
21421 * Get the Record with the specified id.
21422 * @param {String} id The id of the Record to find.
21423 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21425 getById : function(id){
21426 return this.data.key(id);
21430 * Get the Record at the specified index.
21431 * @param {Number} index The index of the Record to find.
21432 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21434 getAt : function(index){
21435 return this.data.itemAt(index);
21439 * Returns a range of Records between specified indices.
21440 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21441 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21442 * @return {Roo.data.Record[]} An array of Records
21444 getRange : function(start, end){
21445 return this.data.getRange(start, end);
21449 storeOptions : function(o){
21450 o = Roo.apply({}, o);
21453 this.lastOptions = o;
21457 * Loads the Record cache from the configured Proxy using the configured Reader.
21459 * If using remote paging, then the first load call must specify the <em>start</em>
21460 * and <em>limit</em> properties in the options.params property to establish the initial
21461 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21463 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21464 * and this call will return before the new data has been loaded. Perform any post-processing
21465 * in a callback function, or in a "load" event handler.</strong>
21467 * @param {Object} options An object containing properties which control loading options:<ul>
21468 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21469 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21470 * passed the following arguments:<ul>
21471 * <li>r : Roo.data.Record[]</li>
21472 * <li>options: Options object from the load call</li>
21473 * <li>success: Boolean success indicator</li></ul></li>
21474 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21475 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21478 load : function(options){
21479 options = options || {};
21480 if(this.fireEvent("beforeload", this, options) !== false){
21481 this.storeOptions(options);
21482 var p = Roo.apply(options.params || {}, this.baseParams);
21483 // if meta was not loaded from remote source.. try requesting it.
21484 if (!this.reader.metaFromRemote) {
21485 p._requestMeta = 1;
21487 if(this.sortInfo && this.remoteSort){
21488 var pn = this.paramNames;
21489 p[pn["sort"]] = this.sortInfo.field;
21490 p[pn["dir"]] = this.sortInfo.direction;
21492 if (this.multiSort) {
21493 var pn = this.paramNames;
21494 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21497 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21502 * Reloads the Record cache from the configured Proxy using the configured Reader and
21503 * the options from the last load operation performed.
21504 * @param {Object} options (optional) An object containing properties which may override the options
21505 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21506 * the most recently used options are reused).
21508 reload : function(options){
21509 this.load(Roo.applyIf(options||{}, this.lastOptions));
21513 // Called as a callback by the Reader during a load operation.
21514 loadRecords : function(o, options, success){
21515 if(!o || success === false){
21516 if(success !== false){
21517 this.fireEvent("load", this, [], options, o);
21519 if(options.callback){
21520 options.callback.call(options.scope || this, [], options, false);
21524 // if data returned failure - throw an exception.
21525 if (o.success === false) {
21526 // show a message if no listener is registered.
21527 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21528 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21530 // loadmask wil be hooked into this..
21531 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21534 var r = o.records, t = o.totalRecords || r.length;
21536 this.fireEvent("beforeloadadd", this, r, options, o);
21538 if(!options || options.add !== true){
21539 if(this.pruneModifiedRecords){
21540 this.modified = [];
21542 for(var i = 0, len = r.length; i < len; i++){
21546 this.data = this.snapshot;
21547 delete this.snapshot;
21550 this.data.addAll(r);
21551 this.totalLength = t;
21553 this.fireEvent("datachanged", this);
21555 this.totalLength = Math.max(t, this.data.length+r.length);
21558 this.fireEvent("load", this, r, options, o);
21559 if(options.callback){
21560 options.callback.call(options.scope || this, r, options, true);
21566 * Loads data from a passed data block. A Reader which understands the format of the data
21567 * must have been configured in the constructor.
21568 * @param {Object} data The data block from which to read the Records. The format of the data expected
21569 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21570 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21572 loadData : function(o, append){
21573 var r = this.reader.readRecords(o);
21574 this.loadRecords(r, {add: append}, true);
21578 * Gets the number of cached records.
21580 * <em>If using paging, this may not be the total size of the dataset. If the data object
21581 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21582 * the data set size</em>
21584 getCount : function(){
21585 return this.data.length || 0;
21589 * Gets the total number of records in the dataset as returned by the server.
21591 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21592 * the dataset size</em>
21594 getTotalCount : function(){
21595 return this.totalLength || 0;
21599 * Returns the sort state of the Store as an object with two properties:
21601 field {String} The name of the field by which the Records are sorted
21602 direction {String} The sort order, "ASC" or "DESC"
21605 getSortState : function(){
21606 return this.sortInfo;
21610 applySort : function(){
21611 if(this.sortInfo && !this.remoteSort){
21612 var s = this.sortInfo, f = s.field;
21613 var st = this.fields.get(f).sortType;
21614 var fn = function(r1, r2){
21615 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21616 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21618 this.data.sort(s.direction, fn);
21619 if(this.snapshot && this.snapshot != this.data){
21620 this.snapshot.sort(s.direction, fn);
21626 * Sets the default sort column and order to be used by the next load operation.
21627 * @param {String} fieldName The name of the field to sort by.
21628 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21630 setDefaultSort : function(field, dir){
21631 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21635 * Sort the Records.
21636 * If remote sorting is used, the sort is performed on the server, and the cache is
21637 * reloaded. If local sorting is used, the cache is sorted internally.
21638 * @param {String} fieldName The name of the field to sort by.
21639 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21641 sort : function(fieldName, dir){
21642 var f = this.fields.get(fieldName);
21644 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21646 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21647 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21652 this.sortToggle[f.name] = dir;
21653 this.sortInfo = {field: f.name, direction: dir};
21654 if(!this.remoteSort){
21656 this.fireEvent("datachanged", this);
21658 this.load(this.lastOptions);
21663 * Calls the specified function for each of the Records in the cache.
21664 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21665 * Returning <em>false</em> aborts and exits the iteration.
21666 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21668 each : function(fn, scope){
21669 this.data.each(fn, scope);
21673 * Gets all records modified since the last commit. Modified records are persisted across load operations
21674 * (e.g., during paging).
21675 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21677 getModifiedRecords : function(){
21678 return this.modified;
21682 createFilterFn : function(property, value, anyMatch){
21683 if(!value.exec){ // not a regex
21684 value = String(value);
21685 if(value.length == 0){
21688 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21690 return function(r){
21691 return value.test(r.data[property]);
21696 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21697 * @param {String} property A field on your records
21698 * @param {Number} start The record index to start at (defaults to 0)
21699 * @param {Number} end The last record index to include (defaults to length - 1)
21700 * @return {Number} The sum
21702 sum : function(property, start, end){
21703 var rs = this.data.items, v = 0;
21704 start = start || 0;
21705 end = (end || end === 0) ? end : rs.length-1;
21707 for(var i = start; i <= end; i++){
21708 v += (rs[i].data[property] || 0);
21714 * Filter the records by a specified property.
21715 * @param {String} field A field on your records
21716 * @param {String/RegExp} value Either a string that the field
21717 * should start with or a RegExp to test against the field
21718 * @param {Boolean} anyMatch True to match any part not just the beginning
21720 filter : function(property, value, anyMatch){
21721 var fn = this.createFilterFn(property, value, anyMatch);
21722 return fn ? this.filterBy(fn) : this.clearFilter();
21726 * Filter by a function. The specified function will be called with each
21727 * record in this data source. If the function returns true the record is included,
21728 * otherwise it is filtered.
21729 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21730 * @param {Object} scope (optional) The scope of the function (defaults to this)
21732 filterBy : function(fn, scope){
21733 this.snapshot = this.snapshot || this.data;
21734 this.data = this.queryBy(fn, scope||this);
21735 this.fireEvent("datachanged", this);
21739 * Query the records by a specified property.
21740 * @param {String} field A field on your records
21741 * @param {String/RegExp} value Either a string that the field
21742 * should start with or a RegExp to test against the field
21743 * @param {Boolean} anyMatch True to match any part not just the beginning
21744 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21746 query : function(property, value, anyMatch){
21747 var fn = this.createFilterFn(property, value, anyMatch);
21748 return fn ? this.queryBy(fn) : this.data.clone();
21752 * Query by a function. The specified function will be called with each
21753 * record in this data source. If the function returns true the record is included
21755 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21756 * @param {Object} scope (optional) The scope of the function (defaults to this)
21757 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21759 queryBy : function(fn, scope){
21760 var data = this.snapshot || this.data;
21761 return data.filterBy(fn, scope||this);
21765 * Collects unique values for a particular dataIndex from this store.
21766 * @param {String} dataIndex The property to collect
21767 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21768 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21769 * @return {Array} An array of the unique values
21771 collect : function(dataIndex, allowNull, bypassFilter){
21772 var d = (bypassFilter === true && this.snapshot) ?
21773 this.snapshot.items : this.data.items;
21774 var v, sv, r = [], l = {};
21775 for(var i = 0, len = d.length; i < len; i++){
21776 v = d[i].data[dataIndex];
21778 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21787 * Revert to a view of the Record cache with no filtering applied.
21788 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21790 clearFilter : function(suppressEvent){
21791 if(this.snapshot && this.snapshot != this.data){
21792 this.data = this.snapshot;
21793 delete this.snapshot;
21794 if(suppressEvent !== true){
21795 this.fireEvent("datachanged", this);
21801 afterEdit : function(record){
21802 if(this.modified.indexOf(record) == -1){
21803 this.modified.push(record);
21805 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21809 afterReject : function(record){
21810 this.modified.remove(record);
21811 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21815 afterCommit : function(record){
21816 this.modified.remove(record);
21817 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21821 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21822 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21824 commitChanges : function(){
21825 var m = this.modified.slice(0);
21826 this.modified = [];
21827 for(var i = 0, len = m.length; i < len; i++){
21833 * Cancel outstanding changes on all changed records.
21835 rejectChanges : function(){
21836 var m = this.modified.slice(0);
21837 this.modified = [];
21838 for(var i = 0, len = m.length; i < len; i++){
21843 onMetaChange : function(meta, rtype, o){
21844 this.recordType = rtype;
21845 this.fields = rtype.prototype.fields;
21846 delete this.snapshot;
21847 this.sortInfo = meta.sortInfo || this.sortInfo;
21848 this.modified = [];
21849 this.fireEvent('metachange', this, this.reader.meta);
21852 moveIndex : function(data, type)
21854 var index = this.indexOf(data);
21856 var newIndex = index + type;
21860 this.insert(newIndex, data);
21865 * Ext JS Library 1.1.1
21866 * Copyright(c) 2006-2007, Ext JS, LLC.
21868 * Originally Released Under LGPL - original licence link has changed is not relivant.
21871 * <script type="text/javascript">
21875 * @class Roo.data.SimpleStore
21876 * @extends Roo.data.Store
21877 * Small helper class to make creating Stores from Array data easier.
21878 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21879 * @cfg {Array} fields An array of field definition objects, or field name strings.
21880 * @cfg {Array} data The multi-dimensional array of data
21882 * @param {Object} config
21884 Roo.data.SimpleStore = function(config){
21885 Roo.data.SimpleStore.superclass.constructor.call(this, {
21887 reader: new Roo.data.ArrayReader({
21890 Roo.data.Record.create(config.fields)
21892 proxy : new Roo.data.MemoryProxy(config.data)
21896 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21898 * Ext JS Library 1.1.1
21899 * Copyright(c) 2006-2007, Ext JS, LLC.
21901 * Originally Released Under LGPL - original licence link has changed is not relivant.
21904 * <script type="text/javascript">
21909 * @extends Roo.data.Store
21910 * @class Roo.data.JsonStore
21911 * Small helper class to make creating Stores for JSON data easier. <br/>
21913 var store = new Roo.data.JsonStore({
21914 url: 'get-images.php',
21916 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21919 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21920 * JsonReader and HttpProxy (unless inline data is provided).</b>
21921 * @cfg {Array} fields An array of field definition objects, or field name strings.
21923 * @param {Object} config
21925 Roo.data.JsonStore = function(c){
21926 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21927 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21928 reader: new Roo.data.JsonReader(c, c.fields)
21931 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21933 * Ext JS Library 1.1.1
21934 * Copyright(c) 2006-2007, Ext JS, LLC.
21936 * Originally Released Under LGPL - original licence link has changed is not relivant.
21939 * <script type="text/javascript">
21943 Roo.data.Field = function(config){
21944 if(typeof config == "string"){
21945 config = {name: config};
21947 Roo.apply(this, config);
21950 this.type = "auto";
21953 var st = Roo.data.SortTypes;
21954 // named sortTypes are supported, here we look them up
21955 if(typeof this.sortType == "string"){
21956 this.sortType = st[this.sortType];
21959 // set default sortType for strings and dates
21960 if(!this.sortType){
21963 this.sortType = st.asUCString;
21966 this.sortType = st.asDate;
21969 this.sortType = st.none;
21974 var stripRe = /[\$,%]/g;
21976 // prebuilt conversion function for this field, instead of
21977 // switching every time we're reading a value
21979 var cv, dateFormat = this.dateFormat;
21984 cv = function(v){ return v; };
21987 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21991 return v !== undefined && v !== null && v !== '' ?
21992 parseInt(String(v).replace(stripRe, ""), 10) : '';
21997 return v !== undefined && v !== null && v !== '' ?
21998 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22003 cv = function(v){ return v === true || v === "true" || v == 1; };
22010 if(v instanceof Date){
22014 if(dateFormat == "timestamp"){
22015 return new Date(v*1000);
22017 return Date.parseDate(v, dateFormat);
22019 var parsed = Date.parse(v);
22020 return parsed ? new Date(parsed) : null;
22029 Roo.data.Field.prototype = {
22037 * Ext JS Library 1.1.1
22038 * Copyright(c) 2006-2007, Ext JS, LLC.
22040 * Originally Released Under LGPL - original licence link has changed is not relivant.
22043 * <script type="text/javascript">
22046 // Base class for reading structured data from a data source. This class is intended to be
22047 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22050 * @class Roo.data.DataReader
22051 * Base class for reading structured data from a data source. This class is intended to be
22052 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22055 Roo.data.DataReader = function(meta, recordType){
22059 this.recordType = recordType instanceof Array ?
22060 Roo.data.Record.create(recordType) : recordType;
22063 Roo.data.DataReader.prototype = {
22065 * Create an empty record
22066 * @param {Object} data (optional) - overlay some values
22067 * @return {Roo.data.Record} record created.
22069 newRow : function(d) {
22071 this.recordType.prototype.fields.each(function(c) {
22073 case 'int' : da[c.name] = 0; break;
22074 case 'date' : da[c.name] = new Date(); break;
22075 case 'float' : da[c.name] = 0.0; break;
22076 case 'boolean' : da[c.name] = false; break;
22077 default : da[c.name] = ""; break;
22081 return new this.recordType(Roo.apply(da, d));
22086 * Ext JS Library 1.1.1
22087 * Copyright(c) 2006-2007, Ext JS, LLC.
22089 * Originally Released Under LGPL - original licence link has changed is not relivant.
22092 * <script type="text/javascript">
22096 * @class Roo.data.DataProxy
22097 * @extends Roo.data.Observable
22098 * This class is an abstract base class for implementations which provide retrieval of
22099 * unformatted data objects.<br>
22101 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22102 * (of the appropriate type which knows how to parse the data object) to provide a block of
22103 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22105 * Custom implementations must implement the load method as described in
22106 * {@link Roo.data.HttpProxy#load}.
22108 Roo.data.DataProxy = function(){
22111 * @event beforeload
22112 * Fires before a network request is made to retrieve a data object.
22113 * @param {Object} This DataProxy object.
22114 * @param {Object} params The params parameter to the load function.
22119 * Fires before the load method's callback is called.
22120 * @param {Object} This DataProxy object.
22121 * @param {Object} o The data object.
22122 * @param {Object} arg The callback argument object passed to the load function.
22126 * @event loadexception
22127 * Fires if an Exception occurs during data retrieval.
22128 * @param {Object} This DataProxy object.
22129 * @param {Object} o The data object.
22130 * @param {Object} arg The callback argument object passed to the load function.
22131 * @param {Object} e The Exception.
22133 loadexception : true
22135 Roo.data.DataProxy.superclass.constructor.call(this);
22138 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22141 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22145 * Ext JS Library 1.1.1
22146 * Copyright(c) 2006-2007, Ext JS, LLC.
22148 * Originally Released Under LGPL - original licence link has changed is not relivant.
22151 * <script type="text/javascript">
22154 * @class Roo.data.MemoryProxy
22155 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22156 * to the Reader when its load method is called.
22158 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22160 Roo.data.MemoryProxy = function(data){
22164 Roo.data.MemoryProxy.superclass.constructor.call(this);
22168 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22170 * Load data from the requested source (in this case an in-memory
22171 * data object passed to the constructor), read the data object into
22172 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22173 * process that block using the passed callback.
22174 * @param {Object} params This parameter is not used by the MemoryProxy class.
22175 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22176 * object into a block of Roo.data.Records.
22177 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22178 * The function must be passed <ul>
22179 * <li>The Record block object</li>
22180 * <li>The "arg" argument from the load function</li>
22181 * <li>A boolean success indicator</li>
22183 * @param {Object} scope The scope in which to call the callback
22184 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22186 load : function(params, reader, callback, scope, arg){
22187 params = params || {};
22190 result = reader.readRecords(this.data);
22192 this.fireEvent("loadexception", this, arg, null, e);
22193 callback.call(scope, null, arg, false);
22196 callback.call(scope, result, arg, true);
22200 update : function(params, records){
22205 * Ext JS Library 1.1.1
22206 * Copyright(c) 2006-2007, Ext JS, LLC.
22208 * Originally Released Under LGPL - original licence link has changed is not relivant.
22211 * <script type="text/javascript">
22214 * @class Roo.data.HttpProxy
22215 * @extends Roo.data.DataProxy
22216 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22217 * configured to reference a certain URL.<br><br>
22219 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22220 * from which the running page was served.<br><br>
22222 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22224 * Be aware that to enable the browser to parse an XML document, the server must set
22225 * the Content-Type header in the HTTP response to "text/xml".
22227 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22228 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22229 * will be used to make the request.
22231 Roo.data.HttpProxy = function(conn){
22232 Roo.data.HttpProxy.superclass.constructor.call(this);
22233 // is conn a conn config or a real conn?
22235 this.useAjax = !conn || !conn.events;
22239 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22240 // thse are take from connection...
22243 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22246 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22247 * extra parameters to each request made by this object. (defaults to undefined)
22250 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22251 * to each request made by this object. (defaults to undefined)
22254 * @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)
22257 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22260 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22266 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22270 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22271 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22272 * a finer-grained basis than the DataProxy events.
22274 getConnection : function(){
22275 return this.useAjax ? Roo.Ajax : this.conn;
22279 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22280 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22281 * process that block using the passed callback.
22282 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22283 * for the request to the remote server.
22284 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22285 * object into a block of Roo.data.Records.
22286 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22287 * The function must be passed <ul>
22288 * <li>The Record block object</li>
22289 * <li>The "arg" argument from the load function</li>
22290 * <li>A boolean success indicator</li>
22292 * @param {Object} scope The scope in which to call the callback
22293 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22295 load : function(params, reader, callback, scope, arg){
22296 if(this.fireEvent("beforeload", this, params) !== false){
22298 params : params || {},
22300 callback : callback,
22305 callback : this.loadResponse,
22309 Roo.applyIf(o, this.conn);
22310 if(this.activeRequest){
22311 Roo.Ajax.abort(this.activeRequest);
22313 this.activeRequest = Roo.Ajax.request(o);
22315 this.conn.request(o);
22318 callback.call(scope||this, null, arg, false);
22323 loadResponse : function(o, success, response){
22324 delete this.activeRequest;
22326 this.fireEvent("loadexception", this, o, response);
22327 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22332 result = o.reader.read(response);
22334 this.fireEvent("loadexception", this, o, response, e);
22335 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22339 this.fireEvent("load", this, o, o.request.arg);
22340 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22344 update : function(dataSet){
22349 updateResponse : function(dataSet){
22354 * Ext JS Library 1.1.1
22355 * Copyright(c) 2006-2007, Ext JS, LLC.
22357 * Originally Released Under LGPL - original licence link has changed is not relivant.
22360 * <script type="text/javascript">
22364 * @class Roo.data.ScriptTagProxy
22365 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22366 * other than the originating domain of the running page.<br><br>
22368 * <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
22369 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22371 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22372 * source code that is used as the source inside a <script> tag.<br><br>
22374 * In order for the browser to process the returned data, the server must wrap the data object
22375 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22376 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22377 * depending on whether the callback name was passed:
22380 boolean scriptTag = false;
22381 String cb = request.getParameter("callback");
22384 response.setContentType("text/javascript");
22386 response.setContentType("application/x-json");
22388 Writer out = response.getWriter();
22390 out.write(cb + "(");
22392 out.print(dataBlock.toJsonString());
22399 * @param {Object} config A configuration object.
22401 Roo.data.ScriptTagProxy = function(config){
22402 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22403 Roo.apply(this, config);
22404 this.head = document.getElementsByTagName("head")[0];
22407 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22409 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22411 * @cfg {String} url The URL from which to request the data object.
22414 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22418 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22419 * the server the name of the callback function set up by the load call to process the returned data object.
22420 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22421 * javascript output which calls this named function passing the data object as its only parameter.
22423 callbackParam : "callback",
22425 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22426 * name to the request.
22431 * Load data from the configured URL, read the data object into
22432 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22433 * process that block using the passed callback.
22434 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22435 * for the request to the remote server.
22436 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22437 * object into a block of Roo.data.Records.
22438 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22439 * The function must be passed <ul>
22440 * <li>The Record block object</li>
22441 * <li>The "arg" argument from the load function</li>
22442 * <li>A boolean success indicator</li>
22444 * @param {Object} scope The scope in which to call the callback
22445 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22447 load : function(params, reader, callback, scope, arg){
22448 if(this.fireEvent("beforeload", this, params) !== false){
22450 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22452 var url = this.url;
22453 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22455 url += "&_dc=" + (new Date().getTime());
22457 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22460 cb : "stcCallback"+transId,
22461 scriptId : "stcScript"+transId,
22465 callback : callback,
22471 window[trans.cb] = function(o){
22472 conn.handleResponse(o, trans);
22475 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22477 if(this.autoAbort !== false){
22481 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22483 var script = document.createElement("script");
22484 script.setAttribute("src", url);
22485 script.setAttribute("type", "text/javascript");
22486 script.setAttribute("id", trans.scriptId);
22487 this.head.appendChild(script);
22489 this.trans = trans;
22491 callback.call(scope||this, null, arg, false);
22496 isLoading : function(){
22497 return this.trans ? true : false;
22501 * Abort the current server request.
22503 abort : function(){
22504 if(this.isLoading()){
22505 this.destroyTrans(this.trans);
22510 destroyTrans : function(trans, isLoaded){
22511 this.head.removeChild(document.getElementById(trans.scriptId));
22512 clearTimeout(trans.timeoutId);
22514 window[trans.cb] = undefined;
22516 delete window[trans.cb];
22519 // if hasn't been loaded, wait for load to remove it to prevent script error
22520 window[trans.cb] = function(){
22521 window[trans.cb] = undefined;
22523 delete window[trans.cb];
22530 handleResponse : function(o, trans){
22531 this.trans = false;
22532 this.destroyTrans(trans, true);
22535 result = trans.reader.readRecords(o);
22537 this.fireEvent("loadexception", this, o, trans.arg, e);
22538 trans.callback.call(trans.scope||window, null, trans.arg, false);
22541 this.fireEvent("load", this, o, trans.arg);
22542 trans.callback.call(trans.scope||window, result, trans.arg, true);
22546 handleFailure : function(trans){
22547 this.trans = false;
22548 this.destroyTrans(trans, false);
22549 this.fireEvent("loadexception", this, null, trans.arg);
22550 trans.callback.call(trans.scope||window, null, trans.arg, false);
22554 * Ext JS Library 1.1.1
22555 * Copyright(c) 2006-2007, Ext JS, LLC.
22557 * Originally Released Under LGPL - original licence link has changed is not relivant.
22560 * <script type="text/javascript">
22564 * @class Roo.data.JsonReader
22565 * @extends Roo.data.DataReader
22566 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22567 * based on mappings in a provided Roo.data.Record constructor.
22569 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22570 * in the reply previously.
22575 var RecordDef = Roo.data.Record.create([
22576 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22577 {name: 'occupation'} // This field will use "occupation" as the mapping.
22579 var myReader = new Roo.data.JsonReader({
22580 totalProperty: "results", // The property which contains the total dataset size (optional)
22581 root: "rows", // The property which contains an Array of row objects
22582 id: "id" // The property within each row object that provides an ID for the record (optional)
22586 * This would consume a JSON file like this:
22588 { 'results': 2, 'rows': [
22589 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22590 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22593 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22594 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22595 * paged from the remote server.
22596 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22597 * @cfg {String} root name of the property which contains the Array of row objects.
22598 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22600 * Create a new JsonReader
22601 * @param {Object} meta Metadata configuration options
22602 * @param {Object} recordType Either an Array of field definition objects,
22603 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22605 Roo.data.JsonReader = function(meta, recordType){
22608 // set some defaults:
22609 Roo.applyIf(meta, {
22610 totalProperty: 'total',
22611 successProperty : 'success',
22616 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22618 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22621 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22622 * Used by Store query builder to append _requestMeta to params.
22625 metaFromRemote : false,
22627 * This method is only used by a DataProxy which has retrieved data from a remote server.
22628 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22629 * @return {Object} data A data block which is used by an Roo.data.Store object as
22630 * a cache of Roo.data.Records.
22632 read : function(response){
22633 var json = response.responseText;
22635 var o = /* eval:var:o */ eval("("+json+")");
22637 throw {message: "JsonReader.read: Json object not found"};
22643 this.metaFromRemote = true;
22644 this.meta = o.metaData;
22645 this.recordType = Roo.data.Record.create(o.metaData.fields);
22646 this.onMetaChange(this.meta, this.recordType, o);
22648 return this.readRecords(o);
22651 // private function a store will implement
22652 onMetaChange : function(meta, recordType, o){
22659 simpleAccess: function(obj, subsc) {
22666 getJsonAccessor: function(){
22668 return function(expr) {
22670 return(re.test(expr))
22671 ? new Function("obj", "return obj." + expr)
22676 return Roo.emptyFn;
22681 * Create a data block containing Roo.data.Records from an XML document.
22682 * @param {Object} o An object which contains an Array of row objects in the property specified
22683 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22684 * which contains the total size of the dataset.
22685 * @return {Object} data A data block which is used by an Roo.data.Store object as
22686 * a cache of Roo.data.Records.
22688 readRecords : function(o){
22690 * After any data loads, the raw JSON data is available for further custom processing.
22694 var s = this.meta, Record = this.recordType,
22695 f = Record.prototype.fields, fi = f.items, fl = f.length;
22697 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22699 if(s.totalProperty) {
22700 this.getTotal = this.getJsonAccessor(s.totalProperty);
22702 if(s.successProperty) {
22703 this.getSuccess = this.getJsonAccessor(s.successProperty);
22705 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22707 var g = this.getJsonAccessor(s.id);
22708 this.getId = function(rec) {
22710 return (r === undefined || r === "") ? null : r;
22713 this.getId = function(){return null;};
22716 for(var jj = 0; jj < fl; jj++){
22718 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22719 this.ef[jj] = this.getJsonAccessor(map);
22723 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22724 if(s.totalProperty){
22725 var vt = parseInt(this.getTotal(o), 10);
22730 if(s.successProperty){
22731 var vs = this.getSuccess(o);
22732 if(vs === false || vs === 'false'){
22737 for(var i = 0; i < c; i++){
22740 var id = this.getId(n);
22741 for(var j = 0; j < fl; j++){
22743 var v = this.ef[j](n);
22745 Roo.log('missing convert for ' + f.name);
22749 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22751 var record = new Record(values, id);
22753 records[i] = record;
22759 totalRecords : totalRecords
22764 * Ext JS Library 1.1.1
22765 * Copyright(c) 2006-2007, Ext JS, LLC.
22767 * Originally Released Under LGPL - original licence link has changed is not relivant.
22770 * <script type="text/javascript">
22774 * @class Roo.data.XmlReader
22775 * @extends Roo.data.DataReader
22776 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22777 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22779 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22780 * header in the HTTP response must be set to "text/xml".</em>
22784 var RecordDef = Roo.data.Record.create([
22785 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22786 {name: 'occupation'} // This field will use "occupation" as the mapping.
22788 var myReader = new Roo.data.XmlReader({
22789 totalRecords: "results", // The element which contains the total dataset size (optional)
22790 record: "row", // The repeated element which contains row information
22791 id: "id" // The element within the row that provides an ID for the record (optional)
22795 * This would consume an XML file like this:
22799 <results>2</results>
22802 <name>Bill</name>
22803 <occupation>Gardener</occupation>
22807 <name>Ben</name>
22808 <occupation>Horticulturalist</occupation>
22812 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22813 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22814 * paged from the remote server.
22815 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22816 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22817 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22818 * a record identifier value.
22820 * Create a new XmlReader
22821 * @param {Object} meta Metadata configuration options
22822 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22823 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22824 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22826 Roo.data.XmlReader = function(meta, recordType){
22828 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22830 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22832 * This method is only used by a DataProxy which has retrieved data from a remote server.
22833 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22834 * to contain a method called 'responseXML' that returns an XML document object.
22835 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22836 * a cache of Roo.data.Records.
22838 read : function(response){
22839 var doc = response.responseXML;
22841 throw {message: "XmlReader.read: XML Document not available"};
22843 return this.readRecords(doc);
22847 * Create a data block containing Roo.data.Records from an XML document.
22848 * @param {Object} doc A parsed XML document.
22849 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22850 * a cache of Roo.data.Records.
22852 readRecords : function(doc){
22854 * After any data loads/reads, the raw XML Document is available for further custom processing.
22855 * @type XMLDocument
22857 this.xmlData = doc;
22858 var root = doc.documentElement || doc;
22859 var q = Roo.DomQuery;
22860 var recordType = this.recordType, fields = recordType.prototype.fields;
22861 var sid = this.meta.id;
22862 var totalRecords = 0, success = true;
22863 if(this.meta.totalRecords){
22864 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22867 if(this.meta.success){
22868 var sv = q.selectValue(this.meta.success, root, true);
22869 success = sv !== false && sv !== 'false';
22872 var ns = q.select(this.meta.record, root);
22873 for(var i = 0, len = ns.length; i < len; i++) {
22876 var id = sid ? q.selectValue(sid, n) : undefined;
22877 for(var j = 0, jlen = fields.length; j < jlen; j++){
22878 var f = fields.items[j];
22879 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22881 values[f.name] = v;
22883 var record = new recordType(values, id);
22885 records[records.length] = record;
22891 totalRecords : totalRecords || records.length
22896 * Ext JS Library 1.1.1
22897 * Copyright(c) 2006-2007, Ext JS, LLC.
22899 * Originally Released Under LGPL - original licence link has changed is not relivant.
22902 * <script type="text/javascript">
22906 * @class Roo.data.ArrayReader
22907 * @extends Roo.data.DataReader
22908 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22909 * Each element of that Array represents a row of data fields. The
22910 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22911 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22915 var RecordDef = Roo.data.Record.create([
22916 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22917 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22919 var myReader = new Roo.data.ArrayReader({
22920 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22924 * This would consume an Array like this:
22926 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22928 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22930 * Create a new JsonReader
22931 * @param {Object} meta Metadata configuration options.
22932 * @param {Object} recordType Either an Array of field definition objects
22933 * as specified to {@link Roo.data.Record#create},
22934 * or an {@link Roo.data.Record} object
22935 * created using {@link Roo.data.Record#create}.
22937 Roo.data.ArrayReader = function(meta, recordType){
22938 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22941 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22943 * Create a data block containing Roo.data.Records from an XML document.
22944 * @param {Object} o An Array of row objects which represents the dataset.
22945 * @return {Object} data A data block which is used by an Roo.data.Store object as
22946 * a cache of Roo.data.Records.
22948 readRecords : function(o){
22949 var sid = this.meta ? this.meta.id : null;
22950 var recordType = this.recordType, fields = recordType.prototype.fields;
22953 for(var i = 0; i < root.length; i++){
22956 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22957 for(var j = 0, jlen = fields.length; j < jlen; j++){
22958 var f = fields.items[j];
22959 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22960 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22962 values[f.name] = v;
22964 var record = new recordType(values, id);
22966 records[records.length] = record;
22970 totalRecords : records.length
22975 * Ext JS Library 1.1.1
22976 * Copyright(c) 2006-2007, Ext JS, LLC.
22978 * Originally Released Under LGPL - original licence link has changed is not relivant.
22981 * <script type="text/javascript">
22986 * @class Roo.data.Tree
22987 * @extends Roo.util.Observable
22988 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22989 * in the tree have most standard DOM functionality.
22991 * @param {Node} root (optional) The root node
22993 Roo.data.Tree = function(root){
22994 this.nodeHash = {};
22996 * The root node for this tree
23001 this.setRootNode(root);
23006 * Fires when a new child node is appended to a node in this tree.
23007 * @param {Tree} tree The owner tree
23008 * @param {Node} parent The parent node
23009 * @param {Node} node The newly appended node
23010 * @param {Number} index The index of the newly appended node
23015 * Fires when a child node is removed from a node in this tree.
23016 * @param {Tree} tree The owner tree
23017 * @param {Node} parent The parent node
23018 * @param {Node} node The child node removed
23023 * Fires when a node is moved to a new location in the tree
23024 * @param {Tree} tree The owner tree
23025 * @param {Node} node The node moved
23026 * @param {Node} oldParent The old parent of this node
23027 * @param {Node} newParent The new parent of this node
23028 * @param {Number} index The index it was moved to
23033 * Fires when a new child node is inserted in a node in this tree.
23034 * @param {Tree} tree The owner tree
23035 * @param {Node} parent The parent node
23036 * @param {Node} node The child node inserted
23037 * @param {Node} refNode The child node the node was inserted before
23041 * @event beforeappend
23042 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23043 * @param {Tree} tree The owner tree
23044 * @param {Node} parent The parent node
23045 * @param {Node} node The child node to be appended
23047 "beforeappend" : true,
23049 * @event beforeremove
23050 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23051 * @param {Tree} tree The owner tree
23052 * @param {Node} parent The parent node
23053 * @param {Node} node The child node to be removed
23055 "beforeremove" : true,
23057 * @event beforemove
23058 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23059 * @param {Tree} tree The owner tree
23060 * @param {Node} node The node being moved
23061 * @param {Node} oldParent The parent of the node
23062 * @param {Node} newParent The new parent the node is moving to
23063 * @param {Number} index The index it is being moved to
23065 "beforemove" : true,
23067 * @event beforeinsert
23068 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23069 * @param {Tree} tree The owner tree
23070 * @param {Node} parent The parent node
23071 * @param {Node} node The child node to be inserted
23072 * @param {Node} refNode The child node the node is being inserted before
23074 "beforeinsert" : true
23077 Roo.data.Tree.superclass.constructor.call(this);
23080 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23081 pathSeparator: "/",
23083 proxyNodeEvent : function(){
23084 return this.fireEvent.apply(this, arguments);
23088 * Returns the root node for this tree.
23091 getRootNode : function(){
23096 * Sets the root node for this tree.
23097 * @param {Node} node
23100 setRootNode : function(node){
23102 node.ownerTree = this;
23103 node.isRoot = true;
23104 this.registerNode(node);
23109 * Gets a node in this tree by its id.
23110 * @param {String} id
23113 getNodeById : function(id){
23114 return this.nodeHash[id];
23117 registerNode : function(node){
23118 this.nodeHash[node.id] = node;
23121 unregisterNode : function(node){
23122 delete this.nodeHash[node.id];
23125 toString : function(){
23126 return "[Tree"+(this.id?" "+this.id:"")+"]";
23131 * @class Roo.data.Node
23132 * @extends Roo.util.Observable
23133 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23134 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23136 * @param {Object} attributes The attributes/config for the node
23138 Roo.data.Node = function(attributes){
23140 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23143 this.attributes = attributes || {};
23144 this.leaf = this.attributes.leaf;
23146 * The node id. @type String
23148 this.id = this.attributes.id;
23150 this.id = Roo.id(null, "ynode-");
23151 this.attributes.id = this.id;
23156 * All child nodes of this node. @type Array
23158 this.childNodes = [];
23159 if(!this.childNodes.indexOf){ // indexOf is a must
23160 this.childNodes.indexOf = function(o){
23161 for(var i = 0, len = this.length; i < len; i++){
23170 * The parent node for this node. @type Node
23172 this.parentNode = null;
23174 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23176 this.firstChild = null;
23178 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23180 this.lastChild = null;
23182 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23184 this.previousSibling = null;
23186 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23188 this.nextSibling = null;
23193 * Fires when a new child node is appended
23194 * @param {Tree} tree The owner tree
23195 * @param {Node} this This node
23196 * @param {Node} node The newly appended node
23197 * @param {Number} index The index of the newly appended node
23202 * Fires when a child node is removed
23203 * @param {Tree} tree The owner tree
23204 * @param {Node} this This node
23205 * @param {Node} node The removed node
23210 * Fires when this node is moved to a new location in the tree
23211 * @param {Tree} tree The owner tree
23212 * @param {Node} this This node
23213 * @param {Node} oldParent The old parent of this node
23214 * @param {Node} newParent The new parent of this node
23215 * @param {Number} index The index it was moved to
23220 * Fires when a new child node is inserted.
23221 * @param {Tree} tree The owner tree
23222 * @param {Node} this This node
23223 * @param {Node} node The child node inserted
23224 * @param {Node} refNode The child node the node was inserted before
23228 * @event beforeappend
23229 * Fires before a new child is appended, return false to cancel the append.
23230 * @param {Tree} tree The owner tree
23231 * @param {Node} this This node
23232 * @param {Node} node The child node to be appended
23234 "beforeappend" : true,
23236 * @event beforeremove
23237 * Fires before a child is removed, return false to cancel the remove.
23238 * @param {Tree} tree The owner tree
23239 * @param {Node} this This node
23240 * @param {Node} node The child node to be removed
23242 "beforeremove" : true,
23244 * @event beforemove
23245 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23246 * @param {Tree} tree The owner tree
23247 * @param {Node} this This node
23248 * @param {Node} oldParent The parent of this node
23249 * @param {Node} newParent The new parent this node is moving to
23250 * @param {Number} index The index it is being moved to
23252 "beforemove" : true,
23254 * @event beforeinsert
23255 * Fires before a new child is inserted, return false to cancel the insert.
23256 * @param {Tree} tree The owner tree
23257 * @param {Node} this This node
23258 * @param {Node} node The child node to be inserted
23259 * @param {Node} refNode The child node the node is being inserted before
23261 "beforeinsert" : true
23263 this.listeners = this.attributes.listeners;
23264 Roo.data.Node.superclass.constructor.call(this);
23267 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23268 fireEvent : function(evtName){
23269 // first do standard event for this node
23270 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23273 // then bubble it up to the tree if the event wasn't cancelled
23274 var ot = this.getOwnerTree();
23276 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23284 * Returns true if this node is a leaf
23285 * @return {Boolean}
23287 isLeaf : function(){
23288 return this.leaf === true;
23292 setFirstChild : function(node){
23293 this.firstChild = node;
23297 setLastChild : function(node){
23298 this.lastChild = node;
23303 * Returns true if this node is the last child of its parent
23304 * @return {Boolean}
23306 isLast : function(){
23307 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23311 * Returns true if this node is the first child of its parent
23312 * @return {Boolean}
23314 isFirst : function(){
23315 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23318 hasChildNodes : function(){
23319 return !this.isLeaf() && this.childNodes.length > 0;
23323 * Insert node(s) as the last child node of this node.
23324 * @param {Node/Array} node The node or Array of nodes to append
23325 * @return {Node} The appended node if single append, or null if an array was passed
23327 appendChild : function(node){
23329 if(node instanceof Array){
23331 }else if(arguments.length > 1){
23334 // if passed an array or multiple args do them one by one
23336 for(var i = 0, len = multi.length; i < len; i++) {
23337 this.appendChild(multi[i]);
23340 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23343 var index = this.childNodes.length;
23344 var oldParent = node.parentNode;
23345 // it's a move, make sure we move it cleanly
23347 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23350 oldParent.removeChild(node);
23352 index = this.childNodes.length;
23354 this.setFirstChild(node);
23356 this.childNodes.push(node);
23357 node.parentNode = this;
23358 var ps = this.childNodes[index-1];
23360 node.previousSibling = ps;
23361 ps.nextSibling = node;
23363 node.previousSibling = null;
23365 node.nextSibling = null;
23366 this.setLastChild(node);
23367 node.setOwnerTree(this.getOwnerTree());
23368 this.fireEvent("append", this.ownerTree, this, node, index);
23370 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23377 * Removes a child node from this node.
23378 * @param {Node} node The node to remove
23379 * @return {Node} The removed node
23381 removeChild : function(node){
23382 var index = this.childNodes.indexOf(node);
23386 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23390 // remove it from childNodes collection
23391 this.childNodes.splice(index, 1);
23394 if(node.previousSibling){
23395 node.previousSibling.nextSibling = node.nextSibling;
23397 if(node.nextSibling){
23398 node.nextSibling.previousSibling = node.previousSibling;
23401 // update child refs
23402 if(this.firstChild == node){
23403 this.setFirstChild(node.nextSibling);
23405 if(this.lastChild == node){
23406 this.setLastChild(node.previousSibling);
23409 node.setOwnerTree(null);
23410 // clear any references from the node
23411 node.parentNode = null;
23412 node.previousSibling = null;
23413 node.nextSibling = null;
23414 this.fireEvent("remove", this.ownerTree, this, node);
23419 * Inserts the first node before the second node in this nodes childNodes collection.
23420 * @param {Node} node The node to insert
23421 * @param {Node} refNode The node to insert before (if null the node is appended)
23422 * @return {Node} The inserted node
23424 insertBefore : function(node, refNode){
23425 if(!refNode){ // like standard Dom, refNode can be null for append
23426 return this.appendChild(node);
23429 if(node == refNode){
23433 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23436 var index = this.childNodes.indexOf(refNode);
23437 var oldParent = node.parentNode;
23438 var refIndex = index;
23440 // when moving internally, indexes will change after remove
23441 if(oldParent == this && this.childNodes.indexOf(node) < index){
23445 // it's a move, make sure we move it cleanly
23447 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23450 oldParent.removeChild(node);
23453 this.setFirstChild(node);
23455 this.childNodes.splice(refIndex, 0, node);
23456 node.parentNode = this;
23457 var ps = this.childNodes[refIndex-1];
23459 node.previousSibling = ps;
23460 ps.nextSibling = node;
23462 node.previousSibling = null;
23464 node.nextSibling = refNode;
23465 refNode.previousSibling = node;
23466 node.setOwnerTree(this.getOwnerTree());
23467 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23469 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23475 * Returns the child node at the specified index.
23476 * @param {Number} index
23479 item : function(index){
23480 return this.childNodes[index];
23484 * Replaces one child node in this node with another.
23485 * @param {Node} newChild The replacement node
23486 * @param {Node} oldChild The node to replace
23487 * @return {Node} The replaced node
23489 replaceChild : function(newChild, oldChild){
23490 this.insertBefore(newChild, oldChild);
23491 this.removeChild(oldChild);
23496 * Returns the index of a child node
23497 * @param {Node} node
23498 * @return {Number} The index of the node or -1 if it was not found
23500 indexOf : function(child){
23501 return this.childNodes.indexOf(child);
23505 * Returns the tree this node is in.
23508 getOwnerTree : function(){
23509 // if it doesn't have one, look for one
23510 if(!this.ownerTree){
23514 this.ownerTree = p.ownerTree;
23520 return this.ownerTree;
23524 * Returns depth of this node (the root node has a depth of 0)
23527 getDepth : function(){
23530 while(p.parentNode){
23538 setOwnerTree : function(tree){
23539 // if it's move, we need to update everyone
23540 if(tree != this.ownerTree){
23541 if(this.ownerTree){
23542 this.ownerTree.unregisterNode(this);
23544 this.ownerTree = tree;
23545 var cs = this.childNodes;
23546 for(var i = 0, len = cs.length; i < len; i++) {
23547 cs[i].setOwnerTree(tree);
23550 tree.registerNode(this);
23556 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23557 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23558 * @return {String} The path
23560 getPath : function(attr){
23561 attr = attr || "id";
23562 var p = this.parentNode;
23563 var b = [this.attributes[attr]];
23565 b.unshift(p.attributes[attr]);
23568 var sep = this.getOwnerTree().pathSeparator;
23569 return sep + b.join(sep);
23573 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23574 * function call will be the scope provided or the current node. The arguments to the function
23575 * will be the args provided or the current node. If the function returns false at any point,
23576 * the bubble is stopped.
23577 * @param {Function} fn The function to call
23578 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23579 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23581 bubble : function(fn, scope, args){
23584 if(fn.call(scope || p, args || p) === false){
23592 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23593 * function call will be the scope provided or the current node. The arguments to the function
23594 * will be the args provided or the current node. If the function returns false at any point,
23595 * the cascade is stopped on that branch.
23596 * @param {Function} fn The function to call
23597 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23598 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23600 cascade : function(fn, scope, args){
23601 if(fn.call(scope || this, args || this) !== false){
23602 var cs = this.childNodes;
23603 for(var i = 0, len = cs.length; i < len; i++) {
23604 cs[i].cascade(fn, scope, args);
23610 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23611 * function call will be the scope provided or the current node. The arguments to the function
23612 * will be the args provided or the current node. If the function returns false at any point,
23613 * the iteration stops.
23614 * @param {Function} fn The function to call
23615 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23616 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23618 eachChild : function(fn, scope, args){
23619 var cs = this.childNodes;
23620 for(var i = 0, len = cs.length; i < len; i++) {
23621 if(fn.call(scope || this, args || cs[i]) === false){
23628 * Finds the first child that has the attribute with the specified value.
23629 * @param {String} attribute The attribute name
23630 * @param {Mixed} value The value to search for
23631 * @return {Node} The found child or null if none was found
23633 findChild : function(attribute, value){
23634 var cs = this.childNodes;
23635 for(var i = 0, len = cs.length; i < len; i++) {
23636 if(cs[i].attributes[attribute] == value){
23644 * Finds the first child by a custom function. The child matches if the function passed
23646 * @param {Function} fn
23647 * @param {Object} scope (optional)
23648 * @return {Node} The found child or null if none was found
23650 findChildBy : function(fn, scope){
23651 var cs = this.childNodes;
23652 for(var i = 0, len = cs.length; i < len; i++) {
23653 if(fn.call(scope||cs[i], cs[i]) === true){
23661 * Sorts this nodes children using the supplied sort function
23662 * @param {Function} fn
23663 * @param {Object} scope (optional)
23665 sort : function(fn, scope){
23666 var cs = this.childNodes;
23667 var len = cs.length;
23669 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23671 for(var i = 0; i < len; i++){
23673 n.previousSibling = cs[i-1];
23674 n.nextSibling = cs[i+1];
23676 this.setFirstChild(n);
23679 this.setLastChild(n);
23686 * Returns true if this node is an ancestor (at any point) of the passed node.
23687 * @param {Node} node
23688 * @return {Boolean}
23690 contains : function(node){
23691 return node.isAncestor(this);
23695 * Returns true if the passed node is an ancestor (at any point) of this node.
23696 * @param {Node} node
23697 * @return {Boolean}
23699 isAncestor : function(node){
23700 var p = this.parentNode;
23710 toString : function(){
23711 return "[Node"+(this.id?" "+this.id:"")+"]";
23715 * Ext JS Library 1.1.1
23716 * Copyright(c) 2006-2007, Ext JS, LLC.
23718 * Originally Released Under LGPL - original licence link has changed is not relivant.
23721 * <script type="text/javascript">
23726 * @extends Roo.Element
23727 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23728 * automatic maintaining of shadow/shim positions.
23729 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23730 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23731 * you can pass a string with a CSS class name. False turns off the shadow.
23732 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23733 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23734 * @cfg {String} cls CSS class to add to the element
23735 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23736 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23738 * @param {Object} config An object with config options.
23739 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23742 Roo.Layer = function(config, existingEl){
23743 config = config || {};
23744 var dh = Roo.DomHelper;
23745 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23747 this.dom = Roo.getDom(existingEl);
23750 var o = config.dh || {tag: "div", cls: "x-layer"};
23751 this.dom = dh.append(pel, o);
23754 this.addClass(config.cls);
23756 this.constrain = config.constrain !== false;
23757 this.visibilityMode = Roo.Element.VISIBILITY;
23759 this.id = this.dom.id = config.id;
23761 this.id = Roo.id(this.dom);
23763 this.zindex = config.zindex || this.getZIndex();
23764 this.position("absolute", this.zindex);
23766 this.shadowOffset = config.shadowOffset || 4;
23767 this.shadow = new Roo.Shadow({
23768 offset : this.shadowOffset,
23769 mode : config.shadow
23772 this.shadowOffset = 0;
23774 this.useShim = config.shim !== false && Roo.useShims;
23775 this.useDisplay = config.useDisplay;
23779 var supr = Roo.Element.prototype;
23781 // shims are shared among layer to keep from having 100 iframes
23784 Roo.extend(Roo.Layer, Roo.Element, {
23786 getZIndex : function(){
23787 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23790 getShim : function(){
23797 var shim = shims.shift();
23799 shim = this.createShim();
23800 shim.enableDisplayMode('block');
23801 shim.dom.style.display = 'none';
23802 shim.dom.style.visibility = 'visible';
23804 var pn = this.dom.parentNode;
23805 if(shim.dom.parentNode != pn){
23806 pn.insertBefore(shim.dom, this.dom);
23808 shim.setStyle('z-index', this.getZIndex()-2);
23813 hideShim : function(){
23815 this.shim.setDisplayed(false);
23816 shims.push(this.shim);
23821 disableShadow : function(){
23823 this.shadowDisabled = true;
23824 this.shadow.hide();
23825 this.lastShadowOffset = this.shadowOffset;
23826 this.shadowOffset = 0;
23830 enableShadow : function(show){
23832 this.shadowDisabled = false;
23833 this.shadowOffset = this.lastShadowOffset;
23834 delete this.lastShadowOffset;
23842 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23843 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23844 sync : function(doShow){
23845 var sw = this.shadow;
23846 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23847 var sh = this.getShim();
23849 var w = this.getWidth(),
23850 h = this.getHeight();
23852 var l = this.getLeft(true),
23853 t = this.getTop(true);
23855 if(sw && !this.shadowDisabled){
23856 if(doShow && !sw.isVisible()){
23859 sw.realign(l, t, w, h);
23865 // fit the shim behind the shadow, so it is shimmed too
23866 var a = sw.adjusts, s = sh.dom.style;
23867 s.left = (Math.min(l, l+a.l))+"px";
23868 s.top = (Math.min(t, t+a.t))+"px";
23869 s.width = (w+a.w)+"px";
23870 s.height = (h+a.h)+"px";
23877 sh.setLeftTop(l, t);
23884 destroy : function(){
23887 this.shadow.hide();
23889 this.removeAllListeners();
23890 var pn = this.dom.parentNode;
23892 pn.removeChild(this.dom);
23894 Roo.Element.uncache(this.id);
23897 remove : function(){
23902 beginUpdate : function(){
23903 this.updating = true;
23907 endUpdate : function(){
23908 this.updating = false;
23913 hideUnders : function(negOffset){
23915 this.shadow.hide();
23921 constrainXY : function(){
23922 if(this.constrain){
23923 var vw = Roo.lib.Dom.getViewWidth(),
23924 vh = Roo.lib.Dom.getViewHeight();
23925 var s = Roo.get(document).getScroll();
23927 var xy = this.getXY();
23928 var x = xy[0], y = xy[1];
23929 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23930 // only move it if it needs it
23932 // first validate right/bottom
23933 if((x + w) > vw+s.left){
23934 x = vw - w - this.shadowOffset;
23937 if((y + h) > vh+s.top){
23938 y = vh - h - this.shadowOffset;
23941 // then make sure top/left isn't negative
23952 var ay = this.avoidY;
23953 if(y <= ay && (y+h) >= ay){
23959 supr.setXY.call(this, xy);
23965 isVisible : function(){
23966 return this.visible;
23970 showAction : function(){
23971 this.visible = true; // track visibility to prevent getStyle calls
23972 if(this.useDisplay === true){
23973 this.setDisplayed("");
23974 }else if(this.lastXY){
23975 supr.setXY.call(this, this.lastXY);
23976 }else if(this.lastLT){
23977 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23982 hideAction : function(){
23983 this.visible = false;
23984 if(this.useDisplay === true){
23985 this.setDisplayed(false);
23987 this.setLeftTop(-10000,-10000);
23991 // overridden Element method
23992 setVisible : function(v, a, d, c, e){
23997 var cb = function(){
24002 }.createDelegate(this);
24003 supr.setVisible.call(this, true, true, d, cb, e);
24006 this.hideUnders(true);
24015 }.createDelegate(this);
24017 supr.setVisible.call(this, v, a, d, cb, e);
24026 storeXY : function(xy){
24027 delete this.lastLT;
24031 storeLeftTop : function(left, top){
24032 delete this.lastXY;
24033 this.lastLT = [left, top];
24037 beforeFx : function(){
24038 this.beforeAction();
24039 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24043 afterFx : function(){
24044 Roo.Layer.superclass.afterFx.apply(this, arguments);
24045 this.sync(this.isVisible());
24049 beforeAction : function(){
24050 if(!this.updating && this.shadow){
24051 this.shadow.hide();
24055 // overridden Element method
24056 setLeft : function(left){
24057 this.storeLeftTop(left, this.getTop(true));
24058 supr.setLeft.apply(this, arguments);
24062 setTop : function(top){
24063 this.storeLeftTop(this.getLeft(true), top);
24064 supr.setTop.apply(this, arguments);
24068 setLeftTop : function(left, top){
24069 this.storeLeftTop(left, top);
24070 supr.setLeftTop.apply(this, arguments);
24074 setXY : function(xy, a, d, c, e){
24076 this.beforeAction();
24078 var cb = this.createCB(c);
24079 supr.setXY.call(this, xy, a, d, cb, e);
24086 createCB : function(c){
24097 // overridden Element method
24098 setX : function(x, a, d, c, e){
24099 this.setXY([x, this.getY()], a, d, c, e);
24102 // overridden Element method
24103 setY : function(y, a, d, c, e){
24104 this.setXY([this.getX(), y], a, d, c, e);
24107 // overridden Element method
24108 setSize : function(w, h, a, d, c, e){
24109 this.beforeAction();
24110 var cb = this.createCB(c);
24111 supr.setSize.call(this, w, h, a, d, cb, e);
24117 // overridden Element method
24118 setWidth : function(w, a, d, c, e){
24119 this.beforeAction();
24120 var cb = this.createCB(c);
24121 supr.setWidth.call(this, w, a, d, cb, e);
24127 // overridden Element method
24128 setHeight : function(h, a, d, c, e){
24129 this.beforeAction();
24130 var cb = this.createCB(c);
24131 supr.setHeight.call(this, h, a, d, cb, e);
24137 // overridden Element method
24138 setBounds : function(x, y, w, h, a, d, c, e){
24139 this.beforeAction();
24140 var cb = this.createCB(c);
24142 this.storeXY([x, y]);
24143 supr.setXY.call(this, [x, y]);
24144 supr.setSize.call(this, w, h, a, d, cb, e);
24147 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24153 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24154 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24155 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24156 * @param {Number} zindex The new z-index to set
24157 * @return {this} The Layer
24159 setZIndex : function(zindex){
24160 this.zindex = zindex;
24161 this.setStyle("z-index", zindex + 2);
24163 this.shadow.setZIndex(zindex + 1);
24166 this.shim.setStyle("z-index", zindex);
24172 * Ext JS Library 1.1.1
24173 * Copyright(c) 2006-2007, Ext JS, LLC.
24175 * Originally Released Under LGPL - original licence link has changed is not relivant.
24178 * <script type="text/javascript">
24183 * @class Roo.Shadow
24184 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24185 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24186 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24188 * Create a new Shadow
24189 * @param {Object} config The config object
24191 Roo.Shadow = function(config){
24192 Roo.apply(this, config);
24193 if(typeof this.mode != "string"){
24194 this.mode = this.defaultMode;
24196 var o = this.offset, a = {h: 0};
24197 var rad = Math.floor(this.offset/2);
24198 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24204 a.l -= this.offset + rad;
24205 a.t -= this.offset + rad;
24216 a.l -= (this.offset - rad);
24217 a.t -= this.offset + rad;
24219 a.w -= (this.offset - rad)*2;
24230 a.l -= (this.offset - rad);
24231 a.t -= (this.offset - rad);
24233 a.w -= (this.offset + rad + 1);
24234 a.h -= (this.offset + rad);
24243 Roo.Shadow.prototype = {
24245 * @cfg {String} mode
24246 * The shadow display mode. Supports the following options:<br />
24247 * sides: Shadow displays on both sides and bottom only<br />
24248 * frame: Shadow displays equally on all four sides<br />
24249 * drop: Traditional bottom-right drop shadow (default)
24252 * @cfg {String} offset
24253 * The number of pixels to offset the shadow from the element (defaults to 4)
24258 defaultMode: "drop",
24261 * Displays the shadow under the target element
24262 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24264 show : function(target){
24265 target = Roo.get(target);
24267 this.el = Roo.Shadow.Pool.pull();
24268 if(this.el.dom.nextSibling != target.dom){
24269 this.el.insertBefore(target);
24272 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24274 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24277 target.getLeft(true),
24278 target.getTop(true),
24282 this.el.dom.style.display = "block";
24286 * Returns true if the shadow is visible, else false
24288 isVisible : function(){
24289 return this.el ? true : false;
24293 * Direct alignment when values are already available. Show must be called at least once before
24294 * calling this method to ensure it is initialized.
24295 * @param {Number} left The target element left position
24296 * @param {Number} top The target element top position
24297 * @param {Number} width The target element width
24298 * @param {Number} height The target element height
24300 realign : function(l, t, w, h){
24304 var a = this.adjusts, d = this.el.dom, s = d.style;
24306 s.left = (l+a.l)+"px";
24307 s.top = (t+a.t)+"px";
24308 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24310 if(s.width != sws || s.height != shs){
24314 var cn = d.childNodes;
24315 var sww = Math.max(0, (sw-12))+"px";
24316 cn[0].childNodes[1].style.width = sww;
24317 cn[1].childNodes[1].style.width = sww;
24318 cn[2].childNodes[1].style.width = sww;
24319 cn[1].style.height = Math.max(0, (sh-12))+"px";
24325 * Hides this shadow
24329 this.el.dom.style.display = "none";
24330 Roo.Shadow.Pool.push(this.el);
24336 * Adjust the z-index of this shadow
24337 * @param {Number} zindex The new z-index
24339 setZIndex : function(z){
24342 this.el.setStyle("z-index", z);
24347 // Private utility class that manages the internal Shadow cache
24348 Roo.Shadow.Pool = function(){
24350 var markup = Roo.isIE ?
24351 '<div class="x-ie-shadow"></div>' :
24352 '<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>';
24355 var sh = p.shift();
24357 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24358 sh.autoBoxAdjust = false;
24363 push : function(sh){
24369 * Ext JS Library 1.1.1
24370 * Copyright(c) 2006-2007, Ext JS, LLC.
24372 * Originally Released Under LGPL - original licence link has changed is not relivant.
24375 * <script type="text/javascript">
24380 * @class Roo.SplitBar
24381 * @extends Roo.util.Observable
24382 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24386 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24387 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24388 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24389 split.minSize = 100;
24390 split.maxSize = 600;
24391 split.animate = true;
24392 split.on('moved', splitterMoved);
24395 * Create a new SplitBar
24396 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24397 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24398 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24399 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24400 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24401 position of the SplitBar).
24403 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24406 this.el = Roo.get(dragElement, true);
24407 this.el.dom.unselectable = "on";
24409 this.resizingEl = Roo.get(resizingElement, true);
24413 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24414 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24417 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24420 * The minimum size of the resizing element. (Defaults to 0)
24426 * The maximum size of the resizing element. (Defaults to 2000)
24429 this.maxSize = 2000;
24432 * Whether to animate the transition to the new size
24435 this.animate = false;
24438 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24441 this.useShim = false;
24446 if(!existingProxy){
24448 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24450 this.proxy = Roo.get(existingProxy).dom;
24453 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24456 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24459 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24462 this.dragSpecs = {};
24465 * @private The adapter to use to positon and resize elements
24467 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24468 this.adapter.init(this);
24470 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24472 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24473 this.el.addClass("x-splitbar-h");
24476 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24477 this.el.addClass("x-splitbar-v");
24483 * Fires when the splitter is moved (alias for {@link #event-moved})
24484 * @param {Roo.SplitBar} this
24485 * @param {Number} newSize the new width or height
24490 * Fires when the splitter is moved
24491 * @param {Roo.SplitBar} this
24492 * @param {Number} newSize the new width or height
24496 * @event beforeresize
24497 * Fires before the splitter is dragged
24498 * @param {Roo.SplitBar} this
24500 "beforeresize" : true,
24502 "beforeapply" : true
24505 Roo.util.Observable.call(this);
24508 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24509 onStartProxyDrag : function(x, y){
24510 this.fireEvent("beforeresize", this);
24512 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24514 o.enableDisplayMode("block");
24515 // all splitbars share the same overlay
24516 Roo.SplitBar.prototype.overlay = o;
24518 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24519 this.overlay.show();
24520 Roo.get(this.proxy).setDisplayed("block");
24521 var size = this.adapter.getElementSize(this);
24522 this.activeMinSize = this.getMinimumSize();;
24523 this.activeMaxSize = this.getMaximumSize();;
24524 var c1 = size - this.activeMinSize;
24525 var c2 = Math.max(this.activeMaxSize - size, 0);
24526 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24527 this.dd.resetConstraints();
24528 this.dd.setXConstraint(
24529 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24530 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24532 this.dd.setYConstraint(0, 0);
24534 this.dd.resetConstraints();
24535 this.dd.setXConstraint(0, 0);
24536 this.dd.setYConstraint(
24537 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24538 this.placement == Roo.SplitBar.TOP ? c2 : c1
24541 this.dragSpecs.startSize = size;
24542 this.dragSpecs.startPoint = [x, y];
24543 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24547 * @private Called after the drag operation by the DDProxy
24549 onEndProxyDrag : function(e){
24550 Roo.get(this.proxy).setDisplayed(false);
24551 var endPoint = Roo.lib.Event.getXY(e);
24553 this.overlay.hide();
24556 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24557 newSize = this.dragSpecs.startSize +
24558 (this.placement == Roo.SplitBar.LEFT ?
24559 endPoint[0] - this.dragSpecs.startPoint[0] :
24560 this.dragSpecs.startPoint[0] - endPoint[0]
24563 newSize = this.dragSpecs.startSize +
24564 (this.placement == Roo.SplitBar.TOP ?
24565 endPoint[1] - this.dragSpecs.startPoint[1] :
24566 this.dragSpecs.startPoint[1] - endPoint[1]
24569 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24570 if(newSize != this.dragSpecs.startSize){
24571 if(this.fireEvent('beforeapply', this, newSize) !== false){
24572 this.adapter.setElementSize(this, newSize);
24573 this.fireEvent("moved", this, newSize);
24574 this.fireEvent("resize", this, newSize);
24580 * Get the adapter this SplitBar uses
24581 * @return The adapter object
24583 getAdapter : function(){
24584 return this.adapter;
24588 * Set the adapter this SplitBar uses
24589 * @param {Object} adapter A SplitBar adapter object
24591 setAdapter : function(adapter){
24592 this.adapter = adapter;
24593 this.adapter.init(this);
24597 * Gets the minimum size for the resizing element
24598 * @return {Number} The minimum size
24600 getMinimumSize : function(){
24601 return this.minSize;
24605 * Sets the minimum size for the resizing element
24606 * @param {Number} minSize The minimum size
24608 setMinimumSize : function(minSize){
24609 this.minSize = minSize;
24613 * Gets the maximum size for the resizing element
24614 * @return {Number} The maximum size
24616 getMaximumSize : function(){
24617 return this.maxSize;
24621 * Sets the maximum size for the resizing element
24622 * @param {Number} maxSize The maximum size
24624 setMaximumSize : function(maxSize){
24625 this.maxSize = maxSize;
24629 * Sets the initialize size for the resizing element
24630 * @param {Number} size The initial size
24632 setCurrentSize : function(size){
24633 var oldAnimate = this.animate;
24634 this.animate = false;
24635 this.adapter.setElementSize(this, size);
24636 this.animate = oldAnimate;
24640 * Destroy this splitbar.
24641 * @param {Boolean} removeEl True to remove the element
24643 destroy : function(removeEl){
24645 this.shim.remove();
24648 this.proxy.parentNode.removeChild(this.proxy);
24656 * @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.
24658 Roo.SplitBar.createProxy = function(dir){
24659 var proxy = new Roo.Element(document.createElement("div"));
24660 proxy.unselectable();
24661 var cls = 'x-splitbar-proxy';
24662 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24663 document.body.appendChild(proxy.dom);
24668 * @class Roo.SplitBar.BasicLayoutAdapter
24669 * Default Adapter. It assumes the splitter and resizing element are not positioned
24670 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24672 Roo.SplitBar.BasicLayoutAdapter = function(){
24675 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24676 // do nothing for now
24677 init : function(s){
24681 * Called before drag operations to get the current size of the resizing element.
24682 * @param {Roo.SplitBar} s The SplitBar using this adapter
24684 getElementSize : function(s){
24685 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24686 return s.resizingEl.getWidth();
24688 return s.resizingEl.getHeight();
24693 * Called after drag operations to set the size of the resizing element.
24694 * @param {Roo.SplitBar} s The SplitBar using this adapter
24695 * @param {Number} newSize The new size to set
24696 * @param {Function} onComplete A function to be invoked when resizing is complete
24698 setElementSize : function(s, newSize, onComplete){
24699 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24701 s.resizingEl.setWidth(newSize);
24703 onComplete(s, newSize);
24706 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24711 s.resizingEl.setHeight(newSize);
24713 onComplete(s, newSize);
24716 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24723 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24724 * @extends Roo.SplitBar.BasicLayoutAdapter
24725 * Adapter that moves the splitter element to align with the resized sizing element.
24726 * Used with an absolute positioned SplitBar.
24727 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24728 * document.body, make sure you assign an id to the body element.
24730 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24731 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24732 this.container = Roo.get(container);
24735 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24736 init : function(s){
24737 this.basic.init(s);
24740 getElementSize : function(s){
24741 return this.basic.getElementSize(s);
24744 setElementSize : function(s, newSize, onComplete){
24745 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24748 moveSplitter : function(s){
24749 var yes = Roo.SplitBar;
24750 switch(s.placement){
24752 s.el.setX(s.resizingEl.getRight());
24755 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24758 s.el.setY(s.resizingEl.getBottom());
24761 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24768 * Orientation constant - Create a vertical SplitBar
24772 Roo.SplitBar.VERTICAL = 1;
24775 * Orientation constant - Create a horizontal SplitBar
24779 Roo.SplitBar.HORIZONTAL = 2;
24782 * Placement constant - The resizing element is to the left of the splitter element
24786 Roo.SplitBar.LEFT = 1;
24789 * Placement constant - The resizing element is to the right of the splitter element
24793 Roo.SplitBar.RIGHT = 2;
24796 * Placement constant - The resizing element is positioned above the splitter element
24800 Roo.SplitBar.TOP = 3;
24803 * Placement constant - The resizing element is positioned under splitter element
24807 Roo.SplitBar.BOTTOM = 4;
24810 * Ext JS Library 1.1.1
24811 * Copyright(c) 2006-2007, Ext JS, LLC.
24813 * Originally Released Under LGPL - original licence link has changed is not relivant.
24816 * <script type="text/javascript">
24821 * @extends Roo.util.Observable
24822 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24823 * This class also supports single and multi selection modes. <br>
24824 * Create a data model bound view:
24826 var store = new Roo.data.Store(...);
24828 var view = new Roo.View({
24830 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24832 singleSelect: true,
24833 selectedClass: "ydataview-selected",
24837 // listen for node click?
24838 view.on("click", function(vw, index, node, e){
24839 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24843 dataModel.load("foobar.xml");
24845 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24847 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24848 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24850 * Note: old style constructor is still suported (container, template, config)
24853 * Create a new View
24854 * @param {Object} config The config object
24857 Roo.View = function(config, depreciated_tpl, depreciated_config){
24859 this.parent = false;
24861 if (typeof(depreciated_tpl) == 'undefined') {
24862 // new way.. - universal constructor.
24863 Roo.apply(this, config);
24864 this.el = Roo.get(this.el);
24867 this.el = Roo.get(config);
24868 this.tpl = depreciated_tpl;
24869 Roo.apply(this, depreciated_config);
24871 this.wrapEl = this.el.wrap().wrap();
24872 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24875 if(typeof(this.tpl) == "string"){
24876 this.tpl = new Roo.Template(this.tpl);
24878 // support xtype ctors..
24879 this.tpl = new Roo.factory(this.tpl, Roo);
24883 this.tpl.compile();
24888 * @event beforeclick
24889 * Fires before a click is processed. Returns false to cancel the default action.
24890 * @param {Roo.View} this
24891 * @param {Number} index The index of the target node
24892 * @param {HTMLElement} node The target node
24893 * @param {Roo.EventObject} e The raw event object
24895 "beforeclick" : true,
24898 * Fires when a template node is clicked.
24899 * @param {Roo.View} this
24900 * @param {Number} index The index of the target node
24901 * @param {HTMLElement} node The target node
24902 * @param {Roo.EventObject} e The raw event object
24907 * Fires when a template node is double clicked.
24908 * @param {Roo.View} this
24909 * @param {Number} index The index of the target node
24910 * @param {HTMLElement} node The target node
24911 * @param {Roo.EventObject} e The raw event object
24915 * @event contextmenu
24916 * Fires when a template node is right clicked.
24917 * @param {Roo.View} this
24918 * @param {Number} index The index of the target node
24919 * @param {HTMLElement} node The target node
24920 * @param {Roo.EventObject} e The raw event object
24922 "contextmenu" : true,
24924 * @event selectionchange
24925 * Fires when the selected nodes change.
24926 * @param {Roo.View} this
24927 * @param {Array} selections Array of the selected nodes
24929 "selectionchange" : true,
24932 * @event beforeselect
24933 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24934 * @param {Roo.View} this
24935 * @param {HTMLElement} node The node to be selected
24936 * @param {Array} selections Array of currently selected nodes
24938 "beforeselect" : true,
24940 * @event preparedata
24941 * Fires on every row to render, to allow you to change the data.
24942 * @param {Roo.View} this
24943 * @param {Object} data to be rendered (change this)
24945 "preparedata" : true
24953 "click": this.onClick,
24954 "dblclick": this.onDblClick,
24955 "contextmenu": this.onContextMenu,
24959 this.selections = [];
24961 this.cmp = new Roo.CompositeElementLite([]);
24963 this.store = Roo.factory(this.store, Roo.data);
24964 this.setStore(this.store, true);
24967 if ( this.footer && this.footer.xtype) {
24969 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24971 this.footer.dataSource = this.store
24972 this.footer.container = fctr;
24973 this.footer = Roo.factory(this.footer, Roo);
24974 fctr.insertFirst(this.el);
24976 // this is a bit insane - as the paging toolbar seems to detach the el..
24977 // dom.parentNode.parentNode.parentNode
24978 // they get detached?
24982 Roo.View.superclass.constructor.call(this);
24987 Roo.extend(Roo.View, Roo.util.Observable, {
24990 * @cfg {Roo.data.Store} store Data store to load data from.
24995 * @cfg {String|Roo.Element} el The container element.
25000 * @cfg {String|Roo.Template} tpl The template used by this View
25004 * @cfg {String} dataName the named area of the template to use as the data area
25005 * Works with domtemplates roo-name="name"
25009 * @cfg {String} selectedClass The css class to add to selected nodes
25011 selectedClass : "x-view-selected",
25013 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25018 * @cfg {String} text to display on mask (default Loading)
25022 * @cfg {Boolean} multiSelect Allow multiple selection
25024 multiSelect : false,
25026 * @cfg {Boolean} singleSelect Allow single selection
25028 singleSelect: false,
25031 * @cfg {Boolean} toggleSelect - selecting
25033 toggleSelect : false,
25036 * @cfg {Boolean} tickable - selecting
25041 * Returns the element this view is bound to.
25042 * @return {Roo.Element}
25044 getEl : function(){
25045 return this.wrapEl;
25051 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25053 refresh : function(){
25054 Roo.log('refresh');
25057 // if we are using something like 'domtemplate', then
25058 // the what gets used is:
25059 // t.applySubtemplate(NAME, data, wrapping data..)
25060 // the outer template then get' applied with
25061 // the store 'extra data'
25062 // and the body get's added to the
25063 // roo-name="data" node?
25064 // <span class='roo-tpl-{name}'></span> ?????
25068 this.clearSelections();
25069 this.el.update("");
25071 var records = this.store.getRange();
25072 if(records.length < 1) {
25074 // is this valid?? = should it render a template??
25076 this.el.update(this.emptyText);
25080 if (this.dataName) {
25081 this.el.update(t.apply(this.store.meta)); //????
25082 el = this.el.child('.roo-tpl-' + this.dataName);
25085 for(var i = 0, len = records.length; i < len; i++){
25086 var data = this.prepareData(records[i].data, i, records[i]);
25087 this.fireEvent("preparedata", this, data, i, records[i]);
25089 var d = Roo.apply({}, data);
25092 Roo.apply(d, {'roo-id' : Roo.id()});
25096 Roo.each(this.parent.item, function(item){
25097 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25100 Roo.apply(d, {'roo-data-checked' : 'checked'});
25104 html[html.length] = Roo.util.Format.trim(
25106 t.applySubtemplate(this.dataName, d, this.store.meta) :
25113 el.update(html.join(""));
25114 this.nodes = el.dom.childNodes;
25115 this.updateIndexes(0);
25120 * Function to override to reformat the data that is sent to
25121 * the template for each node.
25122 * DEPRICATED - use the preparedata event handler.
25123 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25124 * a JSON object for an UpdateManager bound view).
25126 prepareData : function(data, index, record)
25128 this.fireEvent("preparedata", this, data, index, record);
25132 onUpdate : function(ds, record){
25133 Roo.log('on update');
25134 this.clearSelections();
25135 var index = this.store.indexOf(record);
25136 var n = this.nodes[index];
25137 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25138 n.parentNode.removeChild(n);
25139 this.updateIndexes(index, index);
25145 onAdd : function(ds, records, index)
25147 Roo.log(['on Add', ds, records, index] );
25148 this.clearSelections();
25149 if(this.nodes.length == 0){
25153 var n = this.nodes[index];
25154 for(var i = 0, len = records.length; i < len; i++){
25155 var d = this.prepareData(records[i].data, i, records[i]);
25157 this.tpl.insertBefore(n, d);
25160 this.tpl.append(this.el, d);
25163 this.updateIndexes(index);
25166 onRemove : function(ds, record, index){
25167 Roo.log('onRemove');
25168 this.clearSelections();
25169 var el = this.dataName ?
25170 this.el.child('.roo-tpl-' + this.dataName) :
25173 el.dom.removeChild(this.nodes[index]);
25174 this.updateIndexes(index);
25178 * Refresh an individual node.
25179 * @param {Number} index
25181 refreshNode : function(index){
25182 this.onUpdate(this.store, this.store.getAt(index));
25185 updateIndexes : function(startIndex, endIndex){
25186 var ns = this.nodes;
25187 startIndex = startIndex || 0;
25188 endIndex = endIndex || ns.length - 1;
25189 for(var i = startIndex; i <= endIndex; i++){
25190 ns[i].nodeIndex = i;
25195 * Changes the data store this view uses and refresh the view.
25196 * @param {Store} store
25198 setStore : function(store, initial){
25199 if(!initial && this.store){
25200 this.store.un("datachanged", this.refresh);
25201 this.store.un("add", this.onAdd);
25202 this.store.un("remove", this.onRemove);
25203 this.store.un("update", this.onUpdate);
25204 this.store.un("clear", this.refresh);
25205 this.store.un("beforeload", this.onBeforeLoad);
25206 this.store.un("load", this.onLoad);
25207 this.store.un("loadexception", this.onLoad);
25211 store.on("datachanged", this.refresh, this);
25212 store.on("add", this.onAdd, this);
25213 store.on("remove", this.onRemove, this);
25214 store.on("update", this.onUpdate, this);
25215 store.on("clear", this.refresh, this);
25216 store.on("beforeload", this.onBeforeLoad, this);
25217 store.on("load", this.onLoad, this);
25218 store.on("loadexception", this.onLoad, this);
25226 * onbeforeLoad - masks the loading area.
25229 onBeforeLoad : function(store,opts)
25231 Roo.log('onBeforeLoad');
25233 this.el.update("");
25235 this.el.mask(this.mask ? this.mask : "Loading" );
25237 onLoad : function ()
25244 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25245 * @param {HTMLElement} node
25246 * @return {HTMLElement} The template node
25248 findItemFromChild : function(node){
25249 var el = this.dataName ?
25250 this.el.child('.roo-tpl-' + this.dataName,true) :
25253 if(!node || node.parentNode == el){
25256 var p = node.parentNode;
25257 while(p && p != el){
25258 if(p.parentNode == el){
25267 onClick : function(e){
25268 var item = this.findItemFromChild(e.getTarget());
25270 var index = this.indexOf(item);
25271 if(this.onItemClick(item, index, e) !== false){
25272 this.fireEvent("click", this, index, item, e);
25275 this.clearSelections();
25280 onContextMenu : function(e){
25281 var item = this.findItemFromChild(e.getTarget());
25283 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25288 onDblClick : function(e){
25289 var item = this.findItemFromChild(e.getTarget());
25291 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25295 onItemClick : function(item, index, e)
25297 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25300 if (this.toggleSelect) {
25301 var m = this.isSelected(item) ? 'unselect' : 'select';
25304 _t[m](item, true, false);
25307 if(this.multiSelect || this.singleSelect){
25308 if(this.multiSelect && e.shiftKey && this.lastSelection){
25309 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25311 this.select(item, this.multiSelect && e.ctrlKey);
25312 this.lastSelection = item;
25315 if(!this.tickable){
25316 e.preventDefault();
25324 * Get the number of selected nodes.
25327 getSelectionCount : function(){
25328 return this.selections.length;
25332 * Get the currently selected nodes.
25333 * @return {Array} An array of HTMLElements
25335 getSelectedNodes : function(){
25336 return this.selections;
25340 * Get the indexes of the selected nodes.
25343 getSelectedIndexes : function(){
25344 var indexes = [], s = this.selections;
25345 for(var i = 0, len = s.length; i < len; i++){
25346 indexes.push(s[i].nodeIndex);
25352 * Clear all selections
25353 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25355 clearSelections : function(suppressEvent){
25356 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25357 this.cmp.elements = this.selections;
25358 this.cmp.removeClass(this.selectedClass);
25359 this.selections = [];
25360 if(!suppressEvent){
25361 this.fireEvent("selectionchange", this, this.selections);
25367 * Returns true if the passed node is selected
25368 * @param {HTMLElement/Number} node The node or node index
25369 * @return {Boolean}
25371 isSelected : function(node){
25372 var s = this.selections;
25376 node = this.getNode(node);
25377 return s.indexOf(node) !== -1;
25382 * @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
25383 * @param {Boolean} keepExisting (optional) true to keep existing selections
25384 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25386 select : function(nodeInfo, keepExisting, suppressEvent){
25387 if(nodeInfo instanceof Array){
25389 this.clearSelections(true);
25391 for(var i = 0, len = nodeInfo.length; i < len; i++){
25392 this.select(nodeInfo[i], true, true);
25396 var node = this.getNode(nodeInfo);
25397 if(!node || this.isSelected(node)){
25398 return; // already selected.
25401 this.clearSelections(true);
25404 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25405 Roo.fly(node).addClass(this.selectedClass);
25406 this.selections.push(node);
25407 if(!suppressEvent){
25408 this.fireEvent("selectionchange", this, this.selections);
25416 * @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
25417 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25418 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25420 unselect : function(nodeInfo, keepExisting, suppressEvent)
25422 if(nodeInfo instanceof Array){
25423 Roo.each(this.selections, function(s) {
25424 this.unselect(s, nodeInfo);
25428 var node = this.getNode(nodeInfo);
25429 if(!node || !this.isSelected(node)){
25430 Roo.log("not selected");
25431 return; // not selected.
25435 Roo.each(this.selections, function(s) {
25437 Roo.fly(node).removeClass(this.selectedClass);
25444 this.selections= ns;
25445 this.fireEvent("selectionchange", this, this.selections);
25449 * Gets a template node.
25450 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25451 * @return {HTMLElement} The node or null if it wasn't found
25453 getNode : function(nodeInfo){
25454 if(typeof nodeInfo == "string"){
25455 return document.getElementById(nodeInfo);
25456 }else if(typeof nodeInfo == "number"){
25457 return this.nodes[nodeInfo];
25463 * Gets a range template nodes.
25464 * @param {Number} startIndex
25465 * @param {Number} endIndex
25466 * @return {Array} An array of nodes
25468 getNodes : function(start, end){
25469 var ns = this.nodes;
25470 start = start || 0;
25471 end = typeof end == "undefined" ? ns.length - 1 : end;
25474 for(var i = start; i <= end; i++){
25478 for(var i = start; i >= end; i--){
25486 * Finds the index of the passed node
25487 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25488 * @return {Number} The index of the node or -1
25490 indexOf : function(node){
25491 node = this.getNode(node);
25492 if(typeof node.nodeIndex == "number"){
25493 return node.nodeIndex;
25495 var ns = this.nodes;
25496 for(var i = 0, len = ns.length; i < len; i++){
25506 * Ext JS Library 1.1.1
25507 * Copyright(c) 2006-2007, Ext JS, LLC.
25509 * Originally Released Under LGPL - original licence link has changed is not relivant.
25512 * <script type="text/javascript">
25516 * @class Roo.JsonView
25517 * @extends Roo.View
25518 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25520 var view = new Roo.JsonView({
25521 container: "my-element",
25522 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25527 // listen for node click?
25528 view.on("click", function(vw, index, node, e){
25529 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25532 // direct load of JSON data
25533 view.load("foobar.php");
25535 // Example from my blog list
25536 var tpl = new Roo.Template(
25537 '<div class="entry">' +
25538 '<a class="entry-title" href="{link}">{title}</a>' +
25539 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25540 "</div><hr />"
25543 var moreView = new Roo.JsonView({
25544 container : "entry-list",
25548 moreView.on("beforerender", this.sortEntries, this);
25550 url: "/blog/get-posts.php",
25551 params: "allposts=true",
25552 text: "Loading Blog Entries..."
25556 * Note: old code is supported with arguments : (container, template, config)
25560 * Create a new JsonView
25562 * @param {Object} config The config object
25565 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25568 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25570 var um = this.el.getUpdateManager();
25571 um.setRenderer(this);
25572 um.on("update", this.onLoad, this);
25573 um.on("failure", this.onLoadException, this);
25576 * @event beforerender
25577 * Fires before rendering of the downloaded JSON data.
25578 * @param {Roo.JsonView} this
25579 * @param {Object} data The JSON data loaded
25583 * Fires when data is loaded.
25584 * @param {Roo.JsonView} this
25585 * @param {Object} data The JSON data loaded
25586 * @param {Object} response The raw Connect response object
25589 * @event loadexception
25590 * Fires when loading fails.
25591 * @param {Roo.JsonView} this
25592 * @param {Object} response The raw Connect response object
25595 'beforerender' : true,
25597 'loadexception' : true
25600 Roo.extend(Roo.JsonView, Roo.View, {
25602 * @type {String} The root property in the loaded JSON object that contains the data
25607 * Refreshes the view.
25609 refresh : function(){
25610 this.clearSelections();
25611 this.el.update("");
25613 var o = this.jsonData;
25614 if(o && o.length > 0){
25615 for(var i = 0, len = o.length; i < len; i++){
25616 var data = this.prepareData(o[i], i, o);
25617 html[html.length] = this.tpl.apply(data);
25620 html.push(this.emptyText);
25622 this.el.update(html.join(""));
25623 this.nodes = this.el.dom.childNodes;
25624 this.updateIndexes(0);
25628 * 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.
25629 * @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:
25632 url: "your-url.php",
25633 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25634 callback: yourFunction,
25635 scope: yourObject, //(optional scope)
25638 text: "Loading...",
25643 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25644 * 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.
25645 * @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}
25646 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25647 * @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.
25650 var um = this.el.getUpdateManager();
25651 um.update.apply(um, arguments);
25654 render : function(el, response){
25655 this.clearSelections();
25656 this.el.update("");
25659 o = Roo.util.JSON.decode(response.responseText);
25662 o = o[this.jsonRoot];
25667 * The current JSON data or null
25670 this.beforeRender();
25675 * Get the number of records in the current JSON dataset
25678 getCount : function(){
25679 return this.jsonData ? this.jsonData.length : 0;
25683 * Returns the JSON object for the specified node(s)
25684 * @param {HTMLElement/Array} node The node or an array of nodes
25685 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25686 * you get the JSON object for the node
25688 getNodeData : function(node){
25689 if(node instanceof Array){
25691 for(var i = 0, len = node.length; i < len; i++){
25692 data.push(this.getNodeData(node[i]));
25696 return this.jsonData[this.indexOf(node)] || null;
25699 beforeRender : function(){
25700 this.snapshot = this.jsonData;
25702 this.sort.apply(this, this.sortInfo);
25704 this.fireEvent("beforerender", this, this.jsonData);
25707 onLoad : function(el, o){
25708 this.fireEvent("load", this, this.jsonData, o);
25711 onLoadException : function(el, o){
25712 this.fireEvent("loadexception", this, o);
25716 * Filter the data by a specific property.
25717 * @param {String} property A property on your JSON objects
25718 * @param {String/RegExp} value Either string that the property values
25719 * should start with, or a RegExp to test against the property
25721 filter : function(property, value){
25724 var ss = this.snapshot;
25725 if(typeof value == "string"){
25726 var vlen = value.length;
25728 this.clearFilter();
25731 value = value.toLowerCase();
25732 for(var i = 0, len = ss.length; i < len; i++){
25734 if(o[property].substr(0, vlen).toLowerCase() == value){
25738 } else if(value.exec){ // regex?
25739 for(var i = 0, len = ss.length; i < len; i++){
25741 if(value.test(o[property])){
25748 this.jsonData = data;
25754 * Filter by a function. The passed function will be called with each
25755 * object in the current dataset. If the function returns true the value is kept,
25756 * otherwise it is filtered.
25757 * @param {Function} fn
25758 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25760 filterBy : function(fn, scope){
25763 var ss = this.snapshot;
25764 for(var i = 0, len = ss.length; i < len; i++){
25766 if(fn.call(scope || this, o)){
25770 this.jsonData = data;
25776 * Clears the current filter.
25778 clearFilter : function(){
25779 if(this.snapshot && this.jsonData != this.snapshot){
25780 this.jsonData = this.snapshot;
25787 * Sorts the data for this view and refreshes it.
25788 * @param {String} property A property on your JSON objects to sort on
25789 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25790 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25792 sort : function(property, dir, sortType){
25793 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25796 var dsc = dir && dir.toLowerCase() == "desc";
25797 var f = function(o1, o2){
25798 var v1 = sortType ? sortType(o1[p]) : o1[p];
25799 var v2 = sortType ? sortType(o2[p]) : o2[p];
25802 return dsc ? +1 : -1;
25803 } else if(v1 > v2){
25804 return dsc ? -1 : +1;
25809 this.jsonData.sort(f);
25811 if(this.jsonData != this.snapshot){
25812 this.snapshot.sort(f);
25818 * Ext JS Library 1.1.1
25819 * Copyright(c) 2006-2007, Ext JS, LLC.
25821 * Originally Released Under LGPL - original licence link has changed is not relivant.
25824 * <script type="text/javascript">
25829 * @class Roo.ColorPalette
25830 * @extends Roo.Component
25831 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25832 * Here's an example of typical usage:
25834 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25835 cp.render('my-div');
25837 cp.on('select', function(palette, selColor){
25838 // do something with selColor
25842 * Create a new ColorPalette
25843 * @param {Object} config The config object
25845 Roo.ColorPalette = function(config){
25846 Roo.ColorPalette.superclass.constructor.call(this, config);
25850 * Fires when a color is selected
25851 * @param {ColorPalette} this
25852 * @param {String} color The 6-digit color hex code (without the # symbol)
25858 this.on("select", this.handler, this.scope, true);
25861 Roo.extend(Roo.ColorPalette, Roo.Component, {
25863 * @cfg {String} itemCls
25864 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25866 itemCls : "x-color-palette",
25868 * @cfg {String} value
25869 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25870 * the hex codes are case-sensitive.
25873 clickEvent:'click',
25875 ctype: "Roo.ColorPalette",
25878 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25880 allowReselect : false,
25883 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25884 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25885 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25886 * of colors with the width setting until the box is symmetrical.</p>
25887 * <p>You can override individual colors if needed:</p>
25889 var cp = new Roo.ColorPalette();
25890 cp.colors[0] = "FF0000"; // change the first box to red
25893 Or you can provide a custom array of your own for complete control:
25895 var cp = new Roo.ColorPalette();
25896 cp.colors = ["000000", "993300", "333300"];
25901 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25902 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25903 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25904 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25905 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25909 onRender : function(container, position){
25910 var t = new Roo.MasterTemplate(
25911 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25913 var c = this.colors;
25914 for(var i = 0, len = c.length; i < len; i++){
25917 var el = document.createElement("div");
25918 el.className = this.itemCls;
25920 container.dom.insertBefore(el, position);
25921 this.el = Roo.get(el);
25922 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25923 if(this.clickEvent != 'click'){
25924 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25929 afterRender : function(){
25930 Roo.ColorPalette.superclass.afterRender.call(this);
25932 var s = this.value;
25939 handleClick : function(e, t){
25940 e.preventDefault();
25941 if(!this.disabled){
25942 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25943 this.select(c.toUpperCase());
25948 * Selects the specified color in the palette (fires the select event)
25949 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25951 select : function(color){
25952 color = color.replace("#", "");
25953 if(color != this.value || this.allowReselect){
25956 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25958 el.child("a.color-"+color).addClass("x-color-palette-sel");
25959 this.value = color;
25960 this.fireEvent("select", this, color);
25965 * Ext JS Library 1.1.1
25966 * Copyright(c) 2006-2007, Ext JS, LLC.
25968 * Originally Released Under LGPL - original licence link has changed is not relivant.
25971 * <script type="text/javascript">
25975 * @class Roo.DatePicker
25976 * @extends Roo.Component
25977 * Simple date picker class.
25979 * Create a new DatePicker
25980 * @param {Object} config The config object
25982 Roo.DatePicker = function(config){
25983 Roo.DatePicker.superclass.constructor.call(this, config);
25985 this.value = config && config.value ?
25986 config.value.clearTime() : new Date().clearTime();
25991 * Fires when a date is selected
25992 * @param {DatePicker} this
25993 * @param {Date} date The selected date
25997 * @event monthchange
25998 * Fires when the displayed month changes
25999 * @param {DatePicker} this
26000 * @param {Date} date The selected month
26002 'monthchange': true
26006 this.on("select", this.handler, this.scope || this);
26008 // build the disabledDatesRE
26009 if(!this.disabledDatesRE && this.disabledDates){
26010 var dd = this.disabledDates;
26012 for(var i = 0; i < dd.length; i++){
26014 if(i != dd.length-1) re += "|";
26016 this.disabledDatesRE = new RegExp(re + ")");
26020 Roo.extend(Roo.DatePicker, Roo.Component, {
26022 * @cfg {String} todayText
26023 * The text to display on the button that selects the current date (defaults to "Today")
26025 todayText : "Today",
26027 * @cfg {String} okText
26028 * The text to display on the ok button
26030 okText : " OK ", //   to give the user extra clicking room
26032 * @cfg {String} cancelText
26033 * The text to display on the cancel button
26035 cancelText : "Cancel",
26037 * @cfg {String} todayTip
26038 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26040 todayTip : "{0} (Spacebar)",
26042 * @cfg {Date} minDate
26043 * Minimum allowable date (JavaScript date object, defaults to null)
26047 * @cfg {Date} maxDate
26048 * Maximum allowable date (JavaScript date object, defaults to null)
26052 * @cfg {String} minText
26053 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26055 minText : "This date is before the minimum date",
26057 * @cfg {String} maxText
26058 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26060 maxText : "This date is after the maximum date",
26062 * @cfg {String} format
26063 * The default date format string which can be overriden for localization support. The format must be
26064 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26068 * @cfg {Array} disabledDays
26069 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26071 disabledDays : null,
26073 * @cfg {String} disabledDaysText
26074 * The tooltip to display when the date falls on a disabled day (defaults to "")
26076 disabledDaysText : "",
26078 * @cfg {RegExp} disabledDatesRE
26079 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26081 disabledDatesRE : null,
26083 * @cfg {String} disabledDatesText
26084 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26086 disabledDatesText : "",
26088 * @cfg {Boolean} constrainToViewport
26089 * True to constrain the date picker to the viewport (defaults to true)
26091 constrainToViewport : true,
26093 * @cfg {Array} monthNames
26094 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26096 monthNames : Date.monthNames,
26098 * @cfg {Array} dayNames
26099 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26101 dayNames : Date.dayNames,
26103 * @cfg {String} nextText
26104 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26106 nextText: 'Next Month (Control+Right)',
26108 * @cfg {String} prevText
26109 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26111 prevText: 'Previous Month (Control+Left)',
26113 * @cfg {String} monthYearText
26114 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26116 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26118 * @cfg {Number} startDay
26119 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26123 * @cfg {Bool} showClear
26124 * Show a clear button (usefull for date form elements that can be blank.)
26130 * Sets the value of the date field
26131 * @param {Date} value The date to set
26133 setValue : function(value){
26134 var old = this.value;
26136 if (typeof(value) == 'string') {
26138 value = Date.parseDate(value, this.format);
26141 value = new Date();
26144 this.value = value.clearTime(true);
26146 this.update(this.value);
26151 * Gets the current selected value of the date field
26152 * @return {Date} The selected date
26154 getValue : function(){
26159 focus : function(){
26161 this.update(this.activeDate);
26166 onRender : function(container, position){
26169 '<table cellspacing="0">',
26170 '<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>',
26171 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26172 var dn = this.dayNames;
26173 for(var i = 0; i < 7; i++){
26174 var d = this.startDay+i;
26178 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26180 m[m.length] = "</tr></thead><tbody><tr>";
26181 for(var i = 0; i < 42; i++) {
26182 if(i % 7 == 0 && i != 0){
26183 m[m.length] = "</tr><tr>";
26185 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26187 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26188 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26190 var el = document.createElement("div");
26191 el.className = "x-date-picker";
26192 el.innerHTML = m.join("");
26194 container.dom.insertBefore(el, position);
26196 this.el = Roo.get(el);
26197 this.eventEl = Roo.get(el.firstChild);
26199 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26200 handler: this.showPrevMonth,
26202 preventDefault:true,
26206 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26207 handler: this.showNextMonth,
26209 preventDefault:true,
26213 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26215 this.monthPicker = this.el.down('div.x-date-mp');
26216 this.monthPicker.enableDisplayMode('block');
26218 var kn = new Roo.KeyNav(this.eventEl, {
26219 "left" : function(e){
26221 this.showPrevMonth() :
26222 this.update(this.activeDate.add("d", -1));
26225 "right" : function(e){
26227 this.showNextMonth() :
26228 this.update(this.activeDate.add("d", 1));
26231 "up" : function(e){
26233 this.showNextYear() :
26234 this.update(this.activeDate.add("d", -7));
26237 "down" : function(e){
26239 this.showPrevYear() :
26240 this.update(this.activeDate.add("d", 7));
26243 "pageUp" : function(e){
26244 this.showNextMonth();
26247 "pageDown" : function(e){
26248 this.showPrevMonth();
26251 "enter" : function(e){
26252 e.stopPropagation();
26259 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26261 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26263 this.el.unselectable();
26265 this.cells = this.el.select("table.x-date-inner tbody td");
26266 this.textNodes = this.el.query("table.x-date-inner tbody span");
26268 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26270 tooltip: this.monthYearText
26273 this.mbtn.on('click', this.showMonthPicker, this);
26274 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26277 var today = (new Date()).dateFormat(this.format);
26279 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26280 if (this.showClear) {
26281 baseTb.add( new Roo.Toolbar.Fill());
26284 text: String.format(this.todayText, today),
26285 tooltip: String.format(this.todayTip, today),
26286 handler: this.selectToday,
26290 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26293 if (this.showClear) {
26295 baseTb.add( new Roo.Toolbar.Fill());
26298 cls: 'x-btn-icon x-btn-clear',
26299 handler: function() {
26301 this.fireEvent("select", this, '');
26311 this.update(this.value);
26314 createMonthPicker : function(){
26315 if(!this.monthPicker.dom.firstChild){
26316 var buf = ['<table border="0" cellspacing="0">'];
26317 for(var i = 0; i < 6; i++){
26319 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26320 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26322 '<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>' :
26323 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26327 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26329 '</button><button type="button" class="x-date-mp-cancel">',
26331 '</button></td></tr>',
26334 this.monthPicker.update(buf.join(''));
26335 this.monthPicker.on('click', this.onMonthClick, this);
26336 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26338 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26339 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26341 this.mpMonths.each(function(m, a, i){
26344 m.dom.xmonth = 5 + Math.round(i * .5);
26346 m.dom.xmonth = Math.round((i-1) * .5);
26352 showMonthPicker : function(){
26353 this.createMonthPicker();
26354 var size = this.el.getSize();
26355 this.monthPicker.setSize(size);
26356 this.monthPicker.child('table').setSize(size);
26358 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26359 this.updateMPMonth(this.mpSelMonth);
26360 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26361 this.updateMPYear(this.mpSelYear);
26363 this.monthPicker.slideIn('t', {duration:.2});
26366 updateMPYear : function(y){
26368 var ys = this.mpYears.elements;
26369 for(var i = 1; i <= 10; i++){
26370 var td = ys[i-1], y2;
26372 y2 = y + Math.round(i * .5);
26373 td.firstChild.innerHTML = y2;
26376 y2 = y - (5-Math.round(i * .5));
26377 td.firstChild.innerHTML = y2;
26380 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26384 updateMPMonth : function(sm){
26385 this.mpMonths.each(function(m, a, i){
26386 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26390 selectMPMonth: function(m){
26394 onMonthClick : function(e, t){
26396 var el = new Roo.Element(t), pn;
26397 if(el.is('button.x-date-mp-cancel')){
26398 this.hideMonthPicker();
26400 else if(el.is('button.x-date-mp-ok')){
26401 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26402 this.hideMonthPicker();
26404 else if(pn = el.up('td.x-date-mp-month', 2)){
26405 this.mpMonths.removeClass('x-date-mp-sel');
26406 pn.addClass('x-date-mp-sel');
26407 this.mpSelMonth = pn.dom.xmonth;
26409 else if(pn = el.up('td.x-date-mp-year', 2)){
26410 this.mpYears.removeClass('x-date-mp-sel');
26411 pn.addClass('x-date-mp-sel');
26412 this.mpSelYear = pn.dom.xyear;
26414 else if(el.is('a.x-date-mp-prev')){
26415 this.updateMPYear(this.mpyear-10);
26417 else if(el.is('a.x-date-mp-next')){
26418 this.updateMPYear(this.mpyear+10);
26422 onMonthDblClick : function(e, t){
26424 var el = new Roo.Element(t), pn;
26425 if(pn = el.up('td.x-date-mp-month', 2)){
26426 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26427 this.hideMonthPicker();
26429 else if(pn = el.up('td.x-date-mp-year', 2)){
26430 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26431 this.hideMonthPicker();
26435 hideMonthPicker : function(disableAnim){
26436 if(this.monthPicker){
26437 if(disableAnim === true){
26438 this.monthPicker.hide();
26440 this.monthPicker.slideOut('t', {duration:.2});
26446 showPrevMonth : function(e){
26447 this.update(this.activeDate.add("mo", -1));
26451 showNextMonth : function(e){
26452 this.update(this.activeDate.add("mo", 1));
26456 showPrevYear : function(){
26457 this.update(this.activeDate.add("y", -1));
26461 showNextYear : function(){
26462 this.update(this.activeDate.add("y", 1));
26466 handleMouseWheel : function(e){
26467 var delta = e.getWheelDelta();
26469 this.showPrevMonth();
26471 } else if(delta < 0){
26472 this.showNextMonth();
26478 handleDateClick : function(e, t){
26480 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26481 this.setValue(new Date(t.dateValue));
26482 this.fireEvent("select", this, this.value);
26487 selectToday : function(){
26488 this.setValue(new Date().clearTime());
26489 this.fireEvent("select", this, this.value);
26493 update : function(date)
26495 var vd = this.activeDate;
26496 this.activeDate = date;
26498 var t = date.getTime();
26499 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26500 this.cells.removeClass("x-date-selected");
26501 this.cells.each(function(c){
26502 if(c.dom.firstChild.dateValue == t){
26503 c.addClass("x-date-selected");
26504 setTimeout(function(){
26505 try{c.dom.firstChild.focus();}catch(e){}
26514 var days = date.getDaysInMonth();
26515 var firstOfMonth = date.getFirstDateOfMonth();
26516 var startingPos = firstOfMonth.getDay()-this.startDay;
26518 if(startingPos <= this.startDay){
26522 var pm = date.add("mo", -1);
26523 var prevStart = pm.getDaysInMonth()-startingPos;
26525 var cells = this.cells.elements;
26526 var textEls = this.textNodes;
26527 days += startingPos;
26529 // convert everything to numbers so it's fast
26530 var day = 86400000;
26531 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26532 var today = new Date().clearTime().getTime();
26533 var sel = date.clearTime().getTime();
26534 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26535 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26536 var ddMatch = this.disabledDatesRE;
26537 var ddText = this.disabledDatesText;
26538 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26539 var ddaysText = this.disabledDaysText;
26540 var format = this.format;
26542 var setCellClass = function(cal, cell){
26544 var t = d.getTime();
26545 cell.firstChild.dateValue = t;
26547 cell.className += " x-date-today";
26548 cell.title = cal.todayText;
26551 cell.className += " x-date-selected";
26552 setTimeout(function(){
26553 try{cell.firstChild.focus();}catch(e){}
26558 cell.className = " x-date-disabled";
26559 cell.title = cal.minText;
26563 cell.className = " x-date-disabled";
26564 cell.title = cal.maxText;
26568 if(ddays.indexOf(d.getDay()) != -1){
26569 cell.title = ddaysText;
26570 cell.className = " x-date-disabled";
26573 if(ddMatch && format){
26574 var fvalue = d.dateFormat(format);
26575 if(ddMatch.test(fvalue)){
26576 cell.title = ddText.replace("%0", fvalue);
26577 cell.className = " x-date-disabled";
26583 for(; i < startingPos; i++) {
26584 textEls[i].innerHTML = (++prevStart);
26585 d.setDate(d.getDate()+1);
26586 cells[i].className = "x-date-prevday";
26587 setCellClass(this, cells[i]);
26589 for(; i < days; i++){
26590 intDay = i - startingPos + 1;
26591 textEls[i].innerHTML = (intDay);
26592 d.setDate(d.getDate()+1);
26593 cells[i].className = "x-date-active";
26594 setCellClass(this, cells[i]);
26597 for(; i < 42; i++) {
26598 textEls[i].innerHTML = (++extraDays);
26599 d.setDate(d.getDate()+1);
26600 cells[i].className = "x-date-nextday";
26601 setCellClass(this, cells[i]);
26604 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26605 this.fireEvent('monthchange', this, date);
26607 if(!this.internalRender){
26608 var main = this.el.dom.firstChild;
26609 var w = main.offsetWidth;
26610 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26611 Roo.fly(main).setWidth(w);
26612 this.internalRender = true;
26613 // opera does not respect the auto grow header center column
26614 // then, after it gets a width opera refuses to recalculate
26615 // without a second pass
26616 if(Roo.isOpera && !this.secondPass){
26617 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26618 this.secondPass = true;
26619 this.update.defer(10, this, [date]);
26627 * Ext JS Library 1.1.1
26628 * Copyright(c) 2006-2007, Ext JS, LLC.
26630 * Originally Released Under LGPL - original licence link has changed is not relivant.
26633 * <script type="text/javascript">
26636 * @class Roo.TabPanel
26637 * @extends Roo.util.Observable
26638 * A lightweight tab container.
26642 // basic tabs 1, built from existing content
26643 var tabs = new Roo.TabPanel("tabs1");
26644 tabs.addTab("script", "View Script");
26645 tabs.addTab("markup", "View Markup");
26646 tabs.activate("script");
26648 // more advanced tabs, built from javascript
26649 var jtabs = new Roo.TabPanel("jtabs");
26650 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26652 // set up the UpdateManager
26653 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26654 var updater = tab2.getUpdateManager();
26655 updater.setDefaultUrl("ajax1.htm");
26656 tab2.on('activate', updater.refresh, updater, true);
26658 // Use setUrl for Ajax loading
26659 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26660 tab3.setUrl("ajax2.htm", null, true);
26663 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26666 jtabs.activate("jtabs-1");
26669 * Create a new TabPanel.
26670 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26671 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26673 Roo.TabPanel = function(container, config){
26675 * The container element for this TabPanel.
26676 * @type Roo.Element
26678 this.el = Roo.get(container, true);
26680 if(typeof config == "boolean"){
26681 this.tabPosition = config ? "bottom" : "top";
26683 Roo.apply(this, config);
26686 if(this.tabPosition == "bottom"){
26687 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26688 this.el.addClass("x-tabs-bottom");
26690 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26691 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26692 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26694 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26696 if(this.tabPosition != "bottom"){
26697 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26698 * @type Roo.Element
26700 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26701 this.el.addClass("x-tabs-top");
26705 this.bodyEl.setStyle("position", "relative");
26707 this.active = null;
26708 this.activateDelegate = this.activate.createDelegate(this);
26713 * Fires when the active tab changes
26714 * @param {Roo.TabPanel} this
26715 * @param {Roo.TabPanelItem} activePanel The new active tab
26719 * @event beforetabchange
26720 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26721 * @param {Roo.TabPanel} this
26722 * @param {Object} e Set cancel to true on this object to cancel the tab change
26723 * @param {Roo.TabPanelItem} tab The tab being changed to
26725 "beforetabchange" : true
26728 Roo.EventManager.onWindowResize(this.onResize, this);
26729 this.cpad = this.el.getPadding("lr");
26730 this.hiddenCount = 0;
26733 // toolbar on the tabbar support...
26734 if (this.toolbar) {
26735 var tcfg = this.toolbar;
26736 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26737 this.toolbar = new Roo.Toolbar(tcfg);
26738 if (Roo.isSafari) {
26739 var tbl = tcfg.container.child('table', true);
26740 tbl.setAttribute('width', '100%');
26747 Roo.TabPanel.superclass.constructor.call(this);
26750 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26752 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26754 tabPosition : "top",
26756 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26758 currentTabWidth : 0,
26760 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26764 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26768 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26770 preferredTabWidth : 175,
26772 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26774 resizeTabs : false,
26776 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26778 monitorResize : true,
26780 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26785 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26786 * @param {String} id The id of the div to use <b>or create</b>
26787 * @param {String} text The text for the tab
26788 * @param {String} content (optional) Content to put in the TabPanelItem body
26789 * @param {Boolean} closable (optional) True to create a close icon on the tab
26790 * @return {Roo.TabPanelItem} The created TabPanelItem
26792 addTab : function(id, text, content, closable){
26793 var item = new Roo.TabPanelItem(this, id, text, closable);
26794 this.addTabItem(item);
26796 item.setContent(content);
26802 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26803 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26804 * @return {Roo.TabPanelItem}
26806 getTab : function(id){
26807 return this.items[id];
26811 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26812 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26814 hideTab : function(id){
26815 var t = this.items[id];
26818 this.hiddenCount++;
26819 this.autoSizeTabs();
26824 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26825 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26827 unhideTab : function(id){
26828 var t = this.items[id];
26830 t.setHidden(false);
26831 this.hiddenCount--;
26832 this.autoSizeTabs();
26837 * Adds an existing {@link Roo.TabPanelItem}.
26838 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26840 addTabItem : function(item){
26841 this.items[item.id] = item;
26842 this.items.push(item);
26843 if(this.resizeTabs){
26844 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26845 this.autoSizeTabs();
26852 * Removes a {@link Roo.TabPanelItem}.
26853 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26855 removeTab : function(id){
26856 var items = this.items;
26857 var tab = items[id];
26858 if(!tab) { return; }
26859 var index = items.indexOf(tab);
26860 if(this.active == tab && items.length > 1){
26861 var newTab = this.getNextAvailable(index);
26866 this.stripEl.dom.removeChild(tab.pnode.dom);
26867 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26868 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26870 items.splice(index, 1);
26871 delete this.items[tab.id];
26872 tab.fireEvent("close", tab);
26873 tab.purgeListeners();
26874 this.autoSizeTabs();
26877 getNextAvailable : function(start){
26878 var items = this.items;
26880 // look for a next tab that will slide over to
26881 // replace the one being removed
26882 while(index < items.length){
26883 var item = items[++index];
26884 if(item && !item.isHidden()){
26888 // if one isn't found select the previous tab (on the left)
26891 var item = items[--index];
26892 if(item && !item.isHidden()){
26900 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26901 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26903 disableTab : function(id){
26904 var tab = this.items[id];
26905 if(tab && this.active != tab){
26911 * Enables a {@link Roo.TabPanelItem} that is disabled.
26912 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26914 enableTab : function(id){
26915 var tab = this.items[id];
26920 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26921 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26922 * @return {Roo.TabPanelItem} The TabPanelItem.
26924 activate : function(id){
26925 var tab = this.items[id];
26929 if(tab == this.active || tab.disabled){
26933 this.fireEvent("beforetabchange", this, e, tab);
26934 if(e.cancel !== true && !tab.disabled){
26936 this.active.hide();
26938 this.active = this.items[id];
26939 this.active.show();
26940 this.fireEvent("tabchange", this, this.active);
26946 * Gets the active {@link Roo.TabPanelItem}.
26947 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26949 getActiveTab : function(){
26950 return this.active;
26954 * Updates the tab body element to fit the height of the container element
26955 * for overflow scrolling
26956 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26958 syncHeight : function(targetHeight){
26959 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26960 var bm = this.bodyEl.getMargins();
26961 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26962 this.bodyEl.setHeight(newHeight);
26966 onResize : function(){
26967 if(this.monitorResize){
26968 this.autoSizeTabs();
26973 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26975 beginUpdate : function(){
26976 this.updating = true;
26980 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26982 endUpdate : function(){
26983 this.updating = false;
26984 this.autoSizeTabs();
26988 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26990 autoSizeTabs : function(){
26991 var count = this.items.length;
26992 var vcount = count - this.hiddenCount;
26993 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26994 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26995 var availWidth = Math.floor(w / vcount);
26996 var b = this.stripBody;
26997 if(b.getWidth() > w){
26998 var tabs = this.items;
26999 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27000 if(availWidth < this.minTabWidth){
27001 /*if(!this.sleft){ // incomplete scrolling code
27002 this.createScrollButtons();
27005 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27008 if(this.currentTabWidth < this.preferredTabWidth){
27009 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27015 * Returns the number of tabs in this TabPanel.
27018 getCount : function(){
27019 return this.items.length;
27023 * Resizes all the tabs to the passed width
27024 * @param {Number} The new width
27026 setTabWidth : function(width){
27027 this.currentTabWidth = width;
27028 for(var i = 0, len = this.items.length; i < len; i++) {
27029 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27034 * Destroys this TabPanel
27035 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27037 destroy : function(removeEl){
27038 Roo.EventManager.removeResizeListener(this.onResize, this);
27039 for(var i = 0, len = this.items.length; i < len; i++){
27040 this.items[i].purgeListeners();
27042 if(removeEl === true){
27043 this.el.update("");
27050 * @class Roo.TabPanelItem
27051 * @extends Roo.util.Observable
27052 * Represents an individual item (tab plus body) in a TabPanel.
27053 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27054 * @param {String} id The id of this TabPanelItem
27055 * @param {String} text The text for the tab of this TabPanelItem
27056 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27058 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27060 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27061 * @type Roo.TabPanel
27063 this.tabPanel = tabPanel;
27065 * The id for this TabPanelItem
27070 this.disabled = false;
27074 this.loaded = false;
27075 this.closable = closable;
27078 * The body element for this TabPanelItem.
27079 * @type Roo.Element
27081 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27082 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27083 this.bodyEl.setStyle("display", "block");
27084 this.bodyEl.setStyle("zoom", "1");
27087 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27089 this.el = Roo.get(els.el, true);
27090 this.inner = Roo.get(els.inner, true);
27091 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27092 this.pnode = Roo.get(els.el.parentNode, true);
27093 this.el.on("mousedown", this.onTabMouseDown, this);
27094 this.el.on("click", this.onTabClick, this);
27097 var c = Roo.get(els.close, true);
27098 c.dom.title = this.closeText;
27099 c.addClassOnOver("close-over");
27100 c.on("click", this.closeClick, this);
27106 * Fires when this tab becomes the active tab.
27107 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27108 * @param {Roo.TabPanelItem} this
27112 * @event beforeclose
27113 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27114 * @param {Roo.TabPanelItem} this
27115 * @param {Object} e Set cancel to true on this object to cancel the close.
27117 "beforeclose": true,
27120 * Fires when this tab is closed.
27121 * @param {Roo.TabPanelItem} this
27125 * @event deactivate
27126 * Fires when this tab is no longer the active tab.
27127 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27128 * @param {Roo.TabPanelItem} this
27130 "deactivate" : true
27132 this.hidden = false;
27134 Roo.TabPanelItem.superclass.constructor.call(this);
27137 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27138 purgeListeners : function(){
27139 Roo.util.Observable.prototype.purgeListeners.call(this);
27140 this.el.removeAllListeners();
27143 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27146 this.pnode.addClass("on");
27149 this.tabPanel.stripWrap.repaint();
27151 this.fireEvent("activate", this.tabPanel, this);
27155 * Returns true if this tab is the active tab.
27156 * @return {Boolean}
27158 isActive : function(){
27159 return this.tabPanel.getActiveTab() == this;
27163 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27166 this.pnode.removeClass("on");
27168 this.fireEvent("deactivate", this.tabPanel, this);
27171 hideAction : function(){
27172 this.bodyEl.hide();
27173 this.bodyEl.setStyle("position", "absolute");
27174 this.bodyEl.setLeft("-20000px");
27175 this.bodyEl.setTop("-20000px");
27178 showAction : function(){
27179 this.bodyEl.setStyle("position", "relative");
27180 this.bodyEl.setTop("");
27181 this.bodyEl.setLeft("");
27182 this.bodyEl.show();
27186 * Set the tooltip for the tab.
27187 * @param {String} tooltip The tab's tooltip
27189 setTooltip : function(text){
27190 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27191 this.textEl.dom.qtip = text;
27192 this.textEl.dom.removeAttribute('title');
27194 this.textEl.dom.title = text;
27198 onTabClick : function(e){
27199 e.preventDefault();
27200 this.tabPanel.activate(this.id);
27203 onTabMouseDown : function(e){
27204 e.preventDefault();
27205 this.tabPanel.activate(this.id);
27208 getWidth : function(){
27209 return this.inner.getWidth();
27212 setWidth : function(width){
27213 var iwidth = width - this.pnode.getPadding("lr");
27214 this.inner.setWidth(iwidth);
27215 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27216 this.pnode.setWidth(width);
27220 * Show or hide the tab
27221 * @param {Boolean} hidden True to hide or false to show.
27223 setHidden : function(hidden){
27224 this.hidden = hidden;
27225 this.pnode.setStyle("display", hidden ? "none" : "");
27229 * Returns true if this tab is "hidden"
27230 * @return {Boolean}
27232 isHidden : function(){
27233 return this.hidden;
27237 * Returns the text for this tab
27240 getText : function(){
27244 autoSize : function(){
27245 //this.el.beginMeasure();
27246 this.textEl.setWidth(1);
27248 * #2804 [new] Tabs in Roojs
27249 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27251 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27252 //this.el.endMeasure();
27256 * Sets the text for the tab (Note: this also sets the tooltip text)
27257 * @param {String} text The tab's text and tooltip
27259 setText : function(text){
27261 this.textEl.update(text);
27262 this.setTooltip(text);
27263 if(!this.tabPanel.resizeTabs){
27268 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27270 activate : function(){
27271 this.tabPanel.activate(this.id);
27275 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27277 disable : function(){
27278 if(this.tabPanel.active != this){
27279 this.disabled = true;
27280 this.pnode.addClass("disabled");
27285 * Enables this TabPanelItem if it was previously disabled.
27287 enable : function(){
27288 this.disabled = false;
27289 this.pnode.removeClass("disabled");
27293 * Sets the content for this TabPanelItem.
27294 * @param {String} content The content
27295 * @param {Boolean} loadScripts true to look for and load scripts
27297 setContent : function(content, loadScripts){
27298 this.bodyEl.update(content, loadScripts);
27302 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27303 * @return {Roo.UpdateManager} The UpdateManager
27305 getUpdateManager : function(){
27306 return this.bodyEl.getUpdateManager();
27310 * Set a URL to be used to load the content for this TabPanelItem.
27311 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27312 * @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)
27313 * @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)
27314 * @return {Roo.UpdateManager} The UpdateManager
27316 setUrl : function(url, params, loadOnce){
27317 if(this.refreshDelegate){
27318 this.un('activate', this.refreshDelegate);
27320 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27321 this.on("activate", this.refreshDelegate);
27322 return this.bodyEl.getUpdateManager();
27326 _handleRefresh : function(url, params, loadOnce){
27327 if(!loadOnce || !this.loaded){
27328 var updater = this.bodyEl.getUpdateManager();
27329 updater.update(url, params, this._setLoaded.createDelegate(this));
27334 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27335 * Will fail silently if the setUrl method has not been called.
27336 * This does not activate the panel, just updates its content.
27338 refresh : function(){
27339 if(this.refreshDelegate){
27340 this.loaded = false;
27341 this.refreshDelegate();
27346 _setLoaded : function(){
27347 this.loaded = true;
27351 closeClick : function(e){
27354 this.fireEvent("beforeclose", this, o);
27355 if(o.cancel !== true){
27356 this.tabPanel.removeTab(this.id);
27360 * The text displayed in the tooltip for the close icon.
27363 closeText : "Close this tab"
27367 Roo.TabPanel.prototype.createStrip = function(container){
27368 var strip = document.createElement("div");
27369 strip.className = "x-tabs-wrap";
27370 container.appendChild(strip);
27374 Roo.TabPanel.prototype.createStripList = function(strip){
27375 // div wrapper for retard IE
27376 // returns the "tr" element.
27377 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27378 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27379 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27380 return strip.firstChild.firstChild.firstChild.firstChild;
27383 Roo.TabPanel.prototype.createBody = function(container){
27384 var body = document.createElement("div");
27385 Roo.id(body, "tab-body");
27386 Roo.fly(body).addClass("x-tabs-body");
27387 container.appendChild(body);
27391 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27392 var body = Roo.getDom(id);
27394 body = document.createElement("div");
27397 Roo.fly(body).addClass("x-tabs-item-body");
27398 bodyEl.insertBefore(body, bodyEl.firstChild);
27402 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27403 var td = document.createElement("td");
27404 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27405 //stripEl.appendChild(td);
27407 td.className = "x-tabs-closable";
27408 if(!this.closeTpl){
27409 this.closeTpl = new Roo.Template(
27410 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27411 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27412 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27415 var el = this.closeTpl.overwrite(td, {"text": text});
27416 var close = el.getElementsByTagName("div")[0];
27417 var inner = el.getElementsByTagName("em")[0];
27418 return {"el": el, "close": close, "inner": inner};
27421 this.tabTpl = new Roo.Template(
27422 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27423 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27426 var el = this.tabTpl.overwrite(td, {"text": text});
27427 var inner = el.getElementsByTagName("em")[0];
27428 return {"el": el, "inner": inner};
27432 * Ext JS Library 1.1.1
27433 * Copyright(c) 2006-2007, Ext JS, LLC.
27435 * Originally Released Under LGPL - original licence link has changed is not relivant.
27438 * <script type="text/javascript">
27442 * @class Roo.Button
27443 * @extends Roo.util.Observable
27444 * Simple Button class
27445 * @cfg {String} text The button text
27446 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27447 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27448 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27449 * @cfg {Object} scope The scope of the handler
27450 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27451 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27452 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27453 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27454 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27455 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27456 applies if enableToggle = true)
27457 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27458 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27459 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27461 * Create a new button
27462 * @param {Object} config The config object
27464 Roo.Button = function(renderTo, config)
27468 renderTo = config.renderTo || false;
27471 Roo.apply(this, config);
27475 * Fires when this button is clicked
27476 * @param {Button} this
27477 * @param {EventObject} e The click event
27482 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27483 * @param {Button} this
27484 * @param {Boolean} pressed
27489 * Fires when the mouse hovers over the button
27490 * @param {Button} this
27491 * @param {Event} e The event object
27493 'mouseover' : true,
27496 * Fires when the mouse exits the button
27497 * @param {Button} this
27498 * @param {Event} e The event object
27503 * Fires when the button is rendered
27504 * @param {Button} this
27509 this.menu = Roo.menu.MenuMgr.get(this.menu);
27511 // register listeners first!! - so render can be captured..
27512 Roo.util.Observable.call(this);
27514 this.render(renderTo);
27520 Roo.extend(Roo.Button, Roo.util.Observable, {
27526 * Read-only. True if this button is hidden
27531 * Read-only. True if this button is disabled
27536 * Read-only. True if this button is pressed (only if enableToggle = true)
27542 * @cfg {Number} tabIndex
27543 * The DOM tabIndex for this button (defaults to undefined)
27545 tabIndex : undefined,
27548 * @cfg {Boolean} enableToggle
27549 * True to enable pressed/not pressed toggling (defaults to false)
27551 enableToggle: false,
27553 * @cfg {Mixed} menu
27554 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27558 * @cfg {String} menuAlign
27559 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27561 menuAlign : "tl-bl?",
27564 * @cfg {String} iconCls
27565 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27567 iconCls : undefined,
27569 * @cfg {String} type
27570 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27575 menuClassTarget: 'tr',
27578 * @cfg {String} clickEvent
27579 * The type of event to map to the button's event handler (defaults to 'click')
27581 clickEvent : 'click',
27584 * @cfg {Boolean} handleMouseEvents
27585 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27587 handleMouseEvents : true,
27590 * @cfg {String} tooltipType
27591 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27593 tooltipType : 'qtip',
27596 * @cfg {String} cls
27597 * A CSS class to apply to the button's main element.
27601 * @cfg {Roo.Template} template (Optional)
27602 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27603 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27604 * require code modifications if required elements (e.g. a button) aren't present.
27608 render : function(renderTo){
27610 if(this.hideParent){
27611 this.parentEl = Roo.get(renderTo);
27613 if(!this.dhconfig){
27614 if(!this.template){
27615 if(!Roo.Button.buttonTemplate){
27616 // hideous table template
27617 Roo.Button.buttonTemplate = new Roo.Template(
27618 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27619 '<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>',
27620 "</tr></tbody></table>");
27622 this.template = Roo.Button.buttonTemplate;
27624 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27625 var btnEl = btn.child("button:first");
27626 btnEl.on('focus', this.onFocus, this);
27627 btnEl.on('blur', this.onBlur, this);
27629 btn.addClass(this.cls);
27632 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27635 btnEl.addClass(this.iconCls);
27637 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27640 if(this.tabIndex !== undefined){
27641 btnEl.dom.tabIndex = this.tabIndex;
27644 if(typeof this.tooltip == 'object'){
27645 Roo.QuickTips.tips(Roo.apply({
27649 btnEl.dom[this.tooltipType] = this.tooltip;
27653 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27657 this.el.dom.id = this.el.id = this.id;
27660 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27661 this.menu.on("show", this.onMenuShow, this);
27662 this.menu.on("hide", this.onMenuHide, this);
27664 btn.addClass("x-btn");
27665 if(Roo.isIE && !Roo.isIE7){
27666 this.autoWidth.defer(1, this);
27670 if(this.handleMouseEvents){
27671 btn.on("mouseover", this.onMouseOver, this);
27672 btn.on("mouseout", this.onMouseOut, this);
27673 btn.on("mousedown", this.onMouseDown, this);
27675 btn.on(this.clickEvent, this.onClick, this);
27676 //btn.on("mouseup", this.onMouseUp, this);
27683 Roo.ButtonToggleMgr.register(this);
27685 this.el.addClass("x-btn-pressed");
27688 var repeater = new Roo.util.ClickRepeater(btn,
27689 typeof this.repeat == "object" ? this.repeat : {}
27691 repeater.on("click", this.onClick, this);
27694 this.fireEvent('render', this);
27698 * Returns the button's underlying element
27699 * @return {Roo.Element} The element
27701 getEl : function(){
27706 * Destroys this Button and removes any listeners.
27708 destroy : function(){
27709 Roo.ButtonToggleMgr.unregister(this);
27710 this.el.removeAllListeners();
27711 this.purgeListeners();
27716 autoWidth : function(){
27718 this.el.setWidth("auto");
27719 if(Roo.isIE7 && Roo.isStrict){
27720 var ib = this.el.child('button');
27721 if(ib && ib.getWidth() > 20){
27723 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27728 this.el.beginMeasure();
27730 if(this.el.getWidth() < this.minWidth){
27731 this.el.setWidth(this.minWidth);
27734 this.el.endMeasure();
27741 * Assigns this button's click handler
27742 * @param {Function} handler The function to call when the button is clicked
27743 * @param {Object} scope (optional) Scope for the function passed in
27745 setHandler : function(handler, scope){
27746 this.handler = handler;
27747 this.scope = scope;
27751 * Sets this button's text
27752 * @param {String} text The button text
27754 setText : function(text){
27757 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27763 * Gets the text for this button
27764 * @return {String} The button text
27766 getText : function(){
27774 this.hidden = false;
27776 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27784 this.hidden = true;
27786 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27791 * Convenience function for boolean show/hide
27792 * @param {Boolean} visible True to show, false to hide
27794 setVisible: function(visible){
27803 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27804 * @param {Boolean} state (optional) Force a particular state
27806 toggle : function(state){
27807 state = state === undefined ? !this.pressed : state;
27808 if(state != this.pressed){
27810 this.el.addClass("x-btn-pressed");
27811 this.pressed = true;
27812 this.fireEvent("toggle", this, true);
27814 this.el.removeClass("x-btn-pressed");
27815 this.pressed = false;
27816 this.fireEvent("toggle", this, false);
27818 if(this.toggleHandler){
27819 this.toggleHandler.call(this.scope || this, this, state);
27827 focus : function(){
27828 this.el.child('button:first').focus();
27832 * Disable this button
27834 disable : function(){
27836 this.el.addClass("x-btn-disabled");
27838 this.disabled = true;
27842 * Enable this button
27844 enable : function(){
27846 this.el.removeClass("x-btn-disabled");
27848 this.disabled = false;
27852 * Convenience function for boolean enable/disable
27853 * @param {Boolean} enabled True to enable, false to disable
27855 setDisabled : function(v){
27856 this[v !== true ? "enable" : "disable"]();
27860 onClick : function(e){
27862 e.preventDefault();
27867 if(!this.disabled){
27868 if(this.enableToggle){
27871 if(this.menu && !this.menu.isVisible()){
27872 this.menu.show(this.el, this.menuAlign);
27874 this.fireEvent("click", this, e);
27876 this.el.removeClass("x-btn-over");
27877 this.handler.call(this.scope || this, this, e);
27882 onMouseOver : function(e){
27883 if(!this.disabled){
27884 this.el.addClass("x-btn-over");
27885 this.fireEvent('mouseover', this, e);
27889 onMouseOut : function(e){
27890 if(!e.within(this.el, true)){
27891 this.el.removeClass("x-btn-over");
27892 this.fireEvent('mouseout', this, e);
27896 onFocus : function(e){
27897 if(!this.disabled){
27898 this.el.addClass("x-btn-focus");
27902 onBlur : function(e){
27903 this.el.removeClass("x-btn-focus");
27906 onMouseDown : function(e){
27907 if(!this.disabled && e.button == 0){
27908 this.el.addClass("x-btn-click");
27909 Roo.get(document).on('mouseup', this.onMouseUp, this);
27913 onMouseUp : function(e){
27915 this.el.removeClass("x-btn-click");
27916 Roo.get(document).un('mouseup', this.onMouseUp, this);
27920 onMenuShow : function(e){
27921 this.el.addClass("x-btn-menu-active");
27924 onMenuHide : function(e){
27925 this.el.removeClass("x-btn-menu-active");
27929 // Private utility class used by Button
27930 Roo.ButtonToggleMgr = function(){
27933 function toggleGroup(btn, state){
27935 var g = groups[btn.toggleGroup];
27936 for(var i = 0, l = g.length; i < l; i++){
27938 g[i].toggle(false);
27945 register : function(btn){
27946 if(!btn.toggleGroup){
27949 var g = groups[btn.toggleGroup];
27951 g = groups[btn.toggleGroup] = [];
27954 btn.on("toggle", toggleGroup);
27957 unregister : function(btn){
27958 if(!btn.toggleGroup){
27961 var g = groups[btn.toggleGroup];
27964 btn.un("toggle", toggleGroup);
27970 * Ext JS Library 1.1.1
27971 * Copyright(c) 2006-2007, Ext JS, LLC.
27973 * Originally Released Under LGPL - original licence link has changed is not relivant.
27976 * <script type="text/javascript">
27980 * @class Roo.SplitButton
27981 * @extends Roo.Button
27982 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27983 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27984 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27985 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27986 * @cfg {String} arrowTooltip The title attribute of the arrow
27988 * Create a new menu button
27989 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27990 * @param {Object} config The config object
27992 Roo.SplitButton = function(renderTo, config){
27993 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27995 * @event arrowclick
27996 * Fires when this button's arrow is clicked
27997 * @param {SplitButton} this
27998 * @param {EventObject} e The click event
28000 this.addEvents({"arrowclick":true});
28003 Roo.extend(Roo.SplitButton, Roo.Button, {
28004 render : function(renderTo){
28005 // this is one sweet looking template!
28006 var tpl = new Roo.Template(
28007 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28008 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28009 '<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>',
28010 "</tbody></table></td><td>",
28011 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28012 '<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>',
28013 "</tbody></table></td></tr></table>"
28015 var btn = tpl.append(renderTo, [this.text, this.type], true);
28016 var btnEl = btn.child("button");
28018 btn.addClass(this.cls);
28021 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28024 btnEl.addClass(this.iconCls);
28026 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28030 if(this.handleMouseEvents){
28031 btn.on("mouseover", this.onMouseOver, this);
28032 btn.on("mouseout", this.onMouseOut, this);
28033 btn.on("mousedown", this.onMouseDown, this);
28034 btn.on("mouseup", this.onMouseUp, this);
28036 btn.on(this.clickEvent, this.onClick, this);
28038 if(typeof this.tooltip == 'object'){
28039 Roo.QuickTips.tips(Roo.apply({
28043 btnEl.dom[this.tooltipType] = this.tooltip;
28046 if(this.arrowTooltip){
28047 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28056 this.el.addClass("x-btn-pressed");
28058 if(Roo.isIE && !Roo.isIE7){
28059 this.autoWidth.defer(1, this);
28064 this.menu.on("show", this.onMenuShow, this);
28065 this.menu.on("hide", this.onMenuHide, this);
28067 this.fireEvent('render', this);
28071 autoWidth : function(){
28073 var tbl = this.el.child("table:first");
28074 var tbl2 = this.el.child("table:last");
28075 this.el.setWidth("auto");
28076 tbl.setWidth("auto");
28077 if(Roo.isIE7 && Roo.isStrict){
28078 var ib = this.el.child('button:first');
28079 if(ib && ib.getWidth() > 20){
28081 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28086 this.el.beginMeasure();
28088 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28089 tbl.setWidth(this.minWidth-tbl2.getWidth());
28092 this.el.endMeasure();
28095 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28099 * Sets this button's click handler
28100 * @param {Function} handler The function to call when the button is clicked
28101 * @param {Object} scope (optional) Scope for the function passed above
28103 setHandler : function(handler, scope){
28104 this.handler = handler;
28105 this.scope = scope;
28109 * Sets this button's arrow click handler
28110 * @param {Function} handler The function to call when the arrow is clicked
28111 * @param {Object} scope (optional) Scope for the function passed above
28113 setArrowHandler : function(handler, scope){
28114 this.arrowHandler = handler;
28115 this.scope = scope;
28121 focus : function(){
28123 this.el.child("button:first").focus();
28128 onClick : function(e){
28129 e.preventDefault();
28130 if(!this.disabled){
28131 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28132 if(this.menu && !this.menu.isVisible()){
28133 this.menu.show(this.el, this.menuAlign);
28135 this.fireEvent("arrowclick", this, e);
28136 if(this.arrowHandler){
28137 this.arrowHandler.call(this.scope || this, this, e);
28140 this.fireEvent("click", this, e);
28142 this.handler.call(this.scope || this, this, e);
28148 onMouseDown : function(e){
28149 if(!this.disabled){
28150 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28154 onMouseUp : function(e){
28155 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28160 // backwards compat
28161 Roo.MenuButton = Roo.SplitButton;/*
28163 * Ext JS Library 1.1.1
28164 * Copyright(c) 2006-2007, Ext JS, LLC.
28166 * Originally Released Under LGPL - original licence link has changed is not relivant.
28169 * <script type="text/javascript">
28173 * @class Roo.Toolbar
28174 * Basic Toolbar class.
28176 * Creates a new Toolbar
28177 * @param {Object} container The config object
28179 Roo.Toolbar = function(container, buttons, config)
28181 /// old consturctor format still supported..
28182 if(container instanceof Array){ // omit the container for later rendering
28183 buttons = container;
28187 if (typeof(container) == 'object' && container.xtype) {
28188 config = container;
28189 container = config.container;
28190 buttons = config.buttons || []; // not really - use items!!
28193 if (config && config.items) {
28194 xitems = config.items;
28195 delete config.items;
28197 Roo.apply(this, config);
28198 this.buttons = buttons;
28201 this.render(container);
28203 this.xitems = xitems;
28204 Roo.each(xitems, function(b) {
28210 Roo.Toolbar.prototype = {
28212 * @cfg {Array} items
28213 * array of button configs or elements to add (will be converted to a MixedCollection)
28217 * @cfg {String/HTMLElement/Element} container
28218 * The id or element that will contain the toolbar
28221 render : function(ct){
28222 this.el = Roo.get(ct);
28224 this.el.addClass(this.cls);
28226 // using a table allows for vertical alignment
28227 // 100% width is needed by Safari...
28228 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28229 this.tr = this.el.child("tr", true);
28231 this.items = new Roo.util.MixedCollection(false, function(o){
28232 return o.id || ("item" + (++autoId));
28235 this.add.apply(this, this.buttons);
28236 delete this.buttons;
28241 * Adds element(s) to the toolbar -- this function takes a variable number of
28242 * arguments of mixed type and adds them to the toolbar.
28243 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28245 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28246 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28247 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28248 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28249 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28250 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28251 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28252 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28253 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28255 * @param {Mixed} arg2
28256 * @param {Mixed} etc.
28259 var a = arguments, l = a.length;
28260 for(var i = 0; i < l; i++){
28265 _add : function(el) {
28268 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28271 if (el.applyTo){ // some kind of form field
28272 return this.addField(el);
28274 if (el.render){ // some kind of Toolbar.Item
28275 return this.addItem(el);
28277 if (typeof el == "string"){ // string
28278 if(el == "separator" || el == "-"){
28279 return this.addSeparator();
28282 return this.addSpacer();
28285 return this.addFill();
28287 return this.addText(el);
28290 if(el.tagName){ // element
28291 return this.addElement(el);
28293 if(typeof el == "object"){ // must be button config?
28294 return this.addButton(el);
28296 // and now what?!?!
28302 * Add an Xtype element
28303 * @param {Object} xtype Xtype Object
28304 * @return {Object} created Object
28306 addxtype : function(e){
28307 return this.add(e);
28311 * Returns the Element for this toolbar.
28312 * @return {Roo.Element}
28314 getEl : function(){
28320 * @return {Roo.Toolbar.Item} The separator item
28322 addSeparator : function(){
28323 return this.addItem(new Roo.Toolbar.Separator());
28327 * Adds a spacer element
28328 * @return {Roo.Toolbar.Spacer} The spacer item
28330 addSpacer : function(){
28331 return this.addItem(new Roo.Toolbar.Spacer());
28335 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28336 * @return {Roo.Toolbar.Fill} The fill item
28338 addFill : function(){
28339 return this.addItem(new Roo.Toolbar.Fill());
28343 * Adds any standard HTML element to the toolbar
28344 * @param {String/HTMLElement/Element} el The element or id of the element to add
28345 * @return {Roo.Toolbar.Item} The element's item
28347 addElement : function(el){
28348 return this.addItem(new Roo.Toolbar.Item(el));
28351 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28352 * @type Roo.util.MixedCollection
28357 * Adds any Toolbar.Item or subclass
28358 * @param {Roo.Toolbar.Item} item
28359 * @return {Roo.Toolbar.Item} The item
28361 addItem : function(item){
28362 var td = this.nextBlock();
28364 this.items.add(item);
28369 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28370 * @param {Object/Array} config A button config or array of configs
28371 * @return {Roo.Toolbar.Button/Array}
28373 addButton : function(config){
28374 if(config instanceof Array){
28376 for(var i = 0, len = config.length; i < len; i++) {
28377 buttons.push(this.addButton(config[i]));
28382 if(!(config instanceof Roo.Toolbar.Button)){
28384 new Roo.Toolbar.SplitButton(config) :
28385 new Roo.Toolbar.Button(config);
28387 var td = this.nextBlock();
28394 * Adds text to the toolbar
28395 * @param {String} text The text to add
28396 * @return {Roo.Toolbar.Item} The element's item
28398 addText : function(text){
28399 return this.addItem(new Roo.Toolbar.TextItem(text));
28403 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28404 * @param {Number} index The index where the item is to be inserted
28405 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28406 * @return {Roo.Toolbar.Button/Item}
28408 insertButton : function(index, item){
28409 if(item instanceof Array){
28411 for(var i = 0, len = item.length; i < len; i++) {
28412 buttons.push(this.insertButton(index + i, item[i]));
28416 if (!(item instanceof Roo.Toolbar.Button)){
28417 item = new Roo.Toolbar.Button(item);
28419 var td = document.createElement("td");
28420 this.tr.insertBefore(td, this.tr.childNodes[index]);
28422 this.items.insert(index, item);
28427 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28428 * @param {Object} config
28429 * @return {Roo.Toolbar.Item} The element's item
28431 addDom : function(config, returnEl){
28432 var td = this.nextBlock();
28433 Roo.DomHelper.overwrite(td, config);
28434 var ti = new Roo.Toolbar.Item(td.firstChild);
28436 this.items.add(ti);
28441 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28442 * @type Roo.util.MixedCollection
28447 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28448 * Note: the field should not have been rendered yet. For a field that has already been
28449 * rendered, use {@link #addElement}.
28450 * @param {Roo.form.Field} field
28451 * @return {Roo.ToolbarItem}
28455 addField : function(field) {
28456 if (!this.fields) {
28458 this.fields = new Roo.util.MixedCollection(false, function(o){
28459 return o.id || ("item" + (++autoId));
28464 var td = this.nextBlock();
28466 var ti = new Roo.Toolbar.Item(td.firstChild);
28468 this.items.add(ti);
28469 this.fields.add(field);
28480 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28481 this.el.child('div').hide();
28489 this.el.child('div').show();
28493 nextBlock : function(){
28494 var td = document.createElement("td");
28495 this.tr.appendChild(td);
28500 destroy : function(){
28501 if(this.items){ // rendered?
28502 Roo.destroy.apply(Roo, this.items.items);
28504 if(this.fields){ // rendered?
28505 Roo.destroy.apply(Roo, this.fields.items);
28507 Roo.Element.uncache(this.el, this.tr);
28512 * @class Roo.Toolbar.Item
28513 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28515 * Creates a new Item
28516 * @param {HTMLElement} el
28518 Roo.Toolbar.Item = function(el){
28519 this.el = Roo.getDom(el);
28520 this.id = Roo.id(this.el);
28521 this.hidden = false;
28524 Roo.Toolbar.Item.prototype = {
28527 * Get this item's HTML Element
28528 * @return {HTMLElement}
28530 getEl : function(){
28535 render : function(td){
28537 td.appendChild(this.el);
28541 * Removes and destroys this item.
28543 destroy : function(){
28544 this.td.parentNode.removeChild(this.td);
28551 this.hidden = false;
28552 this.td.style.display = "";
28559 this.hidden = true;
28560 this.td.style.display = "none";
28564 * Convenience function for boolean show/hide.
28565 * @param {Boolean} visible true to show/false to hide
28567 setVisible: function(visible){
28576 * Try to focus this item.
28578 focus : function(){
28579 Roo.fly(this.el).focus();
28583 * Disables this item.
28585 disable : function(){
28586 Roo.fly(this.td).addClass("x-item-disabled");
28587 this.disabled = true;
28588 this.el.disabled = true;
28592 * Enables this item.
28594 enable : function(){
28595 Roo.fly(this.td).removeClass("x-item-disabled");
28596 this.disabled = false;
28597 this.el.disabled = false;
28603 * @class Roo.Toolbar.Separator
28604 * @extends Roo.Toolbar.Item
28605 * A simple toolbar separator class
28607 * Creates a new Separator
28609 Roo.Toolbar.Separator = function(){
28610 var s = document.createElement("span");
28611 s.className = "ytb-sep";
28612 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28614 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28615 enable:Roo.emptyFn,
28616 disable:Roo.emptyFn,
28621 * @class Roo.Toolbar.Spacer
28622 * @extends Roo.Toolbar.Item
28623 * A simple element that adds extra horizontal space to a toolbar.
28625 * Creates a new Spacer
28627 Roo.Toolbar.Spacer = function(){
28628 var s = document.createElement("div");
28629 s.className = "ytb-spacer";
28630 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28632 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28633 enable:Roo.emptyFn,
28634 disable:Roo.emptyFn,
28639 * @class Roo.Toolbar.Fill
28640 * @extends Roo.Toolbar.Spacer
28641 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28643 * Creates a new Spacer
28645 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28647 render : function(td){
28648 td.style.width = '100%';
28649 Roo.Toolbar.Fill.superclass.render.call(this, td);
28654 * @class Roo.Toolbar.TextItem
28655 * @extends Roo.Toolbar.Item
28656 * A simple class that renders text directly into a toolbar.
28658 * Creates a new TextItem
28659 * @param {String} text
28661 Roo.Toolbar.TextItem = function(text){
28662 if (typeof(text) == 'object') {
28665 var s = document.createElement("span");
28666 s.className = "ytb-text";
28667 s.innerHTML = text;
28668 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28670 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28671 enable:Roo.emptyFn,
28672 disable:Roo.emptyFn,
28677 * @class Roo.Toolbar.Button
28678 * @extends Roo.Button
28679 * A button that renders into a toolbar.
28681 * Creates a new Button
28682 * @param {Object} config A standard {@link Roo.Button} config object
28684 Roo.Toolbar.Button = function(config){
28685 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28687 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28688 render : function(td){
28690 Roo.Toolbar.Button.superclass.render.call(this, td);
28694 * Removes and destroys this button
28696 destroy : function(){
28697 Roo.Toolbar.Button.superclass.destroy.call(this);
28698 this.td.parentNode.removeChild(this.td);
28702 * Shows this button
28705 this.hidden = false;
28706 this.td.style.display = "";
28710 * Hides this button
28713 this.hidden = true;
28714 this.td.style.display = "none";
28718 * Disables this item
28720 disable : function(){
28721 Roo.fly(this.td).addClass("x-item-disabled");
28722 this.disabled = true;
28726 * Enables this item
28728 enable : function(){
28729 Roo.fly(this.td).removeClass("x-item-disabled");
28730 this.disabled = false;
28733 // backwards compat
28734 Roo.ToolbarButton = Roo.Toolbar.Button;
28737 * @class Roo.Toolbar.SplitButton
28738 * @extends Roo.SplitButton
28739 * A menu button that renders into a toolbar.
28741 * Creates a new SplitButton
28742 * @param {Object} config A standard {@link Roo.SplitButton} config object
28744 Roo.Toolbar.SplitButton = function(config){
28745 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28747 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28748 render : function(td){
28750 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28754 * Removes and destroys this button
28756 destroy : function(){
28757 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28758 this.td.parentNode.removeChild(this.td);
28762 * Shows this button
28765 this.hidden = false;
28766 this.td.style.display = "";
28770 * Hides this button
28773 this.hidden = true;
28774 this.td.style.display = "none";
28778 // backwards compat
28779 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28781 * Ext JS Library 1.1.1
28782 * Copyright(c) 2006-2007, Ext JS, LLC.
28784 * Originally Released Under LGPL - original licence link has changed is not relivant.
28787 * <script type="text/javascript">
28791 * @class Roo.PagingToolbar
28792 * @extends Roo.Toolbar
28793 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28795 * Create a new PagingToolbar
28796 * @param {Object} config The config object
28798 Roo.PagingToolbar = function(el, ds, config)
28800 // old args format still supported... - xtype is prefered..
28801 if (typeof(el) == 'object' && el.xtype) {
28802 // created from xtype...
28804 ds = el.dataSource;
28805 el = config.container;
28808 if (config.items) {
28809 items = config.items;
28813 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28816 this.renderButtons(this.el);
28819 // supprot items array.
28821 Roo.each(items, function(e) {
28822 this.add(Roo.factory(e));
28827 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28829 * @cfg {Roo.data.Store} dataSource
28830 * The underlying data store providing the paged data
28833 * @cfg {String/HTMLElement/Element} container
28834 * container The id or element that will contain the toolbar
28837 * @cfg {Boolean} displayInfo
28838 * True to display the displayMsg (defaults to false)
28841 * @cfg {Number} pageSize
28842 * The number of records to display per page (defaults to 20)
28846 * @cfg {String} displayMsg
28847 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28849 displayMsg : 'Displaying {0} - {1} of {2}',
28851 * @cfg {String} emptyMsg
28852 * The message to display when no records are found (defaults to "No data to display")
28854 emptyMsg : 'No data to display',
28856 * Customizable piece of the default paging text (defaults to "Page")
28859 beforePageText : "Page",
28861 * Customizable piece of the default paging text (defaults to "of %0")
28864 afterPageText : "of {0}",
28866 * Customizable piece of the default paging text (defaults to "First Page")
28869 firstText : "First Page",
28871 * Customizable piece of the default paging text (defaults to "Previous Page")
28874 prevText : "Previous Page",
28876 * Customizable piece of the default paging text (defaults to "Next Page")
28879 nextText : "Next Page",
28881 * Customizable piece of the default paging text (defaults to "Last Page")
28884 lastText : "Last Page",
28886 * Customizable piece of the default paging text (defaults to "Refresh")
28889 refreshText : "Refresh",
28892 renderButtons : function(el){
28893 Roo.PagingToolbar.superclass.render.call(this, el);
28894 this.first = this.addButton({
28895 tooltip: this.firstText,
28896 cls: "x-btn-icon x-grid-page-first",
28898 handler: this.onClick.createDelegate(this, ["first"])
28900 this.prev = this.addButton({
28901 tooltip: this.prevText,
28902 cls: "x-btn-icon x-grid-page-prev",
28904 handler: this.onClick.createDelegate(this, ["prev"])
28906 //this.addSeparator();
28907 this.add(this.beforePageText);
28908 this.field = Roo.get(this.addDom({
28913 cls: "x-grid-page-number"
28915 this.field.on("keydown", this.onPagingKeydown, this);
28916 this.field.on("focus", function(){this.dom.select();});
28917 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28918 this.field.setHeight(18);
28919 //this.addSeparator();
28920 this.next = this.addButton({
28921 tooltip: this.nextText,
28922 cls: "x-btn-icon x-grid-page-next",
28924 handler: this.onClick.createDelegate(this, ["next"])
28926 this.last = this.addButton({
28927 tooltip: this.lastText,
28928 cls: "x-btn-icon x-grid-page-last",
28930 handler: this.onClick.createDelegate(this, ["last"])
28932 //this.addSeparator();
28933 this.loading = this.addButton({
28934 tooltip: this.refreshText,
28935 cls: "x-btn-icon x-grid-loading",
28936 handler: this.onClick.createDelegate(this, ["refresh"])
28939 if(this.displayInfo){
28940 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28945 updateInfo : function(){
28946 if(this.displayEl){
28947 var count = this.ds.getCount();
28948 var msg = count == 0 ?
28952 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28954 this.displayEl.update(msg);
28959 onLoad : function(ds, r, o){
28960 this.cursor = o.params ? o.params.start : 0;
28961 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28963 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28964 this.field.dom.value = ap;
28965 this.first.setDisabled(ap == 1);
28966 this.prev.setDisabled(ap == 1);
28967 this.next.setDisabled(ap == ps);
28968 this.last.setDisabled(ap == ps);
28969 this.loading.enable();
28974 getPageData : function(){
28975 var total = this.ds.getTotalCount();
28978 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28979 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28984 onLoadError : function(){
28985 this.loading.enable();
28989 onPagingKeydown : function(e){
28990 var k = e.getKey();
28991 var d = this.getPageData();
28993 var v = this.field.dom.value, pageNum;
28994 if(!v || isNaN(pageNum = parseInt(v, 10))){
28995 this.field.dom.value = d.activePage;
28998 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28999 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29002 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))
29004 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29005 this.field.dom.value = pageNum;
29006 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29009 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29011 var v = this.field.dom.value, pageNum;
29012 var increment = (e.shiftKey) ? 10 : 1;
29013 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29015 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29016 this.field.dom.value = d.activePage;
29019 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29021 this.field.dom.value = parseInt(v, 10) + increment;
29022 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29023 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29030 beforeLoad : function(){
29032 this.loading.disable();
29037 onClick : function(which){
29041 ds.load({params:{start: 0, limit: this.pageSize}});
29044 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29047 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29050 var total = ds.getTotalCount();
29051 var extra = total % this.pageSize;
29052 var lastStart = extra ? (total - extra) : total-this.pageSize;
29053 ds.load({params:{start: lastStart, limit: this.pageSize}});
29056 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29062 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29063 * @param {Roo.data.Store} store The data store to unbind
29065 unbind : function(ds){
29066 ds.un("beforeload", this.beforeLoad, this);
29067 ds.un("load", this.onLoad, this);
29068 ds.un("loadexception", this.onLoadError, this);
29069 ds.un("remove", this.updateInfo, this);
29070 ds.un("add", this.updateInfo, this);
29071 this.ds = undefined;
29075 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29076 * @param {Roo.data.Store} store The data store to bind
29078 bind : function(ds){
29079 ds.on("beforeload", this.beforeLoad, this);
29080 ds.on("load", this.onLoad, this);
29081 ds.on("loadexception", this.onLoadError, this);
29082 ds.on("remove", this.updateInfo, this);
29083 ds.on("add", this.updateInfo, this);
29088 * Ext JS Library 1.1.1
29089 * Copyright(c) 2006-2007, Ext JS, LLC.
29091 * Originally Released Under LGPL - original licence link has changed is not relivant.
29094 * <script type="text/javascript">
29098 * @class Roo.Resizable
29099 * @extends Roo.util.Observable
29100 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29101 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29102 * 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
29103 * the element will be wrapped for you automatically.</p>
29104 * <p>Here is the list of valid resize handles:</p>
29107 ------ -------------------
29116 'hd' horizontal drag
29119 * <p>Here's an example showing the creation of a typical Resizable:</p>
29121 var resizer = new Roo.Resizable("element-id", {
29129 resizer.on("resize", myHandler);
29131 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29132 * resizer.east.setDisplayed(false);</p>
29133 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29134 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29135 * resize operation's new size (defaults to [0, 0])
29136 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29137 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29138 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29139 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29140 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29141 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29142 * @cfg {Number} width The width of the element in pixels (defaults to null)
29143 * @cfg {Number} height The height of the element in pixels (defaults to null)
29144 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29145 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29146 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29147 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29148 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29149 * in favor of the handles config option (defaults to false)
29150 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29151 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29152 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29153 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29154 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29155 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29156 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29157 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29158 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29159 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29160 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29162 * Create a new resizable component
29163 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29164 * @param {Object} config configuration options
29166 Roo.Resizable = function(el, config)
29168 this.el = Roo.get(el);
29170 if(config && config.wrap){
29171 config.resizeChild = this.el;
29172 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29173 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29174 this.el.setStyle("overflow", "hidden");
29175 this.el.setPositioning(config.resizeChild.getPositioning());
29176 config.resizeChild.clearPositioning();
29177 if(!config.width || !config.height){
29178 var csize = config.resizeChild.getSize();
29179 this.el.setSize(csize.width, csize.height);
29181 if(config.pinned && !config.adjustments){
29182 config.adjustments = "auto";
29186 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29187 this.proxy.unselectable();
29188 this.proxy.enableDisplayMode('block');
29190 Roo.apply(this, config);
29193 this.disableTrackOver = true;
29194 this.el.addClass("x-resizable-pinned");
29196 // if the element isn't positioned, make it relative
29197 var position = this.el.getStyle("position");
29198 if(position != "absolute" && position != "fixed"){
29199 this.el.setStyle("position", "relative");
29201 if(!this.handles){ // no handles passed, must be legacy style
29202 this.handles = 's,e,se';
29203 if(this.multiDirectional){
29204 this.handles += ',n,w';
29207 if(this.handles == "all"){
29208 this.handles = "n s e w ne nw se sw";
29210 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29211 var ps = Roo.Resizable.positions;
29212 for(var i = 0, len = hs.length; i < len; i++){
29213 if(hs[i] && ps[hs[i]]){
29214 var pos = ps[hs[i]];
29215 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29219 this.corner = this.southeast;
29221 // updateBox = the box can move..
29222 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29223 this.updateBox = true;
29226 this.activeHandle = null;
29228 if(this.resizeChild){
29229 if(typeof this.resizeChild == "boolean"){
29230 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29232 this.resizeChild = Roo.get(this.resizeChild, true);
29236 if(this.adjustments == "auto"){
29237 var rc = this.resizeChild;
29238 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29239 if(rc && (hw || hn)){
29240 rc.position("relative");
29241 rc.setLeft(hw ? hw.el.getWidth() : 0);
29242 rc.setTop(hn ? hn.el.getHeight() : 0);
29244 this.adjustments = [
29245 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29246 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29250 if(this.draggable){
29251 this.dd = this.dynamic ?
29252 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29253 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29259 * @event beforeresize
29260 * Fired before resize is allowed. Set enabled to false to cancel resize.
29261 * @param {Roo.Resizable} this
29262 * @param {Roo.EventObject} e The mousedown event
29264 "beforeresize" : true,
29267 * Fired a resizing.
29268 * @param {Roo.Resizable} this
29269 * @param {Number} x The new x position
29270 * @param {Number} y The new y position
29271 * @param {Number} w The new w width
29272 * @param {Number} h The new h hight
29273 * @param {Roo.EventObject} e The mouseup event
29278 * Fired after a resize.
29279 * @param {Roo.Resizable} this
29280 * @param {Number} width The new width
29281 * @param {Number} height The new height
29282 * @param {Roo.EventObject} e The mouseup event
29287 if(this.width !== null && this.height !== null){
29288 this.resizeTo(this.width, this.height);
29290 this.updateChildSize();
29293 this.el.dom.style.zoom = 1;
29295 Roo.Resizable.superclass.constructor.call(this);
29298 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29299 resizeChild : false,
29300 adjustments : [0, 0],
29310 multiDirectional : false,
29311 disableTrackOver : false,
29312 easing : 'easeOutStrong',
29313 widthIncrement : 0,
29314 heightIncrement : 0,
29318 preserveRatio : false,
29319 transparent: false,
29325 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29327 constrainTo: undefined,
29329 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29331 resizeRegion: undefined,
29335 * Perform a manual resize
29336 * @param {Number} width
29337 * @param {Number} height
29339 resizeTo : function(width, height){
29340 this.el.setSize(width, height);
29341 this.updateChildSize();
29342 this.fireEvent("resize", this, width, height, null);
29346 startSizing : function(e, handle){
29347 this.fireEvent("beforeresize", this, e);
29348 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29351 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29352 this.overlay.unselectable();
29353 this.overlay.enableDisplayMode("block");
29354 this.overlay.on("mousemove", this.onMouseMove, this);
29355 this.overlay.on("mouseup", this.onMouseUp, this);
29357 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29359 this.resizing = true;
29360 this.startBox = this.el.getBox();
29361 this.startPoint = e.getXY();
29362 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29363 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29365 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29366 this.overlay.show();
29368 if(this.constrainTo) {
29369 var ct = Roo.get(this.constrainTo);
29370 this.resizeRegion = ct.getRegion().adjust(
29371 ct.getFrameWidth('t'),
29372 ct.getFrameWidth('l'),
29373 -ct.getFrameWidth('b'),
29374 -ct.getFrameWidth('r')
29378 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29380 this.proxy.setBox(this.startBox);
29382 this.proxy.setStyle('visibility', 'visible');
29388 onMouseDown : function(handle, e){
29391 this.activeHandle = handle;
29392 this.startSizing(e, handle);
29397 onMouseUp : function(e){
29398 var size = this.resizeElement();
29399 this.resizing = false;
29401 this.overlay.hide();
29403 this.fireEvent("resize", this, size.width, size.height, e);
29407 updateChildSize : function(){
29409 if(this.resizeChild){
29411 var child = this.resizeChild;
29412 var adj = this.adjustments;
29413 if(el.dom.offsetWidth){
29414 var b = el.getSize(true);
29415 child.setSize(b.width+adj[0], b.height+adj[1]);
29417 // Second call here for IE
29418 // The first call enables instant resizing and
29419 // the second call corrects scroll bars if they
29422 setTimeout(function(){
29423 if(el.dom.offsetWidth){
29424 var b = el.getSize(true);
29425 child.setSize(b.width+adj[0], b.height+adj[1]);
29433 snap : function(value, inc, min){
29434 if(!inc || !value) return value;
29435 var newValue = value;
29436 var m = value % inc;
29439 newValue = value + (inc-m);
29441 newValue = value - m;
29444 return Math.max(min, newValue);
29448 resizeElement : function(){
29449 var box = this.proxy.getBox();
29450 if(this.updateBox){
29451 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29453 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29455 this.updateChildSize();
29463 constrain : function(v, diff, m, mx){
29466 }else if(v - diff > mx){
29473 onMouseMove : function(e){
29476 try{// try catch so if something goes wrong the user doesn't get hung
29478 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29482 //var curXY = this.startPoint;
29483 var curSize = this.curSize || this.startBox;
29484 var x = this.startBox.x, y = this.startBox.y;
29485 var ox = x, oy = y;
29486 var w = curSize.width, h = curSize.height;
29487 var ow = w, oh = h;
29488 var mw = this.minWidth, mh = this.minHeight;
29489 var mxw = this.maxWidth, mxh = this.maxHeight;
29490 var wi = this.widthIncrement;
29491 var hi = this.heightIncrement;
29493 var eventXY = e.getXY();
29494 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29495 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29497 var pos = this.activeHandle.position;
29502 w = Math.min(Math.max(mw, w), mxw);
29507 h = Math.min(Math.max(mh, h), mxh);
29512 w = Math.min(Math.max(mw, w), mxw);
29513 h = Math.min(Math.max(mh, h), mxh);
29516 diffY = this.constrain(h, diffY, mh, mxh);
29523 var adiffX = Math.abs(diffX);
29524 var sub = (adiffX % wi); // how much
29525 if (sub > (wi/2)) { // far enough to snap
29526 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29528 // remove difference..
29529 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29533 x = Math.max(this.minX, x);
29536 diffX = this.constrain(w, diffX, mw, mxw);
29542 w = Math.min(Math.max(mw, w), mxw);
29543 diffY = this.constrain(h, diffY, mh, mxh);
29548 diffX = this.constrain(w, diffX, mw, mxw);
29549 diffY = this.constrain(h, diffY, mh, mxh);
29556 diffX = this.constrain(w, diffX, mw, mxw);
29558 h = Math.min(Math.max(mh, h), mxh);
29564 var sw = this.snap(w, wi, mw);
29565 var sh = this.snap(h, hi, mh);
29566 if(sw != w || sh != h){
29589 if(this.preserveRatio){
29594 h = Math.min(Math.max(mh, h), mxh);
29599 w = Math.min(Math.max(mw, w), mxw);
29604 w = Math.min(Math.max(mw, w), mxw);
29610 w = Math.min(Math.max(mw, w), mxw);
29616 h = Math.min(Math.max(mh, h), mxh);
29624 h = Math.min(Math.max(mh, h), mxh);
29634 h = Math.min(Math.max(mh, h), mxh);
29642 if (pos == 'hdrag') {
29645 this.proxy.setBounds(x, y, w, h);
29647 this.resizeElement();
29651 this.fireEvent("resizing", this, x, y, w, h, e);
29655 handleOver : function(){
29657 this.el.addClass("x-resizable-over");
29662 handleOut : function(){
29663 if(!this.resizing){
29664 this.el.removeClass("x-resizable-over");
29669 * Returns the element this component is bound to.
29670 * @return {Roo.Element}
29672 getEl : function(){
29677 * Returns the resizeChild element (or null).
29678 * @return {Roo.Element}
29680 getResizeChild : function(){
29681 return this.resizeChild;
29683 groupHandler : function()
29688 * Destroys this resizable. If the element was wrapped and
29689 * removeEl is not true then the element remains.
29690 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29692 destroy : function(removeEl){
29693 this.proxy.remove();
29695 this.overlay.removeAllListeners();
29696 this.overlay.remove();
29698 var ps = Roo.Resizable.positions;
29700 if(typeof ps[k] != "function" && this[ps[k]]){
29701 var h = this[ps[k]];
29702 h.el.removeAllListeners();
29707 this.el.update("");
29714 // hash to map config positions to true positions
29715 Roo.Resizable.positions = {
29716 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29721 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29723 // only initialize the template if resizable is used
29724 var tpl = Roo.DomHelper.createTemplate(
29725 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29728 Roo.Resizable.Handle.prototype.tpl = tpl;
29730 this.position = pos;
29732 // show north drag fro topdra
29733 var handlepos = pos == 'hdrag' ? 'north' : pos;
29735 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29736 if (pos == 'hdrag') {
29737 this.el.setStyle('cursor', 'pointer');
29739 this.el.unselectable();
29741 this.el.setOpacity(0);
29743 this.el.on("mousedown", this.onMouseDown, this);
29744 if(!disableTrackOver){
29745 this.el.on("mouseover", this.onMouseOver, this);
29746 this.el.on("mouseout", this.onMouseOut, this);
29751 Roo.Resizable.Handle.prototype = {
29752 afterResize : function(rz){
29757 onMouseDown : function(e){
29758 this.rz.onMouseDown(this, e);
29761 onMouseOver : function(e){
29762 this.rz.handleOver(this, e);
29765 onMouseOut : function(e){
29766 this.rz.handleOut(this, e);
29770 * Ext JS Library 1.1.1
29771 * Copyright(c) 2006-2007, Ext JS, LLC.
29773 * Originally Released Under LGPL - original licence link has changed is not relivant.
29776 * <script type="text/javascript">
29780 * @class Roo.Editor
29781 * @extends Roo.Component
29782 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29784 * Create a new Editor
29785 * @param {Roo.form.Field} field The Field object (or descendant)
29786 * @param {Object} config The config object
29788 Roo.Editor = function(field, config){
29789 Roo.Editor.superclass.constructor.call(this, config);
29790 this.field = field;
29793 * @event beforestartedit
29794 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29795 * false from the handler of this event.
29796 * @param {Editor} this
29797 * @param {Roo.Element} boundEl The underlying element bound to this editor
29798 * @param {Mixed} value The field value being set
29800 "beforestartedit" : true,
29803 * Fires when this editor is displayed
29804 * @param {Roo.Element} boundEl The underlying element bound to this editor
29805 * @param {Mixed} value The starting field value
29807 "startedit" : true,
29809 * @event beforecomplete
29810 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29811 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29812 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29813 * event will not fire since no edit actually occurred.
29814 * @param {Editor} this
29815 * @param {Mixed} value The current field value
29816 * @param {Mixed} startValue The original field value
29818 "beforecomplete" : true,
29821 * Fires after editing is complete and any changed value has been written to the underlying field.
29822 * @param {Editor} this
29823 * @param {Mixed} value The current field value
29824 * @param {Mixed} startValue The original field value
29828 * @event specialkey
29829 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29830 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29831 * @param {Roo.form.Field} this
29832 * @param {Roo.EventObject} e The event object
29834 "specialkey" : true
29838 Roo.extend(Roo.Editor, Roo.Component, {
29840 * @cfg {Boolean/String} autosize
29841 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29842 * or "height" to adopt the height only (defaults to false)
29845 * @cfg {Boolean} revertInvalid
29846 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29847 * validation fails (defaults to true)
29850 * @cfg {Boolean} ignoreNoChange
29851 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29852 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29853 * will never be ignored.
29856 * @cfg {Boolean} hideEl
29857 * False to keep the bound element visible while the editor is displayed (defaults to true)
29860 * @cfg {Mixed} value
29861 * The data value of the underlying field (defaults to "")
29865 * @cfg {String} alignment
29866 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29870 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29871 * for bottom-right shadow (defaults to "frame")
29875 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29879 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29881 completeOnEnter : false,
29883 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29885 cancelOnEsc : false,
29887 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29892 onRender : function(ct, position){
29893 this.el = new Roo.Layer({
29894 shadow: this.shadow,
29900 constrain: this.constrain
29902 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29903 if(this.field.msgTarget != 'title'){
29904 this.field.msgTarget = 'qtip';
29906 this.field.render(this.el);
29908 this.field.el.dom.setAttribute('autocomplete', 'off');
29910 this.field.on("specialkey", this.onSpecialKey, this);
29911 if(this.swallowKeys){
29912 this.field.el.swallowEvent(['keydown','keypress']);
29915 this.field.on("blur", this.onBlur, this);
29916 if(this.field.grow){
29917 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29921 onSpecialKey : function(field, e)
29923 //Roo.log('editor onSpecialKey');
29924 if(this.completeOnEnter && e.getKey() == e.ENTER){
29926 this.completeEdit();
29929 // do not fire special key otherwise it might hide close the editor...
29930 if(e.getKey() == e.ENTER){
29933 if(this.cancelOnEsc && e.getKey() == e.ESC){
29937 this.fireEvent('specialkey', field, e);
29942 * Starts the editing process and shows the editor.
29943 * @param {String/HTMLElement/Element} el The element to edit
29944 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29945 * to the innerHTML of el.
29947 startEdit : function(el, value){
29949 this.completeEdit();
29951 this.boundEl = Roo.get(el);
29952 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29953 if(!this.rendered){
29954 this.render(this.parentEl || document.body);
29956 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29959 this.startValue = v;
29960 this.field.setValue(v);
29962 var sz = this.boundEl.getSize();
29963 switch(this.autoSize){
29965 this.setSize(sz.width, "");
29968 this.setSize("", sz.height);
29971 this.setSize(sz.width, sz.height);
29974 this.el.alignTo(this.boundEl, this.alignment);
29975 this.editing = true;
29977 Roo.QuickTips.disable();
29983 * Sets the height and width of this editor.
29984 * @param {Number} width The new width
29985 * @param {Number} height The new height
29987 setSize : function(w, h){
29988 this.field.setSize(w, h);
29995 * Realigns the editor to the bound field based on the current alignment config value.
29997 realign : function(){
29998 this.el.alignTo(this.boundEl, this.alignment);
30002 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30003 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30005 completeEdit : function(remainVisible){
30009 var v = this.getValue();
30010 if(this.revertInvalid !== false && !this.field.isValid()){
30011 v = this.startValue;
30012 this.cancelEdit(true);
30014 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30015 this.editing = false;
30019 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30020 this.editing = false;
30021 if(this.updateEl && this.boundEl){
30022 this.boundEl.update(v);
30024 if(remainVisible !== true){
30027 this.fireEvent("complete", this, v, this.startValue);
30032 onShow : function(){
30034 if(this.hideEl !== false){
30035 this.boundEl.hide();
30038 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30039 this.fixIEFocus = true;
30040 this.deferredFocus.defer(50, this);
30042 this.field.focus();
30044 this.fireEvent("startedit", this.boundEl, this.startValue);
30047 deferredFocus : function(){
30049 this.field.focus();
30054 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30055 * reverted to the original starting value.
30056 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30057 * cancel (defaults to false)
30059 cancelEdit : function(remainVisible){
30061 this.setValue(this.startValue);
30062 if(remainVisible !== true){
30069 onBlur : function(){
30070 if(this.allowBlur !== true && this.editing){
30071 this.completeEdit();
30076 onHide : function(){
30078 this.completeEdit();
30082 if(this.field.collapse){
30083 this.field.collapse();
30086 if(this.hideEl !== false){
30087 this.boundEl.show();
30090 Roo.QuickTips.enable();
30095 * Sets the data value of the editor
30096 * @param {Mixed} value Any valid value supported by the underlying field
30098 setValue : function(v){
30099 this.field.setValue(v);
30103 * Gets the data value of the editor
30104 * @return {Mixed} The data value
30106 getValue : function(){
30107 return this.field.getValue();
30111 * Ext JS Library 1.1.1
30112 * Copyright(c) 2006-2007, Ext JS, LLC.
30114 * Originally Released Under LGPL - original licence link has changed is not relivant.
30117 * <script type="text/javascript">
30121 * @class Roo.BasicDialog
30122 * @extends Roo.util.Observable
30123 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30125 var dlg = new Roo.BasicDialog("my-dlg", {
30134 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30135 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30136 dlg.addButton('Cancel', dlg.hide, dlg);
30139 <b>A Dialog should always be a direct child of the body element.</b>
30140 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30141 * @cfg {String} title Default text to display in the title bar (defaults to null)
30142 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30143 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30144 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30145 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30146 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30147 * (defaults to null with no animation)
30148 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30149 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30150 * property for valid values (defaults to 'all')
30151 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30152 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30153 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30154 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30155 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30156 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30157 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30158 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30159 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30160 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30161 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30162 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30163 * draggable = true (defaults to false)
30164 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30165 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30166 * shadow (defaults to false)
30167 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30168 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30169 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30170 * @cfg {Array} buttons Array of buttons
30171 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30173 * Create a new BasicDialog.
30174 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30175 * @param {Object} config Configuration options
30177 Roo.BasicDialog = function(el, config){
30178 this.el = Roo.get(el);
30179 var dh = Roo.DomHelper;
30180 if(!this.el && config && config.autoCreate){
30181 if(typeof config.autoCreate == "object"){
30182 if(!config.autoCreate.id){
30183 config.autoCreate.id = el;
30185 this.el = dh.append(document.body,
30186 config.autoCreate, true);
30188 this.el = dh.append(document.body,
30189 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30193 el.setDisplayed(true);
30194 el.hide = this.hideAction;
30196 el.addClass("x-dlg");
30198 Roo.apply(this, config);
30200 this.proxy = el.createProxy("x-dlg-proxy");
30201 this.proxy.hide = this.hideAction;
30202 this.proxy.setOpacity(.5);
30206 el.setWidth(config.width);
30209 el.setHeight(config.height);
30211 this.size = el.getSize();
30212 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30213 this.xy = [config.x,config.y];
30215 this.xy = el.getCenterXY(true);
30217 /** The header element @type Roo.Element */
30218 this.header = el.child("> .x-dlg-hd");
30219 /** The body element @type Roo.Element */
30220 this.body = el.child("> .x-dlg-bd");
30221 /** The footer element @type Roo.Element */
30222 this.footer = el.child("> .x-dlg-ft");
30225 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30228 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30231 this.header.unselectable();
30233 this.header.update(this.title);
30235 // this element allows the dialog to be focused for keyboard event
30236 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30237 this.focusEl.swallowEvent("click", true);
30239 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30241 // wrap the body and footer for special rendering
30242 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30244 this.bwrap.dom.appendChild(this.footer.dom);
30247 this.bg = this.el.createChild({
30248 tag: "div", cls:"x-dlg-bg",
30249 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30251 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30254 if(this.autoScroll !== false && !this.autoTabs){
30255 this.body.setStyle("overflow", "auto");
30258 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30260 if(this.closable !== false){
30261 this.el.addClass("x-dlg-closable");
30262 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30263 this.close.on("click", this.closeClick, this);
30264 this.close.addClassOnOver("x-dlg-close-over");
30266 if(this.collapsible !== false){
30267 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30268 this.collapseBtn.on("click", this.collapseClick, this);
30269 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30270 this.header.on("dblclick", this.collapseClick, this);
30272 if(this.resizable !== false){
30273 this.el.addClass("x-dlg-resizable");
30274 this.resizer = new Roo.Resizable(el, {
30275 minWidth: this.minWidth || 80,
30276 minHeight:this.minHeight || 80,
30277 handles: this.resizeHandles || "all",
30280 this.resizer.on("beforeresize", this.beforeResize, this);
30281 this.resizer.on("resize", this.onResize, this);
30283 if(this.draggable !== false){
30284 el.addClass("x-dlg-draggable");
30285 if (!this.proxyDrag) {
30286 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30289 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30291 dd.setHandleElId(this.header.id);
30292 dd.endDrag = this.endMove.createDelegate(this);
30293 dd.startDrag = this.startMove.createDelegate(this);
30294 dd.onDrag = this.onDrag.createDelegate(this);
30299 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30300 this.mask.enableDisplayMode("block");
30302 this.el.addClass("x-dlg-modal");
30305 this.shadow = new Roo.Shadow({
30306 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30307 offset : this.shadowOffset
30310 this.shadowOffset = 0;
30312 if(Roo.useShims && this.shim !== false){
30313 this.shim = this.el.createShim();
30314 this.shim.hide = this.hideAction;
30322 if (this.buttons) {
30323 var bts= this.buttons;
30325 Roo.each(bts, function(b) {
30334 * Fires when a key is pressed
30335 * @param {Roo.BasicDialog} this
30336 * @param {Roo.EventObject} e
30341 * Fires when this dialog is moved by the user.
30342 * @param {Roo.BasicDialog} this
30343 * @param {Number} x The new page X
30344 * @param {Number} y The new page Y
30349 * Fires when this dialog is resized by the user.
30350 * @param {Roo.BasicDialog} this
30351 * @param {Number} width The new width
30352 * @param {Number} height The new height
30356 * @event beforehide
30357 * Fires before this dialog is hidden.
30358 * @param {Roo.BasicDialog} this
30360 "beforehide" : true,
30363 * Fires when this dialog is hidden.
30364 * @param {Roo.BasicDialog} this
30368 * @event beforeshow
30369 * Fires before this dialog is shown.
30370 * @param {Roo.BasicDialog} this
30372 "beforeshow" : true,
30375 * Fires when this dialog is shown.
30376 * @param {Roo.BasicDialog} this
30380 el.on("keydown", this.onKeyDown, this);
30381 el.on("mousedown", this.toFront, this);
30382 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30384 Roo.DialogManager.register(this);
30385 Roo.BasicDialog.superclass.constructor.call(this);
30388 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30389 shadowOffset: Roo.isIE ? 6 : 5,
30392 minButtonWidth: 75,
30393 defaultButton: null,
30394 buttonAlign: "right",
30399 * Sets the dialog title text
30400 * @param {String} text The title text to display
30401 * @return {Roo.BasicDialog} this
30403 setTitle : function(text){
30404 this.header.update(text);
30409 closeClick : function(){
30414 collapseClick : function(){
30415 this[this.collapsed ? "expand" : "collapse"]();
30419 * Collapses the dialog to its minimized state (only the title bar is visible).
30420 * Equivalent to the user clicking the collapse dialog button.
30422 collapse : function(){
30423 if(!this.collapsed){
30424 this.collapsed = true;
30425 this.el.addClass("x-dlg-collapsed");
30426 this.restoreHeight = this.el.getHeight();
30427 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30432 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30433 * clicking the expand dialog button.
30435 expand : function(){
30436 if(this.collapsed){
30437 this.collapsed = false;
30438 this.el.removeClass("x-dlg-collapsed");
30439 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30444 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30445 * @return {Roo.TabPanel} The tabs component
30447 initTabs : function(){
30448 var tabs = this.getTabs();
30449 while(tabs.getTab(0)){
30452 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30454 tabs.addTab(Roo.id(dom), dom.title);
30462 beforeResize : function(){
30463 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30467 onResize : function(){
30468 this.refreshSize();
30469 this.syncBodyHeight();
30470 this.adjustAssets();
30472 this.fireEvent("resize", this, this.size.width, this.size.height);
30476 onKeyDown : function(e){
30477 if(this.isVisible()){
30478 this.fireEvent("keydown", this, e);
30483 * Resizes the dialog.
30484 * @param {Number} width
30485 * @param {Number} height
30486 * @return {Roo.BasicDialog} this
30488 resizeTo : function(width, height){
30489 this.el.setSize(width, height);
30490 this.size = {width: width, height: height};
30491 this.syncBodyHeight();
30492 if(this.fixedcenter){
30495 if(this.isVisible()){
30496 this.constrainXY();
30497 this.adjustAssets();
30499 this.fireEvent("resize", this, width, height);
30505 * Resizes the dialog to fit the specified content size.
30506 * @param {Number} width
30507 * @param {Number} height
30508 * @return {Roo.BasicDialog} this
30510 setContentSize : function(w, h){
30511 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30512 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30513 //if(!this.el.isBorderBox()){
30514 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30515 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30518 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30519 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30521 this.resizeTo(w, h);
30526 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30527 * executed in response to a particular key being pressed while the dialog is active.
30528 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30529 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30530 * @param {Function} fn The function to call
30531 * @param {Object} scope (optional) The scope of the function
30532 * @return {Roo.BasicDialog} this
30534 addKeyListener : function(key, fn, scope){
30535 var keyCode, shift, ctrl, alt;
30536 if(typeof key == "object" && !(key instanceof Array)){
30537 keyCode = key["key"];
30538 shift = key["shift"];
30539 ctrl = key["ctrl"];
30544 var handler = function(dlg, e){
30545 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30546 var k = e.getKey();
30547 if(keyCode instanceof Array){
30548 for(var i = 0, len = keyCode.length; i < len; i++){
30549 if(keyCode[i] == k){
30550 fn.call(scope || window, dlg, k, e);
30556 fn.call(scope || window, dlg, k, e);
30561 this.on("keydown", handler);
30566 * Returns the TabPanel component (creates it if it doesn't exist).
30567 * Note: If you wish to simply check for the existence of tabs without creating them,
30568 * check for a null 'tabs' property.
30569 * @return {Roo.TabPanel} The tabs component
30571 getTabs : function(){
30573 this.el.addClass("x-dlg-auto-tabs");
30574 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30575 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30581 * Adds a button to the footer section of the dialog.
30582 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30583 * object or a valid Roo.DomHelper element config
30584 * @param {Function} handler The function called when the button is clicked
30585 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30586 * @return {Roo.Button} The new button
30588 addButton : function(config, handler, scope){
30589 var dh = Roo.DomHelper;
30591 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30593 if(!this.btnContainer){
30594 var tb = this.footer.createChild({
30596 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30597 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30599 this.btnContainer = tb.firstChild.firstChild.firstChild;
30604 minWidth: this.minButtonWidth,
30607 if(typeof config == "string"){
30608 bconfig.text = config;
30611 bconfig.dhconfig = config;
30613 Roo.apply(bconfig, config);
30617 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30618 bconfig.position = Math.max(0, bconfig.position);
30619 fc = this.btnContainer.childNodes[bconfig.position];
30622 var btn = new Roo.Button(
30624 this.btnContainer.insertBefore(document.createElement("td"),fc)
30625 : this.btnContainer.appendChild(document.createElement("td")),
30626 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30629 this.syncBodyHeight();
30632 * Array of all the buttons that have been added to this dialog via addButton
30637 this.buttons.push(btn);
30642 * Sets the default button to be focused when the dialog is displayed.
30643 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30644 * @return {Roo.BasicDialog} this
30646 setDefaultButton : function(btn){
30647 this.defaultButton = btn;
30652 getHeaderFooterHeight : function(safe){
30655 height += this.header.getHeight();
30658 var fm = this.footer.getMargins();
30659 height += (this.footer.getHeight()+fm.top+fm.bottom);
30661 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30662 height += this.centerBg.getPadding("tb");
30667 syncBodyHeight : function()
30669 var bd = this.body, // the text
30670 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30672 var height = this.size.height - this.getHeaderFooterHeight(false);
30673 bd.setHeight(height-bd.getMargins("tb"));
30674 var hh = this.header.getHeight();
30675 var h = this.size.height-hh;
30678 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30679 bw.setHeight(h-cb.getPadding("tb"));
30681 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30682 bd.setWidth(bw.getWidth(true));
30684 this.tabs.syncHeight();
30686 this.tabs.el.repaint();
30692 * Restores the previous state of the dialog if Roo.state is configured.
30693 * @return {Roo.BasicDialog} this
30695 restoreState : function(){
30696 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30697 if(box && box.width){
30698 this.xy = [box.x, box.y];
30699 this.resizeTo(box.width, box.height);
30705 beforeShow : function(){
30707 if(this.fixedcenter){
30708 this.xy = this.el.getCenterXY(true);
30711 Roo.get(document.body).addClass("x-body-masked");
30712 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30715 this.constrainXY();
30719 animShow : function(){
30720 var b = Roo.get(this.animateTarget).getBox();
30721 this.proxy.setSize(b.width, b.height);
30722 this.proxy.setLocation(b.x, b.y);
30724 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30725 true, .35, this.showEl.createDelegate(this));
30729 * Shows the dialog.
30730 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30731 * @return {Roo.BasicDialog} this
30733 show : function(animateTarget){
30734 if (this.fireEvent("beforeshow", this) === false){
30737 if(this.syncHeightBeforeShow){
30738 this.syncBodyHeight();
30739 }else if(this.firstShow){
30740 this.firstShow = false;
30741 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30743 this.animateTarget = animateTarget || this.animateTarget;
30744 if(!this.el.isVisible()){
30746 if(this.animateTarget && Roo.get(this.animateTarget)){
30756 showEl : function(){
30758 this.el.setXY(this.xy);
30760 this.adjustAssets(true);
30763 // IE peekaboo bug - fix found by Dave Fenwick
30767 this.fireEvent("show", this);
30771 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30772 * dialog itself will receive focus.
30774 focus : function(){
30775 if(this.defaultButton){
30776 this.defaultButton.focus();
30778 this.focusEl.focus();
30783 constrainXY : function(){
30784 if(this.constraintoviewport !== false){
30785 if(!this.viewSize){
30786 if(this.container){
30787 var s = this.container.getSize();
30788 this.viewSize = [s.width, s.height];
30790 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30793 var s = Roo.get(this.container||document).getScroll();
30795 var x = this.xy[0], y = this.xy[1];
30796 var w = this.size.width, h = this.size.height;
30797 var vw = this.viewSize[0], vh = this.viewSize[1];
30798 // only move it if it needs it
30800 // first validate right/bottom
30801 if(x + w > vw+s.left){
30805 if(y + h > vh+s.top){
30809 // then make sure top/left isn't negative
30821 if(this.isVisible()){
30822 this.el.setLocation(x, y);
30823 this.adjustAssets();
30830 onDrag : function(){
30831 if(!this.proxyDrag){
30832 this.xy = this.el.getXY();
30833 this.adjustAssets();
30838 adjustAssets : function(doShow){
30839 var x = this.xy[0], y = this.xy[1];
30840 var w = this.size.width, h = this.size.height;
30841 if(doShow === true){
30843 this.shadow.show(this.el);
30849 if(this.shadow && this.shadow.isVisible()){
30850 this.shadow.show(this.el);
30852 if(this.shim && this.shim.isVisible()){
30853 this.shim.setBounds(x, y, w, h);
30858 adjustViewport : function(w, h){
30860 w = Roo.lib.Dom.getViewWidth();
30861 h = Roo.lib.Dom.getViewHeight();
30864 this.viewSize = [w, h];
30865 if(this.modal && this.mask.isVisible()){
30866 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30867 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30869 if(this.isVisible()){
30870 this.constrainXY();
30875 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30876 * shadow, proxy, mask, etc.) Also removes all event listeners.
30877 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30879 destroy : function(removeEl){
30880 if(this.isVisible()){
30881 this.animateTarget = null;
30884 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30886 this.tabs.destroy(removeEl);
30899 for(var i = 0, len = this.buttons.length; i < len; i++){
30900 this.buttons[i].destroy();
30903 this.el.removeAllListeners();
30904 if(removeEl === true){
30905 this.el.update("");
30908 Roo.DialogManager.unregister(this);
30912 startMove : function(){
30913 if(this.proxyDrag){
30916 if(this.constraintoviewport !== false){
30917 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30922 endMove : function(){
30923 if(!this.proxyDrag){
30924 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30926 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30929 this.refreshSize();
30930 this.adjustAssets();
30932 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30936 * Brings this dialog to the front of any other visible dialogs
30937 * @return {Roo.BasicDialog} this
30939 toFront : function(){
30940 Roo.DialogManager.bringToFront(this);
30945 * Sends this dialog to the back (under) of any other visible dialogs
30946 * @return {Roo.BasicDialog} this
30948 toBack : function(){
30949 Roo.DialogManager.sendToBack(this);
30954 * Centers this dialog in the viewport
30955 * @return {Roo.BasicDialog} this
30957 center : function(){
30958 var xy = this.el.getCenterXY(true);
30959 this.moveTo(xy[0], xy[1]);
30964 * Moves the dialog's top-left corner to the specified point
30965 * @param {Number} x
30966 * @param {Number} y
30967 * @return {Roo.BasicDialog} this
30969 moveTo : function(x, y){
30971 if(this.isVisible()){
30972 this.el.setXY(this.xy);
30973 this.adjustAssets();
30979 * Aligns the dialog to the specified element
30980 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30981 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30982 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30983 * @return {Roo.BasicDialog} this
30985 alignTo : function(element, position, offsets){
30986 this.xy = this.el.getAlignToXY(element, position, offsets);
30987 if(this.isVisible()){
30988 this.el.setXY(this.xy);
30989 this.adjustAssets();
30995 * Anchors an element to another element and realigns it when the window is resized.
30996 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30997 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30998 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30999 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31000 * is a number, it is used as the buffer delay (defaults to 50ms).
31001 * @return {Roo.BasicDialog} this
31003 anchorTo : function(el, alignment, offsets, monitorScroll){
31004 var action = function(){
31005 this.alignTo(el, alignment, offsets);
31007 Roo.EventManager.onWindowResize(action, this);
31008 var tm = typeof monitorScroll;
31009 if(tm != 'undefined'){
31010 Roo.EventManager.on(window, 'scroll', action, this,
31011 {buffer: tm == 'number' ? monitorScroll : 50});
31018 * Returns true if the dialog is visible
31019 * @return {Boolean}
31021 isVisible : function(){
31022 return this.el.isVisible();
31026 animHide : function(callback){
31027 var b = Roo.get(this.animateTarget).getBox();
31029 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31031 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31032 this.hideEl.createDelegate(this, [callback]));
31036 * Hides the dialog.
31037 * @param {Function} callback (optional) Function to call when the dialog is hidden
31038 * @return {Roo.BasicDialog} this
31040 hide : function(callback){
31041 if (this.fireEvent("beforehide", this) === false){
31045 this.shadow.hide();
31050 // sometimes animateTarget seems to get set.. causing problems...
31051 // this just double checks..
31052 if(this.animateTarget && Roo.get(this.animateTarget)) {
31053 this.animHide(callback);
31056 this.hideEl(callback);
31062 hideEl : function(callback){
31066 Roo.get(document.body).removeClass("x-body-masked");
31068 this.fireEvent("hide", this);
31069 if(typeof callback == "function"){
31075 hideAction : function(){
31076 this.setLeft("-10000px");
31077 this.setTop("-10000px");
31078 this.setStyle("visibility", "hidden");
31082 refreshSize : function(){
31083 this.size = this.el.getSize();
31084 this.xy = this.el.getXY();
31085 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31089 // z-index is managed by the DialogManager and may be overwritten at any time
31090 setZIndex : function(index){
31092 this.mask.setStyle("z-index", index);
31095 this.shim.setStyle("z-index", ++index);
31098 this.shadow.setZIndex(++index);
31100 this.el.setStyle("z-index", ++index);
31102 this.proxy.setStyle("z-index", ++index);
31105 this.resizer.proxy.setStyle("z-index", ++index);
31108 this.lastZIndex = index;
31112 * Returns the element for this dialog
31113 * @return {Roo.Element} The underlying dialog Element
31115 getEl : function(){
31121 * @class Roo.DialogManager
31122 * Provides global access to BasicDialogs that have been created and
31123 * support for z-indexing (layering) multiple open dialogs.
31125 Roo.DialogManager = function(){
31127 var accessList = [];
31131 var sortDialogs = function(d1, d2){
31132 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31136 var orderDialogs = function(){
31137 accessList.sort(sortDialogs);
31138 var seed = Roo.DialogManager.zseed;
31139 for(var i = 0, len = accessList.length; i < len; i++){
31140 var dlg = accessList[i];
31142 dlg.setZIndex(seed + (i*10));
31149 * The starting z-index for BasicDialogs (defaults to 9000)
31150 * @type Number The z-index value
31155 register : function(dlg){
31156 list[dlg.id] = dlg;
31157 accessList.push(dlg);
31161 unregister : function(dlg){
31162 delete list[dlg.id];
31165 if(!accessList.indexOf){
31166 for( i = 0, len = accessList.length; i < len; i++){
31167 if(accessList[i] == dlg){
31168 accessList.splice(i, 1);
31173 i = accessList.indexOf(dlg);
31175 accessList.splice(i, 1);
31181 * Gets a registered dialog by id
31182 * @param {String/Object} id The id of the dialog or a dialog
31183 * @return {Roo.BasicDialog} this
31185 get : function(id){
31186 return typeof id == "object" ? id : list[id];
31190 * Brings the specified dialog to the front
31191 * @param {String/Object} dlg The id of the dialog or a dialog
31192 * @return {Roo.BasicDialog} this
31194 bringToFront : function(dlg){
31195 dlg = this.get(dlg);
31198 dlg._lastAccess = new Date().getTime();
31205 * Sends the specified dialog to the back
31206 * @param {String/Object} dlg The id of the dialog or a dialog
31207 * @return {Roo.BasicDialog} this
31209 sendToBack : function(dlg){
31210 dlg = this.get(dlg);
31211 dlg._lastAccess = -(new Date().getTime());
31217 * Hides all dialogs
31219 hideAll : function(){
31220 for(var id in list){
31221 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31230 * @class Roo.LayoutDialog
31231 * @extends Roo.BasicDialog
31232 * Dialog which provides adjustments for working with a layout in a Dialog.
31233 * Add your necessary layout config options to the dialog's config.<br>
31234 * Example usage (including a nested layout):
31237 dialog = new Roo.LayoutDialog("download-dlg", {
31246 // layout config merges with the dialog config
31248 tabPosition: "top",
31249 alwaysShowTabs: true
31252 dialog.addKeyListener(27, dialog.hide, dialog);
31253 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31254 dialog.addButton("Build It!", this.getDownload, this);
31256 // we can even add nested layouts
31257 var innerLayout = new Roo.BorderLayout("dl-inner", {
31267 innerLayout.beginUpdate();
31268 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31269 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31270 innerLayout.endUpdate(true);
31272 var layout = dialog.getLayout();
31273 layout.beginUpdate();
31274 layout.add("center", new Roo.ContentPanel("standard-panel",
31275 {title: "Download the Source", fitToFrame:true}));
31276 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31277 {title: "Build your own roo.js"}));
31278 layout.getRegion("center").showPanel(sp);
31279 layout.endUpdate();
31283 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31284 * @param {Object} config configuration options
31286 Roo.LayoutDialog = function(el, cfg){
31289 if (typeof(cfg) == 'undefined') {
31290 config = Roo.apply({}, el);
31291 // not sure why we use documentElement here.. - it should always be body.
31292 // IE7 borks horribly if we use documentElement.
31293 // webkit also does not like documentElement - it creates a body element...
31294 el = Roo.get( document.body || document.documentElement ).createChild();
31295 //config.autoCreate = true;
31299 config.autoTabs = false;
31300 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31301 this.body.setStyle({overflow:"hidden", position:"relative"});
31302 this.layout = new Roo.BorderLayout(this.body.dom, config);
31303 this.layout.monitorWindowResize = false;
31304 this.el.addClass("x-dlg-auto-layout");
31305 // fix case when center region overwrites center function
31306 this.center = Roo.BasicDialog.prototype.center;
31307 this.on("show", this.layout.layout, this.layout, true);
31308 if (config.items) {
31309 var xitems = config.items;
31310 delete config.items;
31311 Roo.each(xitems, this.addxtype, this);
31316 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31318 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31321 endUpdate : function(){
31322 this.layout.endUpdate();
31326 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31329 beginUpdate : function(){
31330 this.layout.beginUpdate();
31334 * Get the BorderLayout for this dialog
31335 * @return {Roo.BorderLayout}
31337 getLayout : function(){
31338 return this.layout;
31341 showEl : function(){
31342 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31344 this.layout.layout();
31349 // Use the syncHeightBeforeShow config option to control this automatically
31350 syncBodyHeight : function(){
31351 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31352 if(this.layout){this.layout.layout();}
31356 * Add an xtype element (actually adds to the layout.)
31357 * @return {Object} xdata xtype object data.
31360 addxtype : function(c) {
31361 return this.layout.addxtype(c);
31365 * Ext JS Library 1.1.1
31366 * Copyright(c) 2006-2007, Ext JS, LLC.
31368 * Originally Released Under LGPL - original licence link has changed is not relivant.
31371 * <script type="text/javascript">
31375 * @class Roo.MessageBox
31376 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31380 Roo.Msg.alert('Status', 'Changes saved successfully.');
31382 // Prompt for user data:
31383 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31385 // process text value...
31389 // Show a dialog using config options:
31391 title:'Save Changes?',
31392 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31393 buttons: Roo.Msg.YESNOCANCEL,
31400 Roo.MessageBox = function(){
31401 var dlg, opt, mask, waitTimer;
31402 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31403 var buttons, activeTextEl, bwidth;
31406 var handleButton = function(button){
31408 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31412 var handleHide = function(){
31413 if(opt && opt.cls){
31414 dlg.el.removeClass(opt.cls);
31417 Roo.TaskMgr.stop(waitTimer);
31423 var updateButtons = function(b){
31426 buttons["ok"].hide();
31427 buttons["cancel"].hide();
31428 buttons["yes"].hide();
31429 buttons["no"].hide();
31430 dlg.footer.dom.style.display = 'none';
31433 dlg.footer.dom.style.display = '';
31434 for(var k in buttons){
31435 if(typeof buttons[k] != "function"){
31438 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31439 width += buttons[k].el.getWidth()+15;
31449 var handleEsc = function(d, k, e){
31450 if(opt && opt.closable !== false){
31460 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31461 * @return {Roo.BasicDialog} The BasicDialog element
31463 getDialog : function(){
31465 dlg = new Roo.BasicDialog("x-msg-box", {
31470 constraintoviewport:false,
31472 collapsible : false,
31475 width:400, height:100,
31476 buttonAlign:"center",
31477 closeClick : function(){
31478 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31479 handleButton("no");
31481 handleButton("cancel");
31485 dlg.on("hide", handleHide);
31487 dlg.addKeyListener(27, handleEsc);
31489 var bt = this.buttonText;
31490 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31491 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31492 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31493 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31494 bodyEl = dlg.body.createChild({
31496 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>'
31498 msgEl = bodyEl.dom.firstChild;
31499 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31500 textboxEl.enableDisplayMode();
31501 textboxEl.addKeyListener([10,13], function(){
31502 if(dlg.isVisible() && opt && opt.buttons){
31503 if(opt.buttons.ok){
31504 handleButton("ok");
31505 }else if(opt.buttons.yes){
31506 handleButton("yes");
31510 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31511 textareaEl.enableDisplayMode();
31512 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31513 progressEl.enableDisplayMode();
31514 var pf = progressEl.dom.firstChild;
31516 pp = Roo.get(pf.firstChild);
31517 pp.setHeight(pf.offsetHeight);
31525 * Updates the message box body text
31526 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31527 * the XHTML-compliant non-breaking space character '&#160;')
31528 * @return {Roo.MessageBox} This message box
31530 updateText : function(text){
31531 if(!dlg.isVisible() && !opt.width){
31532 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31534 msgEl.innerHTML = text || ' ';
31536 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31537 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31539 Math.min(opt.width || cw , this.maxWidth),
31540 Math.max(opt.minWidth || this.minWidth, bwidth)
31543 activeTextEl.setWidth(w);
31545 if(dlg.isVisible()){
31546 dlg.fixedcenter = false;
31548 // to big, make it scroll. = But as usual stupid IE does not support
31551 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31552 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31553 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31555 bodyEl.dom.style.height = '';
31556 bodyEl.dom.style.overflowY = '';
31559 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31561 bodyEl.dom.style.overflowX = '';
31564 dlg.setContentSize(w, bodyEl.getHeight());
31565 if(dlg.isVisible()){
31566 dlg.fixedcenter = true;
31572 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31573 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31574 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31575 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31576 * @return {Roo.MessageBox} This message box
31578 updateProgress : function(value, text){
31580 this.updateText(text);
31582 if (pp) { // weird bug on my firefox - for some reason this is not defined
31583 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31589 * Returns true if the message box is currently displayed
31590 * @return {Boolean} True if the message box is visible, else false
31592 isVisible : function(){
31593 return dlg && dlg.isVisible();
31597 * Hides the message box if it is displayed
31600 if(this.isVisible()){
31606 * Displays a new message box, or reinitializes an existing message box, based on the config options
31607 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31608 * The following config object properties are supported:
31610 Property Type Description
31611 ---------- --------------- ------------------------------------------------------------------------------------
31612 animEl String/Element An id or Element from which the message box should animate as it opens and
31613 closes (defaults to undefined)
31614 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31615 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31616 closable Boolean False to hide the top-right close button (defaults to true). Note that
31617 progress and wait dialogs will ignore this property and always hide the
31618 close button as they can only be closed programmatically.
31619 cls String A custom CSS class to apply to the message box element
31620 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31621 displayed (defaults to 75)
31622 fn Function A callback function to execute after closing the dialog. The arguments to the
31623 function will be btn (the name of the button that was clicked, if applicable,
31624 e.g. "ok"), and text (the value of the active text field, if applicable).
31625 Progress and wait dialogs will ignore this option since they do not respond to
31626 user actions and can only be closed programmatically, so any required function
31627 should be called by the same code after it closes the dialog.
31628 icon String A CSS class that provides a background image to be used as an icon for
31629 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31630 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31631 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31632 modal Boolean False to allow user interaction with the page while the message box is
31633 displayed (defaults to true)
31634 msg String A string that will replace the existing message box body text (defaults
31635 to the XHTML-compliant non-breaking space character ' ')
31636 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31637 progress Boolean True to display a progress bar (defaults to false)
31638 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31639 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31640 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31641 title String The title text
31642 value String The string value to set into the active textbox element if displayed
31643 wait Boolean True to display a progress bar (defaults to false)
31644 width Number The width of the dialog in pixels
31651 msg: 'Please enter your address:',
31653 buttons: Roo.MessageBox.OKCANCEL,
31656 animEl: 'addAddressBtn'
31659 * @param {Object} config Configuration options
31660 * @return {Roo.MessageBox} This message box
31662 show : function(options)
31665 // this causes nightmares if you show one dialog after another
31666 // especially on callbacks..
31668 if(this.isVisible()){
31671 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31672 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31673 Roo.log("New Dialog Message:" + options.msg )
31674 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31675 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31678 var d = this.getDialog();
31680 d.setTitle(opt.title || " ");
31681 d.close.setDisplayed(opt.closable !== false);
31682 activeTextEl = textboxEl;
31683 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31688 textareaEl.setHeight(typeof opt.multiline == "number" ?
31689 opt.multiline : this.defaultTextHeight);
31690 activeTextEl = textareaEl;
31699 progressEl.setDisplayed(opt.progress === true);
31700 this.updateProgress(0);
31701 activeTextEl.dom.value = opt.value || "";
31703 dlg.setDefaultButton(activeTextEl);
31705 var bs = opt.buttons;
31708 db = buttons["ok"];
31709 }else if(bs && bs.yes){
31710 db = buttons["yes"];
31712 dlg.setDefaultButton(db);
31714 bwidth = updateButtons(opt.buttons);
31715 this.updateText(opt.msg);
31717 d.el.addClass(opt.cls);
31719 d.proxyDrag = opt.proxyDrag === true;
31720 d.modal = opt.modal !== false;
31721 d.mask = opt.modal !== false ? mask : false;
31722 if(!d.isVisible()){
31723 // force it to the end of the z-index stack so it gets a cursor in FF
31724 document.body.appendChild(dlg.el.dom);
31725 d.animateTarget = null;
31726 d.show(options.animEl);
31732 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31733 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31734 * and closing the message box when the process is complete.
31735 * @param {String} title The title bar text
31736 * @param {String} msg The message box body text
31737 * @return {Roo.MessageBox} This message box
31739 progress : function(title, msg){
31746 minWidth: this.minProgressWidth,
31753 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31754 * If a callback function is passed it will be called after the user clicks the button, and the
31755 * id of the button that was clicked will be passed as the only parameter to the callback
31756 * (could also be the top-right close button).
31757 * @param {String} title The title bar text
31758 * @param {String} msg The message box body text
31759 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31760 * @param {Object} scope (optional) The scope of the callback function
31761 * @return {Roo.MessageBox} This message box
31763 alert : function(title, msg, fn, scope){
31776 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31777 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31778 * You are responsible for closing the message box when the process is complete.
31779 * @param {String} msg The message box body text
31780 * @param {String} title (optional) The title bar text
31781 * @return {Roo.MessageBox} This message box
31783 wait : function(msg, title){
31794 waitTimer = Roo.TaskMgr.start({
31796 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31804 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31805 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31806 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31807 * @param {String} title The title bar text
31808 * @param {String} msg The message box body text
31809 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31810 * @param {Object} scope (optional) The scope of the callback function
31811 * @return {Roo.MessageBox} This message box
31813 confirm : function(title, msg, fn, scope){
31817 buttons: this.YESNO,
31826 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31827 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31828 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31829 * (could also be the top-right close button) and the text that was entered will be passed as the two
31830 * parameters to the callback.
31831 * @param {String} title The title bar text
31832 * @param {String} msg The message box body text
31833 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31834 * @param {Object} scope (optional) The scope of the callback function
31835 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31836 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31837 * @return {Roo.MessageBox} This message box
31839 prompt : function(title, msg, fn, scope, multiline){
31843 buttons: this.OKCANCEL,
31848 multiline: multiline,
31855 * Button config that displays a single OK button
31860 * Button config that displays Yes and No buttons
31863 YESNO : {yes:true, no:true},
31865 * Button config that displays OK and Cancel buttons
31868 OKCANCEL : {ok:true, cancel:true},
31870 * Button config that displays Yes, No and Cancel buttons
31873 YESNOCANCEL : {yes:true, no:true, cancel:true},
31876 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31879 defaultTextHeight : 75,
31881 * The maximum width in pixels of the message box (defaults to 600)
31886 * The minimum width in pixels of the message box (defaults to 100)
31891 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31892 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31895 minProgressWidth : 250,
31897 * An object containing the default button text strings that can be overriden for localized language support.
31898 * Supported properties are: ok, cancel, yes and no.
31899 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31912 * Shorthand for {@link Roo.MessageBox}
31914 Roo.Msg = Roo.MessageBox;/*
31916 * Ext JS Library 1.1.1
31917 * Copyright(c) 2006-2007, Ext JS, LLC.
31919 * Originally Released Under LGPL - original licence link has changed is not relivant.
31922 * <script type="text/javascript">
31925 * @class Roo.QuickTips
31926 * Provides attractive and customizable tooltips for any element.
31929 Roo.QuickTips = function(){
31930 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31931 var ce, bd, xy, dd;
31932 var visible = false, disabled = true, inited = false;
31933 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31935 var onOver = function(e){
31939 var t = e.getTarget();
31940 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31943 if(ce && t == ce.el){
31944 clearTimeout(hideProc);
31947 if(t && tagEls[t.id]){
31948 tagEls[t.id].el = t;
31949 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31952 var ttp, et = Roo.fly(t);
31953 var ns = cfg.namespace;
31954 if(tm.interceptTitles && t.title){
31957 t.removeAttribute("title");
31958 e.preventDefault();
31960 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31963 showProc = show.defer(tm.showDelay, tm, [{
31966 width: et.getAttributeNS(ns, cfg.width),
31967 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31968 title: et.getAttributeNS(ns, cfg.title),
31969 cls: et.getAttributeNS(ns, cfg.cls)
31974 var onOut = function(e){
31975 clearTimeout(showProc);
31976 var t = e.getTarget();
31977 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31978 hideProc = setTimeout(hide, tm.hideDelay);
31982 var onMove = function(e){
31988 if(tm.trackMouse && ce){
31993 var onDown = function(e){
31994 clearTimeout(showProc);
31995 clearTimeout(hideProc);
31997 if(tm.hideOnClick){
32000 tm.enable.defer(100, tm);
32005 var getPad = function(){
32006 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32009 var show = function(o){
32013 clearTimeout(dismissProc);
32015 if(removeCls){ // in case manually hidden
32016 el.removeClass(removeCls);
32020 el.addClass(ce.cls);
32021 removeCls = ce.cls;
32024 tipTitle.update(ce.title);
32027 tipTitle.update('');
32030 el.dom.style.width = tm.maxWidth+'px';
32031 //tipBody.dom.style.width = '';
32032 tipBodyText.update(o.text);
32033 var p = getPad(), w = ce.width;
32035 var td = tipBodyText.dom;
32036 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32037 if(aw > tm.maxWidth){
32039 }else if(aw < tm.minWidth){
32045 //tipBody.setWidth(w);
32046 el.setWidth(parseInt(w, 10) + p);
32047 if(ce.autoHide === false){
32048 close.setDisplayed(true);
32053 close.setDisplayed(false);
32059 el.avoidY = xy[1]-18;
32064 el.setStyle("visibility", "visible");
32065 el.fadeIn({callback: afterShow});
32071 var afterShow = function(){
32075 if(tm.autoDismiss && ce.autoHide !== false){
32076 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32081 var hide = function(noanim){
32082 clearTimeout(dismissProc);
32083 clearTimeout(hideProc);
32085 if(el.isVisible()){
32087 if(noanim !== true && tm.animate){
32088 el.fadeOut({callback: afterHide});
32095 var afterHide = function(){
32098 el.removeClass(removeCls);
32105 * @cfg {Number} minWidth
32106 * The minimum width of the quick tip (defaults to 40)
32110 * @cfg {Number} maxWidth
32111 * The maximum width of the quick tip (defaults to 300)
32115 * @cfg {Boolean} interceptTitles
32116 * True to automatically use the element's DOM title value if available (defaults to false)
32118 interceptTitles : false,
32120 * @cfg {Boolean} trackMouse
32121 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32123 trackMouse : false,
32125 * @cfg {Boolean} hideOnClick
32126 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32128 hideOnClick : true,
32130 * @cfg {Number} showDelay
32131 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32135 * @cfg {Number} hideDelay
32136 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32140 * @cfg {Boolean} autoHide
32141 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32142 * Used in conjunction with hideDelay.
32147 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32148 * (defaults to true). Used in conjunction with autoDismissDelay.
32150 autoDismiss : true,
32153 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32155 autoDismissDelay : 5000,
32157 * @cfg {Boolean} animate
32158 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32163 * @cfg {String} title
32164 * Title text to display (defaults to ''). This can be any valid HTML markup.
32168 * @cfg {String} text
32169 * Body text to display (defaults to ''). This can be any valid HTML markup.
32173 * @cfg {String} cls
32174 * A CSS class to apply to the base quick tip element (defaults to '').
32178 * @cfg {Number} width
32179 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32180 * minWidth or maxWidth.
32185 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32186 * or display QuickTips in a page.
32189 tm = Roo.QuickTips;
32190 cfg = tm.tagConfig;
32192 if(!Roo.isReady){ // allow calling of init() before onReady
32193 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32196 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32197 el.fxDefaults = {stopFx: true};
32198 // maximum custom styling
32199 //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>');
32200 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>');
32201 tipTitle = el.child('h3');
32202 tipTitle.enableDisplayMode("block");
32203 tipBody = el.child('div.x-tip-bd');
32204 tipBodyText = el.child('div.x-tip-bd-inner');
32205 //bdLeft = el.child('div.x-tip-bd-left');
32206 //bdRight = el.child('div.x-tip-bd-right');
32207 close = el.child('div.x-tip-close');
32208 close.enableDisplayMode("block");
32209 close.on("click", hide);
32210 var d = Roo.get(document);
32211 d.on("mousedown", onDown);
32212 d.on("mouseover", onOver);
32213 d.on("mouseout", onOut);
32214 d.on("mousemove", onMove);
32215 esc = d.addKeyListener(27, hide);
32218 dd = el.initDD("default", null, {
32219 onDrag : function(){
32223 dd.setHandleElId(tipTitle.id);
32232 * Configures a new quick tip instance and assigns it to a target element. The following config options
32235 Property Type Description
32236 ---------- --------------------- ------------------------------------------------------------------------
32237 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32239 * @param {Object} config The config object
32241 register : function(config){
32242 var cs = config instanceof Array ? config : arguments;
32243 for(var i = 0, len = cs.length; i < len; i++) {
32245 var target = c.target;
32247 if(target instanceof Array){
32248 for(var j = 0, jlen = target.length; j < jlen; j++){
32249 tagEls[target[j]] = c;
32252 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32259 * Removes this quick tip from its element and destroys it.
32260 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32262 unregister : function(el){
32263 delete tagEls[Roo.id(el)];
32267 * Enable this quick tip.
32269 enable : function(){
32270 if(inited && disabled){
32272 if(locks.length < 1){
32279 * Disable this quick tip.
32281 disable : function(){
32283 clearTimeout(showProc);
32284 clearTimeout(hideProc);
32285 clearTimeout(dismissProc);
32293 * Returns true if the quick tip is enabled, else false.
32295 isEnabled : function(){
32302 attribute : "qtip",
32312 // backwards compat
32313 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32315 * Ext JS Library 1.1.1
32316 * Copyright(c) 2006-2007, Ext JS, LLC.
32318 * Originally Released Under LGPL - original licence link has changed is not relivant.
32321 * <script type="text/javascript">
32326 * @class Roo.tree.TreePanel
32327 * @extends Roo.data.Tree
32329 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32330 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32331 * @cfg {Boolean} enableDD true to enable drag and drop
32332 * @cfg {Boolean} enableDrag true to enable just drag
32333 * @cfg {Boolean} enableDrop true to enable just drop
32334 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32335 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32336 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32337 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32338 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32339 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32340 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32341 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32342 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32343 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32344 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32345 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32346 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32347 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32348 * @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>
32349 * @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>
32352 * @param {String/HTMLElement/Element} el The container element
32353 * @param {Object} config
32355 Roo.tree.TreePanel = function(el, config){
32357 var loader = false;
32359 root = config.root;
32360 delete config.root;
32362 if (config.loader) {
32363 loader = config.loader;
32364 delete config.loader;
32367 Roo.apply(this, config);
32368 Roo.tree.TreePanel.superclass.constructor.call(this);
32369 this.el = Roo.get(el);
32370 this.el.addClass('x-tree');
32371 //console.log(root);
32373 this.setRootNode( Roo.factory(root, Roo.tree));
32376 this.loader = Roo.factory(loader, Roo.tree);
32379 * Read-only. The id of the container element becomes this TreePanel's id.
32381 this.id = this.el.id;
32384 * @event beforeload
32385 * Fires before a node is loaded, return false to cancel
32386 * @param {Node} node The node being loaded
32388 "beforeload" : true,
32391 * Fires when a node is loaded
32392 * @param {Node} node The node that was loaded
32396 * @event textchange
32397 * Fires when the text for a node is changed
32398 * @param {Node} node The node
32399 * @param {String} text The new text
32400 * @param {String} oldText The old text
32402 "textchange" : true,
32404 * @event beforeexpand
32405 * Fires before a node is expanded, return false to cancel.
32406 * @param {Node} node The node
32407 * @param {Boolean} deep
32408 * @param {Boolean} anim
32410 "beforeexpand" : true,
32412 * @event beforecollapse
32413 * Fires before a node is collapsed, return false to cancel.
32414 * @param {Node} node The node
32415 * @param {Boolean} deep
32416 * @param {Boolean} anim
32418 "beforecollapse" : true,
32421 * Fires when a node is expanded
32422 * @param {Node} node The node
32426 * @event disabledchange
32427 * Fires when the disabled status of a node changes
32428 * @param {Node} node The node
32429 * @param {Boolean} disabled
32431 "disabledchange" : true,
32434 * Fires when a node is collapsed
32435 * @param {Node} node The node
32439 * @event beforeclick
32440 * Fires before click processing on a node. Return false to cancel the default action.
32441 * @param {Node} node The node
32442 * @param {Roo.EventObject} e The event object
32444 "beforeclick":true,
32446 * @event checkchange
32447 * Fires when a node with a checkbox's checked property changes
32448 * @param {Node} this This node
32449 * @param {Boolean} checked
32451 "checkchange":true,
32454 * Fires when a node is clicked
32455 * @param {Node} node The node
32456 * @param {Roo.EventObject} e The event object
32461 * Fires when a node is double clicked
32462 * @param {Node} node The node
32463 * @param {Roo.EventObject} e The event object
32467 * @event contextmenu
32468 * Fires when a node is right clicked
32469 * @param {Node} node The node
32470 * @param {Roo.EventObject} e The event object
32472 "contextmenu":true,
32474 * @event beforechildrenrendered
32475 * Fires right before the child nodes for a node are rendered
32476 * @param {Node} node The node
32478 "beforechildrenrendered":true,
32481 * Fires when a node starts being dragged
32482 * @param {Roo.tree.TreePanel} this
32483 * @param {Roo.tree.TreeNode} node
32484 * @param {event} e The raw browser event
32486 "startdrag" : true,
32489 * Fires when a drag operation is complete
32490 * @param {Roo.tree.TreePanel} this
32491 * @param {Roo.tree.TreeNode} node
32492 * @param {event} e The raw browser event
32497 * Fires when a dragged node is dropped on a valid DD target
32498 * @param {Roo.tree.TreePanel} this
32499 * @param {Roo.tree.TreeNode} node
32500 * @param {DD} dd The dd it was dropped on
32501 * @param {event} e The raw browser event
32505 * @event beforenodedrop
32506 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32507 * passed to handlers has the following properties:<br />
32508 * <ul style="padding:5px;padding-left:16px;">
32509 * <li>tree - The TreePanel</li>
32510 * <li>target - The node being targeted for the drop</li>
32511 * <li>data - The drag data from the drag source</li>
32512 * <li>point - The point of the drop - append, above or below</li>
32513 * <li>source - The drag source</li>
32514 * <li>rawEvent - Raw mouse event</li>
32515 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32516 * to be inserted by setting them on this object.</li>
32517 * <li>cancel - Set this to true to cancel the drop.</li>
32519 * @param {Object} dropEvent
32521 "beforenodedrop" : true,
32524 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32525 * passed to handlers has the following properties:<br />
32526 * <ul style="padding:5px;padding-left:16px;">
32527 * <li>tree - The TreePanel</li>
32528 * <li>target - The node being targeted for the drop</li>
32529 * <li>data - The drag data from the drag source</li>
32530 * <li>point - The point of the drop - append, above or below</li>
32531 * <li>source - The drag source</li>
32532 * <li>rawEvent - Raw mouse event</li>
32533 * <li>dropNode - Dropped node(s).</li>
32535 * @param {Object} dropEvent
32539 * @event nodedragover
32540 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32541 * passed to handlers has the following properties:<br />
32542 * <ul style="padding:5px;padding-left:16px;">
32543 * <li>tree - The TreePanel</li>
32544 * <li>target - The node being targeted for the drop</li>
32545 * <li>data - The drag data from the drag source</li>
32546 * <li>point - The point of the drop - append, above or below</li>
32547 * <li>source - The drag source</li>
32548 * <li>rawEvent - Raw mouse event</li>
32549 * <li>dropNode - Drop node(s) provided by the source.</li>
32550 * <li>cancel - Set this to true to signal drop not allowed.</li>
32552 * @param {Object} dragOverEvent
32554 "nodedragover" : true
32557 if(this.singleExpand){
32558 this.on("beforeexpand", this.restrictExpand, this);
32561 this.editor.tree = this;
32562 this.editor = Roo.factory(this.editor, Roo.tree);
32565 if (this.selModel) {
32566 this.selModel = Roo.factory(this.selModel, Roo.tree);
32570 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32571 rootVisible : true,
32572 animate: Roo.enableFx,
32575 hlDrop : Roo.enableFx,
32579 rendererTip: false,
32581 restrictExpand : function(node){
32582 var p = node.parentNode;
32584 if(p.expandedChild && p.expandedChild.parentNode == p){
32585 p.expandedChild.collapse();
32587 p.expandedChild = node;
32591 // private override
32592 setRootNode : function(node){
32593 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32594 if(!this.rootVisible){
32595 node.ui = new Roo.tree.RootTreeNodeUI(node);
32601 * Returns the container element for this TreePanel
32603 getEl : function(){
32608 * Returns the default TreeLoader for this TreePanel
32610 getLoader : function(){
32611 return this.loader;
32617 expandAll : function(){
32618 this.root.expand(true);
32622 * Collapse all nodes
32624 collapseAll : function(){
32625 this.root.collapse(true);
32629 * Returns the selection model used by this TreePanel
32631 getSelectionModel : function(){
32632 if(!this.selModel){
32633 this.selModel = new Roo.tree.DefaultSelectionModel();
32635 return this.selModel;
32639 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32640 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32641 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32644 getChecked : function(a, startNode){
32645 startNode = startNode || this.root;
32647 var f = function(){
32648 if(this.attributes.checked){
32649 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32652 startNode.cascade(f);
32657 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32658 * @param {String} path
32659 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32660 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32661 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32663 expandPath : function(path, attr, callback){
32664 attr = attr || "id";
32665 var keys = path.split(this.pathSeparator);
32666 var curNode = this.root;
32667 if(curNode.attributes[attr] != keys[1]){ // invalid root
32669 callback(false, null);
32674 var f = function(){
32675 if(++index == keys.length){
32677 callback(true, curNode);
32681 var c = curNode.findChild(attr, keys[index]);
32684 callback(false, curNode);
32689 c.expand(false, false, f);
32691 curNode.expand(false, false, f);
32695 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32696 * @param {String} path
32697 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32698 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32699 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32701 selectPath : function(path, attr, callback){
32702 attr = attr || "id";
32703 var keys = path.split(this.pathSeparator);
32704 var v = keys.pop();
32705 if(keys.length > 0){
32706 var f = function(success, node){
32707 if(success && node){
32708 var n = node.findChild(attr, v);
32714 }else if(callback){
32715 callback(false, n);
32719 callback(false, n);
32723 this.expandPath(keys.join(this.pathSeparator), attr, f);
32725 this.root.select();
32727 callback(true, this.root);
32732 getTreeEl : function(){
32737 * Trigger rendering of this TreePanel
32739 render : function(){
32740 if (this.innerCt) {
32741 return this; // stop it rendering more than once!!
32744 this.innerCt = this.el.createChild({tag:"ul",
32745 cls:"x-tree-root-ct " +
32746 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32748 if(this.containerScroll){
32749 Roo.dd.ScrollManager.register(this.el);
32751 if((this.enableDD || this.enableDrop) && !this.dropZone){
32753 * The dropZone used by this tree if drop is enabled
32754 * @type Roo.tree.TreeDropZone
32756 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32757 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32760 if((this.enableDD || this.enableDrag) && !this.dragZone){
32762 * The dragZone used by this tree if drag is enabled
32763 * @type Roo.tree.TreeDragZone
32765 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32766 ddGroup: this.ddGroup || "TreeDD",
32767 scroll: this.ddScroll
32770 this.getSelectionModel().init(this);
32772 Roo.log("ROOT not set in tree");
32775 this.root.render();
32776 if(!this.rootVisible){
32777 this.root.renderChildren();
32783 * Ext JS Library 1.1.1
32784 * Copyright(c) 2006-2007, Ext JS, LLC.
32786 * Originally Released Under LGPL - original licence link has changed is not relivant.
32789 * <script type="text/javascript">
32794 * @class Roo.tree.DefaultSelectionModel
32795 * @extends Roo.util.Observable
32796 * The default single selection for a TreePanel.
32797 * @param {Object} cfg Configuration
32799 Roo.tree.DefaultSelectionModel = function(cfg){
32800 this.selNode = null;
32806 * @event selectionchange
32807 * Fires when the selected node changes
32808 * @param {DefaultSelectionModel} this
32809 * @param {TreeNode} node the new selection
32811 "selectionchange" : true,
32814 * @event beforeselect
32815 * Fires before the selected node changes, return false to cancel the change
32816 * @param {DefaultSelectionModel} this
32817 * @param {TreeNode} node the new selection
32818 * @param {TreeNode} node the old selection
32820 "beforeselect" : true
32823 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32826 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32827 init : function(tree){
32829 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32830 tree.on("click", this.onNodeClick, this);
32833 onNodeClick : function(node, e){
32834 if (e.ctrlKey && this.selNode == node) {
32835 this.unselect(node);
32843 * @param {TreeNode} node The node to select
32844 * @return {TreeNode} The selected node
32846 select : function(node){
32847 var last = this.selNode;
32848 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32850 last.ui.onSelectedChange(false);
32852 this.selNode = node;
32853 node.ui.onSelectedChange(true);
32854 this.fireEvent("selectionchange", this, node, last);
32861 * @param {TreeNode} node The node to unselect
32863 unselect : function(node){
32864 if(this.selNode == node){
32865 this.clearSelections();
32870 * Clear all selections
32872 clearSelections : function(){
32873 var n = this.selNode;
32875 n.ui.onSelectedChange(false);
32876 this.selNode = null;
32877 this.fireEvent("selectionchange", this, null);
32883 * Get the selected node
32884 * @return {TreeNode} The selected node
32886 getSelectedNode : function(){
32887 return this.selNode;
32891 * Returns true if the node is selected
32892 * @param {TreeNode} node The node to check
32893 * @return {Boolean}
32895 isSelected : function(node){
32896 return this.selNode == node;
32900 * Selects the node above the selected node in the tree, intelligently walking the nodes
32901 * @return TreeNode The new selection
32903 selectPrevious : function(){
32904 var s = this.selNode || this.lastSelNode;
32908 var ps = s.previousSibling;
32910 if(!ps.isExpanded() || ps.childNodes.length < 1){
32911 return this.select(ps);
32913 var lc = ps.lastChild;
32914 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32917 return this.select(lc);
32919 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32920 return this.select(s.parentNode);
32926 * Selects the node above the selected node in the tree, intelligently walking the nodes
32927 * @return TreeNode The new selection
32929 selectNext : function(){
32930 var s = this.selNode || this.lastSelNode;
32934 if(s.firstChild && s.isExpanded()){
32935 return this.select(s.firstChild);
32936 }else if(s.nextSibling){
32937 return this.select(s.nextSibling);
32938 }else if(s.parentNode){
32940 s.parentNode.bubble(function(){
32941 if(this.nextSibling){
32942 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32951 onKeyDown : function(e){
32952 var s = this.selNode || this.lastSelNode;
32953 // undesirable, but required
32958 var k = e.getKey();
32966 this.selectPrevious();
32969 e.preventDefault();
32970 if(s.hasChildNodes()){
32971 if(!s.isExpanded()){
32973 }else if(s.firstChild){
32974 this.select(s.firstChild, e);
32979 e.preventDefault();
32980 if(s.hasChildNodes() && s.isExpanded()){
32982 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32983 this.select(s.parentNode, e);
32991 * @class Roo.tree.MultiSelectionModel
32992 * @extends Roo.util.Observable
32993 * Multi selection for a TreePanel.
32994 * @param {Object} cfg Configuration
32996 Roo.tree.MultiSelectionModel = function(){
32997 this.selNodes = [];
33001 * @event selectionchange
33002 * Fires when the selected nodes change
33003 * @param {MultiSelectionModel} this
33004 * @param {Array} nodes Array of the selected nodes
33006 "selectionchange" : true
33008 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33012 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33013 init : function(tree){
33015 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33016 tree.on("click", this.onNodeClick, this);
33019 onNodeClick : function(node, e){
33020 this.select(node, e, e.ctrlKey);
33025 * @param {TreeNode} node The node to select
33026 * @param {EventObject} e (optional) An event associated with the selection
33027 * @param {Boolean} keepExisting True to retain existing selections
33028 * @return {TreeNode} The selected node
33030 select : function(node, e, keepExisting){
33031 if(keepExisting !== true){
33032 this.clearSelections(true);
33034 if(this.isSelected(node)){
33035 this.lastSelNode = node;
33038 this.selNodes.push(node);
33039 this.selMap[node.id] = node;
33040 this.lastSelNode = node;
33041 node.ui.onSelectedChange(true);
33042 this.fireEvent("selectionchange", this, this.selNodes);
33048 * @param {TreeNode} node The node to unselect
33050 unselect : function(node){
33051 if(this.selMap[node.id]){
33052 node.ui.onSelectedChange(false);
33053 var sn = this.selNodes;
33056 index = sn.indexOf(node);
33058 for(var i = 0, len = sn.length; i < len; i++){
33066 this.selNodes.splice(index, 1);
33068 delete this.selMap[node.id];
33069 this.fireEvent("selectionchange", this, this.selNodes);
33074 * Clear all selections
33076 clearSelections : function(suppressEvent){
33077 var sn = this.selNodes;
33079 for(var i = 0, len = sn.length; i < len; i++){
33080 sn[i].ui.onSelectedChange(false);
33082 this.selNodes = [];
33084 if(suppressEvent !== true){
33085 this.fireEvent("selectionchange", this, this.selNodes);
33091 * Returns true if the node is selected
33092 * @param {TreeNode} node The node to check
33093 * @return {Boolean}
33095 isSelected : function(node){
33096 return this.selMap[node.id] ? true : false;
33100 * Returns an array of the selected nodes
33103 getSelectedNodes : function(){
33104 return this.selNodes;
33107 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33109 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33111 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33114 * Ext JS Library 1.1.1
33115 * Copyright(c) 2006-2007, Ext JS, LLC.
33117 * Originally Released Under LGPL - original licence link has changed is not relivant.
33120 * <script type="text/javascript">
33124 * @class Roo.tree.TreeNode
33125 * @extends Roo.data.Node
33126 * @cfg {String} text The text for this node
33127 * @cfg {Boolean} expanded true to start the node expanded
33128 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33129 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33130 * @cfg {Boolean} disabled true to start the node disabled
33131 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33132 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33133 * @cfg {String} cls A css class to be added to the node
33134 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33135 * @cfg {String} href URL of the link used for the node (defaults to #)
33136 * @cfg {String} hrefTarget target frame for the link
33137 * @cfg {String} qtip An Ext QuickTip for the node
33138 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33139 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33140 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33141 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33142 * (defaults to undefined with no checkbox rendered)
33144 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33146 Roo.tree.TreeNode = function(attributes){
33147 attributes = attributes || {};
33148 if(typeof attributes == "string"){
33149 attributes = {text: attributes};
33151 this.childrenRendered = false;
33152 this.rendered = false;
33153 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33154 this.expanded = attributes.expanded === true;
33155 this.isTarget = attributes.isTarget !== false;
33156 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33157 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33160 * Read-only. The text for this node. To change it use setText().
33163 this.text = attributes.text;
33165 * True if this node is disabled.
33168 this.disabled = attributes.disabled === true;
33172 * @event textchange
33173 * Fires when the text for this node is changed
33174 * @param {Node} this This node
33175 * @param {String} text The new text
33176 * @param {String} oldText The old text
33178 "textchange" : true,
33180 * @event beforeexpand
33181 * Fires before this node is expanded, return false to cancel.
33182 * @param {Node} this This node
33183 * @param {Boolean} deep
33184 * @param {Boolean} anim
33186 "beforeexpand" : true,
33188 * @event beforecollapse
33189 * Fires before this node is collapsed, return false to cancel.
33190 * @param {Node} this This node
33191 * @param {Boolean} deep
33192 * @param {Boolean} anim
33194 "beforecollapse" : true,
33197 * Fires when this node is expanded
33198 * @param {Node} this This node
33202 * @event disabledchange
33203 * Fires when the disabled status of this node changes
33204 * @param {Node} this This node
33205 * @param {Boolean} disabled
33207 "disabledchange" : true,
33210 * Fires when this node is collapsed
33211 * @param {Node} this This node
33215 * @event beforeclick
33216 * Fires before click processing. Return false to cancel the default action.
33217 * @param {Node} this This node
33218 * @param {Roo.EventObject} e The event object
33220 "beforeclick":true,
33222 * @event checkchange
33223 * Fires when a node with a checkbox's checked property changes
33224 * @param {Node} this This node
33225 * @param {Boolean} checked
33227 "checkchange":true,
33230 * Fires when this node is clicked
33231 * @param {Node} this This node
33232 * @param {Roo.EventObject} e The event object
33237 * Fires when this node is double clicked
33238 * @param {Node} this This node
33239 * @param {Roo.EventObject} e The event object
33243 * @event contextmenu
33244 * Fires when this node is right clicked
33245 * @param {Node} this This node
33246 * @param {Roo.EventObject} e The event object
33248 "contextmenu":true,
33250 * @event beforechildrenrendered
33251 * Fires right before the child nodes for this node are rendered
33252 * @param {Node} this This node
33254 "beforechildrenrendered":true
33257 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33260 * Read-only. The UI for this node
33263 this.ui = new uiClass(this);
33265 // finally support items[]
33266 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33271 Roo.each(this.attributes.items, function(c) {
33272 this.appendChild(Roo.factory(c,Roo.Tree));
33274 delete this.attributes.items;
33279 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33280 preventHScroll: true,
33282 * Returns true if this node is expanded
33283 * @return {Boolean}
33285 isExpanded : function(){
33286 return this.expanded;
33290 * Returns the UI object for this node
33291 * @return {TreeNodeUI}
33293 getUI : function(){
33297 // private override
33298 setFirstChild : function(node){
33299 var of = this.firstChild;
33300 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33301 if(this.childrenRendered && of && node != of){
33302 of.renderIndent(true, true);
33305 this.renderIndent(true, true);
33309 // private override
33310 setLastChild : function(node){
33311 var ol = this.lastChild;
33312 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33313 if(this.childrenRendered && ol && node != ol){
33314 ol.renderIndent(true, true);
33317 this.renderIndent(true, true);
33321 // these methods are overridden to provide lazy rendering support
33322 // private override
33323 appendChild : function()
33325 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33326 if(node && this.childrenRendered){
33329 this.ui.updateExpandIcon();
33333 // private override
33334 removeChild : function(node){
33335 this.ownerTree.getSelectionModel().unselect(node);
33336 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33337 // if it's been rendered remove dom node
33338 if(this.childrenRendered){
33341 if(this.childNodes.length < 1){
33342 this.collapse(false, false);
33344 this.ui.updateExpandIcon();
33346 if(!this.firstChild) {
33347 this.childrenRendered = false;
33352 // private override
33353 insertBefore : function(node, refNode){
33354 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33355 if(newNode && refNode && this.childrenRendered){
33358 this.ui.updateExpandIcon();
33363 * Sets the text for this node
33364 * @param {String} text
33366 setText : function(text){
33367 var oldText = this.text;
33369 this.attributes.text = text;
33370 if(this.rendered){ // event without subscribing
33371 this.ui.onTextChange(this, text, oldText);
33373 this.fireEvent("textchange", this, text, oldText);
33377 * Triggers selection of this node
33379 select : function(){
33380 this.getOwnerTree().getSelectionModel().select(this);
33384 * Triggers deselection of this node
33386 unselect : function(){
33387 this.getOwnerTree().getSelectionModel().unselect(this);
33391 * Returns true if this node is selected
33392 * @return {Boolean}
33394 isSelected : function(){
33395 return this.getOwnerTree().getSelectionModel().isSelected(this);
33399 * Expand this node.
33400 * @param {Boolean} deep (optional) True to expand all children as well
33401 * @param {Boolean} anim (optional) false to cancel the default animation
33402 * @param {Function} callback (optional) A callback to be called when
33403 * expanding this node completes (does not wait for deep expand to complete).
33404 * Called with 1 parameter, this node.
33406 expand : function(deep, anim, callback){
33407 if(!this.expanded){
33408 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33411 if(!this.childrenRendered){
33412 this.renderChildren();
33414 this.expanded = true;
33415 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33416 this.ui.animExpand(function(){
33417 this.fireEvent("expand", this);
33418 if(typeof callback == "function"){
33422 this.expandChildNodes(true);
33424 }.createDelegate(this));
33428 this.fireEvent("expand", this);
33429 if(typeof callback == "function"){
33434 if(typeof callback == "function"){
33439 this.expandChildNodes(true);
33443 isHiddenRoot : function(){
33444 return this.isRoot && !this.getOwnerTree().rootVisible;
33448 * Collapse this node.
33449 * @param {Boolean} deep (optional) True to collapse all children as well
33450 * @param {Boolean} anim (optional) false to cancel the default animation
33452 collapse : function(deep, anim){
33453 if(this.expanded && !this.isHiddenRoot()){
33454 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33457 this.expanded = false;
33458 if((this.getOwnerTree().animate && anim !== false) || anim){
33459 this.ui.animCollapse(function(){
33460 this.fireEvent("collapse", this);
33462 this.collapseChildNodes(true);
33464 }.createDelegate(this));
33467 this.ui.collapse();
33468 this.fireEvent("collapse", this);
33472 var cs = this.childNodes;
33473 for(var i = 0, len = cs.length; i < len; i++) {
33474 cs[i].collapse(true, false);
33480 delayedExpand : function(delay){
33481 if(!this.expandProcId){
33482 this.expandProcId = this.expand.defer(delay, this);
33487 cancelExpand : function(){
33488 if(this.expandProcId){
33489 clearTimeout(this.expandProcId);
33491 this.expandProcId = false;
33495 * Toggles expanded/collapsed state of the node
33497 toggle : function(){
33506 * Ensures all parent nodes are expanded
33508 ensureVisible : function(callback){
33509 var tree = this.getOwnerTree();
33510 tree.expandPath(this.parentNode.getPath(), false, function(){
33511 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33512 Roo.callback(callback);
33513 }.createDelegate(this));
33517 * Expand all child nodes
33518 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33520 expandChildNodes : function(deep){
33521 var cs = this.childNodes;
33522 for(var i = 0, len = cs.length; i < len; i++) {
33523 cs[i].expand(deep);
33528 * Collapse all child nodes
33529 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33531 collapseChildNodes : function(deep){
33532 var cs = this.childNodes;
33533 for(var i = 0, len = cs.length; i < len; i++) {
33534 cs[i].collapse(deep);
33539 * Disables this node
33541 disable : function(){
33542 this.disabled = true;
33544 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33545 this.ui.onDisableChange(this, true);
33547 this.fireEvent("disabledchange", this, true);
33551 * Enables this node
33553 enable : function(){
33554 this.disabled = false;
33555 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33556 this.ui.onDisableChange(this, false);
33558 this.fireEvent("disabledchange", this, false);
33562 renderChildren : function(suppressEvent){
33563 if(suppressEvent !== false){
33564 this.fireEvent("beforechildrenrendered", this);
33566 var cs = this.childNodes;
33567 for(var i = 0, len = cs.length; i < len; i++){
33568 cs[i].render(true);
33570 this.childrenRendered = true;
33574 sort : function(fn, scope){
33575 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33576 if(this.childrenRendered){
33577 var cs = this.childNodes;
33578 for(var i = 0, len = cs.length; i < len; i++){
33579 cs[i].render(true);
33585 render : function(bulkRender){
33586 this.ui.render(bulkRender);
33587 if(!this.rendered){
33588 this.rendered = true;
33590 this.expanded = false;
33591 this.expand(false, false);
33597 renderIndent : function(deep, refresh){
33599 this.ui.childIndent = null;
33601 this.ui.renderIndent();
33602 if(deep === true && this.childrenRendered){
33603 var cs = this.childNodes;
33604 for(var i = 0, len = cs.length; i < len; i++){
33605 cs[i].renderIndent(true, refresh);
33611 * Ext JS Library 1.1.1
33612 * Copyright(c) 2006-2007, Ext JS, LLC.
33614 * Originally Released Under LGPL - original licence link has changed is not relivant.
33617 * <script type="text/javascript">
33621 * @class Roo.tree.AsyncTreeNode
33622 * @extends Roo.tree.TreeNode
33623 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33625 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33627 Roo.tree.AsyncTreeNode = function(config){
33628 this.loaded = false;
33629 this.loading = false;
33630 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33632 * @event beforeload
33633 * Fires before this node is loaded, return false to cancel
33634 * @param {Node} this This node
33636 this.addEvents({'beforeload':true, 'load': true});
33639 * Fires when this node is loaded
33640 * @param {Node} this This node
33643 * The loader used by this node (defaults to using the tree's defined loader)
33648 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33649 expand : function(deep, anim, callback){
33650 if(this.loading){ // if an async load is already running, waiting til it's done
33652 var f = function(){
33653 if(!this.loading){ // done loading
33654 clearInterval(timer);
33655 this.expand(deep, anim, callback);
33657 }.createDelegate(this);
33658 timer = setInterval(f, 200);
33662 if(this.fireEvent("beforeload", this) === false){
33665 this.loading = true;
33666 this.ui.beforeLoad(this);
33667 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33669 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33673 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33677 * Returns true if this node is currently loading
33678 * @return {Boolean}
33680 isLoading : function(){
33681 return this.loading;
33684 loadComplete : function(deep, anim, callback){
33685 this.loading = false;
33686 this.loaded = true;
33687 this.ui.afterLoad(this);
33688 this.fireEvent("load", this);
33689 this.expand(deep, anim, callback);
33693 * Returns true if this node has been loaded
33694 * @return {Boolean}
33696 isLoaded : function(){
33697 return this.loaded;
33700 hasChildNodes : function(){
33701 if(!this.isLeaf() && !this.loaded){
33704 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33709 * Trigger a reload for this node
33710 * @param {Function} callback
33712 reload : function(callback){
33713 this.collapse(false, false);
33714 while(this.firstChild){
33715 this.removeChild(this.firstChild);
33717 this.childrenRendered = false;
33718 this.loaded = false;
33719 if(this.isHiddenRoot()){
33720 this.expanded = false;
33722 this.expand(false, false, callback);
33726 * Ext JS Library 1.1.1
33727 * Copyright(c) 2006-2007, Ext JS, LLC.
33729 * Originally Released Under LGPL - original licence link has changed is not relivant.
33732 * <script type="text/javascript">
33736 * @class Roo.tree.TreeNodeUI
33738 * @param {Object} node The node to render
33739 * The TreeNode UI implementation is separate from the
33740 * tree implementation. Unless you are customizing the tree UI,
33741 * you should never have to use this directly.
33743 Roo.tree.TreeNodeUI = function(node){
33745 this.rendered = false;
33746 this.animating = false;
33747 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33750 Roo.tree.TreeNodeUI.prototype = {
33751 removeChild : function(node){
33753 this.ctNode.removeChild(node.ui.getEl());
33757 beforeLoad : function(){
33758 this.addClass("x-tree-node-loading");
33761 afterLoad : function(){
33762 this.removeClass("x-tree-node-loading");
33765 onTextChange : function(node, text, oldText){
33767 this.textNode.innerHTML = text;
33771 onDisableChange : function(node, state){
33772 this.disabled = state;
33774 this.addClass("x-tree-node-disabled");
33776 this.removeClass("x-tree-node-disabled");
33780 onSelectedChange : function(state){
33783 this.addClass("x-tree-selected");
33786 this.removeClass("x-tree-selected");
33790 onMove : function(tree, node, oldParent, newParent, index, refNode){
33791 this.childIndent = null;
33793 var targetNode = newParent.ui.getContainer();
33794 if(!targetNode){//target not rendered
33795 this.holder = document.createElement("div");
33796 this.holder.appendChild(this.wrap);
33799 var insertBefore = refNode ? refNode.ui.getEl() : null;
33801 targetNode.insertBefore(this.wrap, insertBefore);
33803 targetNode.appendChild(this.wrap);
33805 this.node.renderIndent(true);
33809 addClass : function(cls){
33811 Roo.fly(this.elNode).addClass(cls);
33815 removeClass : function(cls){
33817 Roo.fly(this.elNode).removeClass(cls);
33821 remove : function(){
33823 this.holder = document.createElement("div");
33824 this.holder.appendChild(this.wrap);
33828 fireEvent : function(){
33829 return this.node.fireEvent.apply(this.node, arguments);
33832 initEvents : function(){
33833 this.node.on("move", this.onMove, this);
33834 var E = Roo.EventManager;
33835 var a = this.anchor;
33837 var el = Roo.fly(a, '_treeui');
33839 if(Roo.isOpera){ // opera render bug ignores the CSS
33840 el.setStyle("text-decoration", "none");
33843 el.on("click", this.onClick, this);
33844 el.on("dblclick", this.onDblClick, this);
33847 Roo.EventManager.on(this.checkbox,
33848 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33851 el.on("contextmenu", this.onContextMenu, this);
33853 var icon = Roo.fly(this.iconNode);
33854 icon.on("click", this.onClick, this);
33855 icon.on("dblclick", this.onDblClick, this);
33856 icon.on("contextmenu", this.onContextMenu, this);
33857 E.on(this.ecNode, "click", this.ecClick, this, true);
33859 if(this.node.disabled){
33860 this.addClass("x-tree-node-disabled");
33862 if(this.node.hidden){
33863 this.addClass("x-tree-node-disabled");
33865 var ot = this.node.getOwnerTree();
33866 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33867 if(dd && (!this.node.isRoot || ot.rootVisible)){
33868 Roo.dd.Registry.register(this.elNode, {
33870 handles: this.getDDHandles(),
33876 getDDHandles : function(){
33877 return [this.iconNode, this.textNode];
33882 this.wrap.style.display = "none";
33888 this.wrap.style.display = "";
33892 onContextMenu : function(e){
33893 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33894 e.preventDefault();
33896 this.fireEvent("contextmenu", this.node, e);
33900 onClick : function(e){
33905 if(this.fireEvent("beforeclick", this.node, e) !== false){
33906 if(!this.disabled && this.node.attributes.href){
33907 this.fireEvent("click", this.node, e);
33910 e.preventDefault();
33915 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33916 this.node.toggle();
33919 this.fireEvent("click", this.node, e);
33925 onDblClick : function(e){
33926 e.preventDefault();
33931 this.toggleCheck();
33933 if(!this.animating && this.node.hasChildNodes()){
33934 this.node.toggle();
33936 this.fireEvent("dblclick", this.node, e);
33939 onCheckChange : function(){
33940 var checked = this.checkbox.checked;
33941 this.node.attributes.checked = checked;
33942 this.fireEvent('checkchange', this.node, checked);
33945 ecClick : function(e){
33946 if(!this.animating && this.node.hasChildNodes()){
33947 this.node.toggle();
33951 startDrop : function(){
33952 this.dropping = true;
33955 // delayed drop so the click event doesn't get fired on a drop
33956 endDrop : function(){
33957 setTimeout(function(){
33958 this.dropping = false;
33959 }.createDelegate(this), 50);
33962 expand : function(){
33963 this.updateExpandIcon();
33964 this.ctNode.style.display = "";
33967 focus : function(){
33968 if(!this.node.preventHScroll){
33969 try{this.anchor.focus();
33971 }else if(!Roo.isIE){
33973 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33974 var l = noscroll.scrollLeft;
33975 this.anchor.focus();
33976 noscroll.scrollLeft = l;
33981 toggleCheck : function(value){
33982 var cb = this.checkbox;
33984 cb.checked = (value === undefined ? !cb.checked : value);
33990 this.anchor.blur();
33994 animExpand : function(callback){
33995 var ct = Roo.get(this.ctNode);
33997 if(!this.node.hasChildNodes()){
33998 this.updateExpandIcon();
33999 this.ctNode.style.display = "";
34000 Roo.callback(callback);
34003 this.animating = true;
34004 this.updateExpandIcon();
34007 callback : function(){
34008 this.animating = false;
34009 Roo.callback(callback);
34012 duration: this.node.ownerTree.duration || .25
34016 highlight : function(){
34017 var tree = this.node.getOwnerTree();
34018 Roo.fly(this.wrap).highlight(
34019 tree.hlColor || "C3DAF9",
34020 {endColor: tree.hlBaseColor}
34024 collapse : function(){
34025 this.updateExpandIcon();
34026 this.ctNode.style.display = "none";
34029 animCollapse : function(callback){
34030 var ct = Roo.get(this.ctNode);
34031 ct.enableDisplayMode('block');
34034 this.animating = true;
34035 this.updateExpandIcon();
34038 callback : function(){
34039 this.animating = false;
34040 Roo.callback(callback);
34043 duration: this.node.ownerTree.duration || .25
34047 getContainer : function(){
34048 return this.ctNode;
34051 getEl : function(){
34055 appendDDGhost : function(ghostNode){
34056 ghostNode.appendChild(this.elNode.cloneNode(true));
34059 getDDRepairXY : function(){
34060 return Roo.lib.Dom.getXY(this.iconNode);
34063 onRender : function(){
34067 render : function(bulkRender){
34068 var n = this.node, a = n.attributes;
34069 var targetNode = n.parentNode ?
34070 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34072 if(!this.rendered){
34073 this.rendered = true;
34075 this.renderElements(n, a, targetNode, bulkRender);
34078 if(this.textNode.setAttributeNS){
34079 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34081 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34084 this.textNode.setAttribute("ext:qtip", a.qtip);
34086 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34089 }else if(a.qtipCfg){
34090 a.qtipCfg.target = Roo.id(this.textNode);
34091 Roo.QuickTips.register(a.qtipCfg);
34094 if(!this.node.expanded){
34095 this.updateExpandIcon();
34098 if(bulkRender === true) {
34099 targetNode.appendChild(this.wrap);
34104 renderElements : function(n, a, targetNode, bulkRender)
34106 // add some indent caching, this helps performance when rendering a large tree
34107 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34108 var t = n.getOwnerTree();
34109 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34110 if (typeof(n.attributes.html) != 'undefined') {
34111 txt = n.attributes.html;
34113 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34114 var cb = typeof a.checked == 'boolean';
34115 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34116 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34117 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34118 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34119 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34120 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34121 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34122 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34123 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34124 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34127 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34128 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34129 n.nextSibling.ui.getEl(), buf.join(""));
34131 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34134 this.elNode = this.wrap.childNodes[0];
34135 this.ctNode = this.wrap.childNodes[1];
34136 var cs = this.elNode.childNodes;
34137 this.indentNode = cs[0];
34138 this.ecNode = cs[1];
34139 this.iconNode = cs[2];
34142 this.checkbox = cs[3];
34145 this.anchor = cs[index];
34146 this.textNode = cs[index].firstChild;
34149 getAnchor : function(){
34150 return this.anchor;
34153 getTextEl : function(){
34154 return this.textNode;
34157 getIconEl : function(){
34158 return this.iconNode;
34161 isChecked : function(){
34162 return this.checkbox ? this.checkbox.checked : false;
34165 updateExpandIcon : function(){
34167 var n = this.node, c1, c2;
34168 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34169 var hasChild = n.hasChildNodes();
34173 c1 = "x-tree-node-collapsed";
34174 c2 = "x-tree-node-expanded";
34177 c1 = "x-tree-node-expanded";
34178 c2 = "x-tree-node-collapsed";
34181 this.removeClass("x-tree-node-leaf");
34182 this.wasLeaf = false;
34184 if(this.c1 != c1 || this.c2 != c2){
34185 Roo.fly(this.elNode).replaceClass(c1, c2);
34186 this.c1 = c1; this.c2 = c2;
34189 // this changes non-leafs into leafs if they have no children.
34190 // it's not very rational behaviour..
34192 if(!this.wasLeaf && this.node.leaf){
34193 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34196 this.wasLeaf = true;
34199 var ecc = "x-tree-ec-icon "+cls;
34200 if(this.ecc != ecc){
34201 this.ecNode.className = ecc;
34207 getChildIndent : function(){
34208 if(!this.childIndent){
34212 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34214 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34216 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34221 this.childIndent = buf.join("");
34223 return this.childIndent;
34226 renderIndent : function(){
34229 var p = this.node.parentNode;
34231 indent = p.ui.getChildIndent();
34233 if(this.indentMarkup != indent){ // don't rerender if not required
34234 this.indentNode.innerHTML = indent;
34235 this.indentMarkup = indent;
34237 this.updateExpandIcon();
34242 Roo.tree.RootTreeNodeUI = function(){
34243 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34245 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34246 render : function(){
34247 if(!this.rendered){
34248 var targetNode = this.node.ownerTree.innerCt.dom;
34249 this.node.expanded = true;
34250 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34251 this.wrap = this.ctNode = targetNode.firstChild;
34254 collapse : function(){
34256 expand : function(){
34260 * Ext JS Library 1.1.1
34261 * Copyright(c) 2006-2007, Ext JS, LLC.
34263 * Originally Released Under LGPL - original licence link has changed is not relivant.
34266 * <script type="text/javascript">
34269 * @class Roo.tree.TreeLoader
34270 * @extends Roo.util.Observable
34271 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34272 * nodes from a specified URL. The response must be a javascript Array definition
34273 * who's elements are node definition objects. eg:
34278 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34279 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34286 * The old style respose with just an array is still supported, but not recommended.
34289 * A server request is sent, and child nodes are loaded only when a node is expanded.
34290 * The loading node's id is passed to the server under the parameter name "node" to
34291 * enable the server to produce the correct child nodes.
34293 * To pass extra parameters, an event handler may be attached to the "beforeload"
34294 * event, and the parameters specified in the TreeLoader's baseParams property:
34296 myTreeLoader.on("beforeload", function(treeLoader, node) {
34297 this.baseParams.category = node.attributes.category;
34300 * This would pass an HTTP parameter called "category" to the server containing
34301 * the value of the Node's "category" attribute.
34303 * Creates a new Treeloader.
34304 * @param {Object} config A config object containing config properties.
34306 Roo.tree.TreeLoader = function(config){
34307 this.baseParams = {};
34308 this.requestMethod = "POST";
34309 Roo.apply(this, config);
34314 * @event beforeload
34315 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34316 * @param {Object} This TreeLoader object.
34317 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34318 * @param {Object} callback The callback function specified in the {@link #load} call.
34323 * Fires when the node has been successfuly loaded.
34324 * @param {Object} This TreeLoader object.
34325 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34326 * @param {Object} response The response object containing the data from the server.
34330 * @event loadexception
34331 * Fires if the network request failed.
34332 * @param {Object} This TreeLoader object.
34333 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34334 * @param {Object} response The response object containing the data from the server.
34336 loadexception : true,
34339 * Fires before a node is created, enabling you to return custom Node types
34340 * @param {Object} This TreeLoader object.
34341 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34346 Roo.tree.TreeLoader.superclass.constructor.call(this);
34349 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34351 * @cfg {String} dataUrl The URL from which to request a Json string which
34352 * specifies an array of node definition object representing the child nodes
34356 * @cfg {String} requestMethod either GET or POST
34357 * defaults to POST (due to BC)
34361 * @cfg {Object} baseParams (optional) An object containing properties which
34362 * specify HTTP parameters to be passed to each request for child nodes.
34365 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34366 * created by this loader. If the attributes sent by the server have an attribute in this object,
34367 * they take priority.
34370 * @cfg {Object} uiProviders (optional) An object containing properties which
34372 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34373 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34374 * <i>uiProvider</i> attribute of a returned child node is a string rather
34375 * than a reference to a TreeNodeUI implementation, this that string value
34376 * is used as a property name in the uiProviders object. You can define the provider named
34377 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34382 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34383 * child nodes before loading.
34385 clearOnLoad : true,
34388 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34389 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34390 * Grid query { data : [ .....] }
34395 * @cfg {String} queryParam (optional)
34396 * Name of the query as it will be passed on the querystring (defaults to 'node')
34397 * eg. the request will be ?node=[id]
34404 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34405 * This is called automatically when a node is expanded, but may be used to reload
34406 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34407 * @param {Roo.tree.TreeNode} node
34408 * @param {Function} callback
34410 load : function(node, callback){
34411 if(this.clearOnLoad){
34412 while(node.firstChild){
34413 node.removeChild(node.firstChild);
34416 if(node.attributes.children){ // preloaded json children
34417 var cs = node.attributes.children;
34418 for(var i = 0, len = cs.length; i < len; i++){
34419 node.appendChild(this.createNode(cs[i]));
34421 if(typeof callback == "function"){
34424 }else if(this.dataUrl){
34425 this.requestData(node, callback);
34429 getParams: function(node){
34430 var buf = [], bp = this.baseParams;
34431 for(var key in bp){
34432 if(typeof bp[key] != "function"){
34433 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34436 var n = this.queryParam === false ? 'node' : this.queryParam;
34437 buf.push(n + "=", encodeURIComponent(node.id));
34438 return buf.join("");
34441 requestData : function(node, callback){
34442 if(this.fireEvent("beforeload", this, node, callback) !== false){
34443 this.transId = Roo.Ajax.request({
34444 method:this.requestMethod,
34445 url: this.dataUrl||this.url,
34446 success: this.handleResponse,
34447 failure: this.handleFailure,
34449 argument: {callback: callback, node: node},
34450 params: this.getParams(node)
34453 // if the load is cancelled, make sure we notify
34454 // the node that we are done
34455 if(typeof callback == "function"){
34461 isLoading : function(){
34462 return this.transId ? true : false;
34465 abort : function(){
34466 if(this.isLoading()){
34467 Roo.Ajax.abort(this.transId);
34472 createNode : function(attr)
34474 // apply baseAttrs, nice idea Corey!
34475 if(this.baseAttrs){
34476 Roo.applyIf(attr, this.baseAttrs);
34478 if(this.applyLoader !== false){
34479 attr.loader = this;
34481 // uiProvider = depreciated..
34483 if(typeof(attr.uiProvider) == 'string'){
34484 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34485 /** eval:var:attr */ eval(attr.uiProvider);
34487 if(typeof(this.uiProviders['default']) != 'undefined') {
34488 attr.uiProvider = this.uiProviders['default'];
34491 this.fireEvent('create', this, attr);
34493 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34495 new Roo.tree.TreeNode(attr) :
34496 new Roo.tree.AsyncTreeNode(attr));
34499 processResponse : function(response, node, callback)
34501 var json = response.responseText;
34504 var o = Roo.decode(json);
34506 if (this.root === false && typeof(o.success) != undefined) {
34507 this.root = 'data'; // the default behaviour for list like data..
34510 if (this.root !== false && !o.success) {
34511 // it's a failure condition.
34512 var a = response.argument;
34513 this.fireEvent("loadexception", this, a.node, response);
34514 Roo.log("Load failed - should have a handler really");
34520 if (this.root !== false) {
34524 for(var i = 0, len = o.length; i < len; i++){
34525 var n = this.createNode(o[i]);
34527 node.appendChild(n);
34530 if(typeof callback == "function"){
34531 callback(this, node);
34534 this.handleFailure(response);
34538 handleResponse : function(response){
34539 this.transId = false;
34540 var a = response.argument;
34541 this.processResponse(response, a.node, a.callback);
34542 this.fireEvent("load", this, a.node, response);
34545 handleFailure : function(response)
34547 // should handle failure better..
34548 this.transId = false;
34549 var a = response.argument;
34550 this.fireEvent("loadexception", this, a.node, response);
34551 if(typeof a.callback == "function"){
34552 a.callback(this, a.node);
34557 * Ext JS Library 1.1.1
34558 * Copyright(c) 2006-2007, Ext JS, LLC.
34560 * Originally Released Under LGPL - original licence link has changed is not relivant.
34563 * <script type="text/javascript">
34567 * @class Roo.tree.TreeFilter
34568 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34569 * @param {TreePanel} tree
34570 * @param {Object} config (optional)
34572 Roo.tree.TreeFilter = function(tree, config){
34574 this.filtered = {};
34575 Roo.apply(this, config);
34578 Roo.tree.TreeFilter.prototype = {
34585 * Filter the data by a specific attribute.
34586 * @param {String/RegExp} value Either string that the attribute value
34587 * should start with or a RegExp to test against the attribute
34588 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34589 * @param {TreeNode} startNode (optional) The node to start the filter at.
34591 filter : function(value, attr, startNode){
34592 attr = attr || "text";
34594 if(typeof value == "string"){
34595 var vlen = value.length;
34596 // auto clear empty filter
34597 if(vlen == 0 && this.clearBlank){
34601 value = value.toLowerCase();
34603 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34605 }else if(value.exec){ // regex?
34607 return value.test(n.attributes[attr]);
34610 throw 'Illegal filter type, must be string or regex';
34612 this.filterBy(f, null, startNode);
34616 * Filter by a function. The passed function will be called with each
34617 * node in the tree (or from the startNode). If the function returns true, the node is kept
34618 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34619 * @param {Function} fn The filter function
34620 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34622 filterBy : function(fn, scope, startNode){
34623 startNode = startNode || this.tree.root;
34624 if(this.autoClear){
34627 var af = this.filtered, rv = this.reverse;
34628 var f = function(n){
34629 if(n == startNode){
34635 var m = fn.call(scope || n, n);
34643 startNode.cascade(f);
34646 if(typeof id != "function"){
34648 if(n && n.parentNode){
34649 n.parentNode.removeChild(n);
34657 * Clears the current filter. Note: with the "remove" option
34658 * set a filter cannot be cleared.
34660 clear : function(){
34662 var af = this.filtered;
34664 if(typeof id != "function"){
34671 this.filtered = {};
34676 * Ext JS Library 1.1.1
34677 * Copyright(c) 2006-2007, Ext JS, LLC.
34679 * Originally Released Under LGPL - original licence link has changed is not relivant.
34682 * <script type="text/javascript">
34687 * @class Roo.tree.TreeSorter
34688 * Provides sorting of nodes in a TreePanel
34690 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34691 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34692 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34693 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34694 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34695 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34697 * @param {TreePanel} tree
34698 * @param {Object} config
34700 Roo.tree.TreeSorter = function(tree, config){
34701 Roo.apply(this, config);
34702 tree.on("beforechildrenrendered", this.doSort, this);
34703 tree.on("append", this.updateSort, this);
34704 tree.on("insert", this.updateSort, this);
34706 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34707 var p = this.property || "text";
34708 var sortType = this.sortType;
34709 var fs = this.folderSort;
34710 var cs = this.caseSensitive === true;
34711 var leafAttr = this.leafAttr || 'leaf';
34713 this.sortFn = function(n1, n2){
34715 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34718 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34722 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34723 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34725 return dsc ? +1 : -1;
34727 return dsc ? -1 : +1;
34734 Roo.tree.TreeSorter.prototype = {
34735 doSort : function(node){
34736 node.sort(this.sortFn);
34739 compareNodes : function(n1, n2){
34740 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34743 updateSort : function(tree, node){
34744 if(node.childrenRendered){
34745 this.doSort.defer(1, this, [node]);
34750 * Ext JS Library 1.1.1
34751 * Copyright(c) 2006-2007, Ext JS, LLC.
34753 * Originally Released Under LGPL - original licence link has changed is not relivant.
34756 * <script type="text/javascript">
34759 if(Roo.dd.DropZone){
34761 Roo.tree.TreeDropZone = function(tree, config){
34762 this.allowParentInsert = false;
34763 this.allowContainerDrop = false;
34764 this.appendOnly = false;
34765 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34767 this.lastInsertClass = "x-tree-no-status";
34768 this.dragOverData = {};
34771 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34772 ddGroup : "TreeDD",
34775 expandDelay : 1000,
34777 expandNode : function(node){
34778 if(node.hasChildNodes() && !node.isExpanded()){
34779 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34783 queueExpand : function(node){
34784 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34787 cancelExpand : function(){
34788 if(this.expandProcId){
34789 clearTimeout(this.expandProcId);
34790 this.expandProcId = false;
34794 isValidDropPoint : function(n, pt, dd, e, data){
34795 if(!n || !data){ return false; }
34796 var targetNode = n.node;
34797 var dropNode = data.node;
34798 // default drop rules
34799 if(!(targetNode && targetNode.isTarget && pt)){
34802 if(pt == "append" && targetNode.allowChildren === false){
34805 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34808 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34811 // reuse the object
34812 var overEvent = this.dragOverData;
34813 overEvent.tree = this.tree;
34814 overEvent.target = targetNode;
34815 overEvent.data = data;
34816 overEvent.point = pt;
34817 overEvent.source = dd;
34818 overEvent.rawEvent = e;
34819 overEvent.dropNode = dropNode;
34820 overEvent.cancel = false;
34821 var result = this.tree.fireEvent("nodedragover", overEvent);
34822 return overEvent.cancel === false && result !== false;
34825 getDropPoint : function(e, n, dd)
34829 return tn.allowChildren !== false ? "append" : false; // always append for root
34831 var dragEl = n.ddel;
34832 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34833 var y = Roo.lib.Event.getPageY(e);
34834 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34836 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34837 var noAppend = tn.allowChildren === false;
34838 if(this.appendOnly || tn.parentNode.allowChildren === false){
34839 return noAppend ? false : "append";
34841 var noBelow = false;
34842 if(!this.allowParentInsert){
34843 noBelow = tn.hasChildNodes() && tn.isExpanded();
34845 var q = (b - t) / (noAppend ? 2 : 3);
34846 if(y >= t && y < (t + q)){
34848 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34855 onNodeEnter : function(n, dd, e, data)
34857 this.cancelExpand();
34860 onNodeOver : function(n, dd, e, data)
34863 var pt = this.getDropPoint(e, n, dd);
34866 // auto node expand check
34867 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34868 this.queueExpand(node);
34869 }else if(pt != "append"){
34870 this.cancelExpand();
34873 // set the insert point style on the target node
34874 var returnCls = this.dropNotAllowed;
34875 if(this.isValidDropPoint(n, pt, dd, e, data)){
34880 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34881 cls = "x-tree-drag-insert-above";
34882 }else if(pt == "below"){
34883 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34884 cls = "x-tree-drag-insert-below";
34886 returnCls = "x-tree-drop-ok-append";
34887 cls = "x-tree-drag-append";
34889 if(this.lastInsertClass != cls){
34890 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34891 this.lastInsertClass = cls;
34898 onNodeOut : function(n, dd, e, data){
34900 this.cancelExpand();
34901 this.removeDropIndicators(n);
34904 onNodeDrop : function(n, dd, e, data){
34905 var point = this.getDropPoint(e, n, dd);
34906 var targetNode = n.node;
34907 targetNode.ui.startDrop();
34908 if(!this.isValidDropPoint(n, point, dd, e, data)){
34909 targetNode.ui.endDrop();
34912 // first try to find the drop node
34913 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34916 target: targetNode,
34921 dropNode: dropNode,
34924 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34925 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34926 targetNode.ui.endDrop();
34929 // allow target changing
34930 targetNode = dropEvent.target;
34931 if(point == "append" && !targetNode.isExpanded()){
34932 targetNode.expand(false, null, function(){
34933 this.completeDrop(dropEvent);
34934 }.createDelegate(this));
34936 this.completeDrop(dropEvent);
34941 completeDrop : function(de){
34942 var ns = de.dropNode, p = de.point, t = de.target;
34943 if(!(ns instanceof Array)){
34947 for(var i = 0, len = ns.length; i < len; i++){
34950 t.parentNode.insertBefore(n, t);
34951 }else if(p == "below"){
34952 t.parentNode.insertBefore(n, t.nextSibling);
34958 if(this.tree.hlDrop){
34962 this.tree.fireEvent("nodedrop", de);
34965 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34966 if(this.tree.hlDrop){
34967 dropNode.ui.focus();
34968 dropNode.ui.highlight();
34970 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34973 getTree : function(){
34977 removeDropIndicators : function(n){
34980 Roo.fly(el).removeClass([
34981 "x-tree-drag-insert-above",
34982 "x-tree-drag-insert-below",
34983 "x-tree-drag-append"]);
34984 this.lastInsertClass = "_noclass";
34988 beforeDragDrop : function(target, e, id){
34989 this.cancelExpand();
34993 afterRepair : function(data){
34994 if(data && Roo.enableFx){
34995 data.node.ui.highlight();
35005 * Ext JS Library 1.1.1
35006 * Copyright(c) 2006-2007, Ext JS, LLC.
35008 * Originally Released Under LGPL - original licence link has changed is not relivant.
35011 * <script type="text/javascript">
35015 if(Roo.dd.DragZone){
35016 Roo.tree.TreeDragZone = function(tree, config){
35017 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35021 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35022 ddGroup : "TreeDD",
35024 onBeforeDrag : function(data, e){
35026 return n && n.draggable && !n.disabled;
35030 onInitDrag : function(e){
35031 var data = this.dragData;
35032 this.tree.getSelectionModel().select(data.node);
35033 this.proxy.update("");
35034 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35035 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35038 getRepairXY : function(e, data){
35039 return data.node.ui.getDDRepairXY();
35042 onEndDrag : function(data, e){
35043 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35048 onValidDrop : function(dd, e, id){
35049 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35053 beforeInvalidDrop : function(e, id){
35054 // this scrolls the original position back into view
35055 var sm = this.tree.getSelectionModel();
35056 sm.clearSelections();
35057 sm.select(this.dragData.node);
35062 * Ext JS Library 1.1.1
35063 * Copyright(c) 2006-2007, Ext JS, LLC.
35065 * Originally Released Under LGPL - original licence link has changed is not relivant.
35068 * <script type="text/javascript">
35071 * @class Roo.tree.TreeEditor
35072 * @extends Roo.Editor
35073 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35074 * as the editor field.
35076 * @param {Object} config (used to be the tree panel.)
35077 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35079 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35080 * @cfg {Roo.form.TextField|Object} field The field configuration
35084 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35087 if (oldconfig) { // old style..
35088 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35091 tree = config.tree;
35092 config.field = config.field || {};
35093 config.field.xtype = 'TextField';
35094 field = Roo.factory(config.field, Roo.form);
35096 config = config || {};
35101 * @event beforenodeedit
35102 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35103 * false from the handler of this event.
35104 * @param {Editor} this
35105 * @param {Roo.tree.Node} node
35107 "beforenodeedit" : true
35111 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35115 tree.on('beforeclick', this.beforeNodeClick, this);
35116 tree.getTreeEl().on('mousedown', this.hide, this);
35117 this.on('complete', this.updateNode, this);
35118 this.on('beforestartedit', this.fitToTree, this);
35119 this.on('startedit', this.bindScroll, this, {delay:10});
35120 this.on('specialkey', this.onSpecialKey, this);
35123 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35125 * @cfg {String} alignment
35126 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35132 * @cfg {Boolean} hideEl
35133 * True to hide the bound element while the editor is displayed (defaults to false)
35137 * @cfg {String} cls
35138 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35140 cls: "x-small-editor x-tree-editor",
35142 * @cfg {Boolean} shim
35143 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35149 * @cfg {Number} maxWidth
35150 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35151 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35152 * scroll and client offsets into account prior to each edit.
35159 fitToTree : function(ed, el){
35160 var td = this.tree.getTreeEl().dom, nd = el.dom;
35161 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35162 td.scrollLeft = nd.offsetLeft;
35166 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35167 this.setSize(w, '');
35169 return this.fireEvent('beforenodeedit', this, this.editNode);
35174 triggerEdit : function(node){
35175 this.completeEdit();
35176 this.editNode = node;
35177 this.startEdit(node.ui.textNode, node.text);
35181 bindScroll : function(){
35182 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35186 beforeNodeClick : function(node, e){
35187 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35188 this.lastClick = new Date();
35189 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35191 this.triggerEdit(node);
35198 updateNode : function(ed, value){
35199 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35200 this.editNode.setText(value);
35204 onHide : function(){
35205 Roo.tree.TreeEditor.superclass.onHide.call(this);
35207 this.editNode.ui.focus();
35212 onSpecialKey : function(field, e){
35213 var k = e.getKey();
35217 }else if(k == e.ENTER && !e.hasModifier()){
35219 this.completeEdit();
35222 });//<Script type="text/javascript">
35225 * Ext JS Library 1.1.1
35226 * Copyright(c) 2006-2007, Ext JS, LLC.
35228 * Originally Released Under LGPL - original licence link has changed is not relivant.
35231 * <script type="text/javascript">
35235 * Not documented??? - probably should be...
35238 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35239 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35241 renderElements : function(n, a, targetNode, bulkRender){
35242 //consel.log("renderElements?");
35243 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35245 var t = n.getOwnerTree();
35246 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35248 var cols = t.columns;
35249 var bw = t.borderWidth;
35251 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35252 var cb = typeof a.checked == "boolean";
35253 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35254 var colcls = 'x-t-' + tid + '-c0';
35256 '<li class="x-tree-node">',
35259 '<div class="x-tree-node-el ', a.cls,'">',
35261 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35264 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35265 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35266 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35267 (a.icon ? ' x-tree-node-inline-icon' : ''),
35268 (a.iconCls ? ' '+a.iconCls : ''),
35269 '" unselectable="on" />',
35270 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35271 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35273 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35274 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35275 '<span unselectable="on" qtip="' + tx + '">',
35279 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35280 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35282 for(var i = 1, len = cols.length; i < len; i++){
35284 colcls = 'x-t-' + tid + '-c' +i;
35285 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35286 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35287 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35293 '<div class="x-clear"></div></div>',
35294 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35297 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35298 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35299 n.nextSibling.ui.getEl(), buf.join(""));
35301 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35303 var el = this.wrap.firstChild;
35305 this.elNode = el.firstChild;
35306 this.ranchor = el.childNodes[1];
35307 this.ctNode = this.wrap.childNodes[1];
35308 var cs = el.firstChild.childNodes;
35309 this.indentNode = cs[0];
35310 this.ecNode = cs[1];
35311 this.iconNode = cs[2];
35314 this.checkbox = cs[3];
35317 this.anchor = cs[index];
35319 this.textNode = cs[index].firstChild;
35321 //el.on("click", this.onClick, this);
35322 //el.on("dblclick", this.onDblClick, this);
35325 // console.log(this);
35327 initEvents : function(){
35328 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35331 var a = this.ranchor;
35333 var el = Roo.get(a);
35335 if(Roo.isOpera){ // opera render bug ignores the CSS
35336 el.setStyle("text-decoration", "none");
35339 el.on("click", this.onClick, this);
35340 el.on("dblclick", this.onDblClick, this);
35341 el.on("contextmenu", this.onContextMenu, this);
35345 /*onSelectedChange : function(state){
35348 this.addClass("x-tree-selected");
35351 this.removeClass("x-tree-selected");
35354 addClass : function(cls){
35356 Roo.fly(this.elRow).addClass(cls);
35362 removeClass : function(cls){
35364 Roo.fly(this.elRow).removeClass(cls);
35370 });//<Script type="text/javascript">
35374 * Ext JS Library 1.1.1
35375 * Copyright(c) 2006-2007, Ext JS, LLC.
35377 * Originally Released Under LGPL - original licence link has changed is not relivant.
35380 * <script type="text/javascript">
35385 * @class Roo.tree.ColumnTree
35386 * @extends Roo.data.TreePanel
35387 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35388 * @cfg {int} borderWidth compined right/left border allowance
35390 * @param {String/HTMLElement/Element} el The container element
35391 * @param {Object} config
35393 Roo.tree.ColumnTree = function(el, config)
35395 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35399 * Fire this event on a container when it resizes
35400 * @param {int} w Width
35401 * @param {int} h Height
35405 this.on('resize', this.onResize, this);
35408 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35412 borderWidth: Roo.isBorderBox ? 0 : 2,
35415 render : function(){
35416 // add the header.....
35418 Roo.tree.ColumnTree.superclass.render.apply(this);
35420 this.el.addClass('x-column-tree');
35422 this.headers = this.el.createChild(
35423 {cls:'x-tree-headers'},this.innerCt.dom);
35425 var cols = this.columns, c;
35426 var totalWidth = 0;
35428 var len = cols.length;
35429 for(var i = 0; i < len; i++){
35431 totalWidth += c.width;
35432 this.headEls.push(this.headers.createChild({
35433 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35435 cls:'x-tree-hd-text',
35438 style:'width:'+(c.width-this.borderWidth)+'px;'
35441 this.headers.createChild({cls:'x-clear'});
35442 // prevent floats from wrapping when clipped
35443 this.headers.setWidth(totalWidth);
35444 //this.innerCt.setWidth(totalWidth);
35445 this.innerCt.setStyle({ overflow: 'auto' });
35446 this.onResize(this.width, this.height);
35450 onResize : function(w,h)
35455 this.innerCt.setWidth(this.width);
35456 this.innerCt.setHeight(this.height-20);
35459 var cols = this.columns, c;
35460 var totalWidth = 0;
35462 var len = cols.length;
35463 for(var i = 0; i < len; i++){
35465 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35466 // it's the expander..
35467 expEl = this.headEls[i];
35470 totalWidth += c.width;
35474 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35476 this.headers.setWidth(w-20);
35485 * Ext JS Library 1.1.1
35486 * Copyright(c) 2006-2007, Ext JS, LLC.
35488 * Originally Released Under LGPL - original licence link has changed is not relivant.
35491 * <script type="text/javascript">
35495 * @class Roo.menu.Menu
35496 * @extends Roo.util.Observable
35497 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35498 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35500 * Creates a new Menu
35501 * @param {Object} config Configuration options
35503 Roo.menu.Menu = function(config){
35504 Roo.apply(this, config);
35505 this.id = this.id || Roo.id();
35508 * @event beforeshow
35509 * Fires before this menu is displayed
35510 * @param {Roo.menu.Menu} this
35514 * @event beforehide
35515 * Fires before this menu is hidden
35516 * @param {Roo.menu.Menu} this
35521 * Fires after this menu is displayed
35522 * @param {Roo.menu.Menu} this
35527 * Fires after this menu is hidden
35528 * @param {Roo.menu.Menu} this
35533 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35534 * @param {Roo.menu.Menu} this
35535 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35536 * @param {Roo.EventObject} e
35541 * Fires when the mouse is hovering over this menu
35542 * @param {Roo.menu.Menu} this
35543 * @param {Roo.EventObject} e
35544 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35549 * Fires when the mouse exits this menu
35550 * @param {Roo.menu.Menu} this
35551 * @param {Roo.EventObject} e
35552 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35557 * Fires when a menu item contained in this menu is clicked
35558 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35559 * @param {Roo.EventObject} e
35563 if (this.registerMenu) {
35564 Roo.menu.MenuMgr.register(this);
35567 var mis = this.items;
35568 this.items = new Roo.util.MixedCollection();
35570 this.add.apply(this, mis);
35574 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35576 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35580 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35581 * for bottom-right shadow (defaults to "sides")
35585 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35586 * this menu (defaults to "tl-tr?")
35588 subMenuAlign : "tl-tr?",
35590 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35591 * relative to its element of origin (defaults to "tl-bl?")
35593 defaultAlign : "tl-bl?",
35595 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35597 allowOtherMenus : false,
35599 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35601 registerMenu : true,
35606 render : function(){
35610 var el = this.el = new Roo.Layer({
35612 shadow:this.shadow,
35614 parentEl: this.parentEl || document.body,
35618 this.keyNav = new Roo.menu.MenuNav(this);
35621 el.addClass("x-menu-plain");
35624 el.addClass(this.cls);
35626 // generic focus element
35627 this.focusEl = el.createChild({
35628 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35630 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35631 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35633 ul.on("mouseover", this.onMouseOver, this);
35634 ul.on("mouseout", this.onMouseOut, this);
35635 this.items.each(function(item){
35640 var li = document.createElement("li");
35641 li.className = "x-menu-list-item";
35642 ul.dom.appendChild(li);
35643 item.render(li, this);
35650 autoWidth : function(){
35651 var el = this.el, ul = this.ul;
35655 var w = this.width;
35658 }else if(Roo.isIE){
35659 el.setWidth(this.minWidth);
35660 var t = el.dom.offsetWidth; // force recalc
35661 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35666 delayAutoWidth : function(){
35669 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35671 this.awTask.delay(20);
35676 findTargetItem : function(e){
35677 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35678 if(t && t.menuItemId){
35679 return this.items.get(t.menuItemId);
35684 onClick : function(e){
35685 Roo.log("menu.onClick");
35686 var t = this.findTargetItem(e);
35691 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35692 if(t == this.activeItem && t.shouldDeactivate(e)){
35693 this.activeItem.deactivate();
35694 delete this.activeItem;
35698 this.setActiveItem(t, true);
35706 this.fireEvent("click", this, t, e);
35710 setActiveItem : function(item, autoExpand){
35711 if(item != this.activeItem){
35712 if(this.activeItem){
35713 this.activeItem.deactivate();
35715 this.activeItem = item;
35716 item.activate(autoExpand);
35717 }else if(autoExpand){
35723 tryActivate : function(start, step){
35724 var items = this.items;
35725 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35726 var item = items.get(i);
35727 if(!item.disabled && item.canActivate){
35728 this.setActiveItem(item, false);
35736 onMouseOver : function(e){
35738 if(t = this.findTargetItem(e)){
35739 if(t.canActivate && !t.disabled){
35740 this.setActiveItem(t, true);
35743 this.fireEvent("mouseover", this, e, t);
35747 onMouseOut : function(e){
35749 if(t = this.findTargetItem(e)){
35750 if(t == this.activeItem && t.shouldDeactivate(e)){
35751 this.activeItem.deactivate();
35752 delete this.activeItem;
35755 this.fireEvent("mouseout", this, e, t);
35759 * Read-only. Returns true if the menu is currently displayed, else false.
35762 isVisible : function(){
35763 return this.el && !this.hidden;
35767 * Displays this menu relative to another element
35768 * @param {String/HTMLElement/Roo.Element} element The element to align to
35769 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35770 * the element (defaults to this.defaultAlign)
35771 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35773 show : function(el, pos, parentMenu){
35774 this.parentMenu = parentMenu;
35778 this.fireEvent("beforeshow", this);
35779 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35783 * Displays this menu at a specific xy position
35784 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35785 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35787 showAt : function(xy, parentMenu, /* private: */_e){
35788 this.parentMenu = parentMenu;
35793 this.fireEvent("beforeshow", this);
35794 xy = this.el.adjustForConstraints(xy);
35798 this.hidden = false;
35800 this.fireEvent("show", this);
35803 focus : function(){
35805 this.doFocus.defer(50, this);
35809 doFocus : function(){
35811 this.focusEl.focus();
35816 * Hides this menu and optionally all parent menus
35817 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35819 hide : function(deep){
35820 if(this.el && this.isVisible()){
35821 this.fireEvent("beforehide", this);
35822 if(this.activeItem){
35823 this.activeItem.deactivate();
35824 this.activeItem = null;
35827 this.hidden = true;
35828 this.fireEvent("hide", this);
35830 if(deep === true && this.parentMenu){
35831 this.parentMenu.hide(true);
35836 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35837 * Any of the following are valid:
35839 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35840 * <li>An HTMLElement object which will be converted to a menu item</li>
35841 * <li>A menu item config object that will be created as a new menu item</li>
35842 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35843 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35848 var menu = new Roo.menu.Menu();
35850 // Create a menu item to add by reference
35851 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35853 // Add a bunch of items at once using different methods.
35854 // Only the last item added will be returned.
35855 var item = menu.add(
35856 menuItem, // add existing item by ref
35857 'Dynamic Item', // new TextItem
35858 '-', // new separator
35859 { text: 'Config Item' } // new item by config
35862 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35863 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35866 var a = arguments, l = a.length, item;
35867 for(var i = 0; i < l; i++){
35869 if ((typeof(el) == "object") && el.xtype && el.xns) {
35870 el = Roo.factory(el, Roo.menu);
35873 if(el.render){ // some kind of Item
35874 item = this.addItem(el);
35875 }else if(typeof el == "string"){ // string
35876 if(el == "separator" || el == "-"){
35877 item = this.addSeparator();
35879 item = this.addText(el);
35881 }else if(el.tagName || el.el){ // element
35882 item = this.addElement(el);
35883 }else if(typeof el == "object"){ // must be menu item config?
35884 item = this.addMenuItem(el);
35891 * Returns this menu's underlying {@link Roo.Element} object
35892 * @return {Roo.Element} The element
35894 getEl : function(){
35902 * Adds a separator bar to the menu
35903 * @return {Roo.menu.Item} The menu item that was added
35905 addSeparator : function(){
35906 return this.addItem(new Roo.menu.Separator());
35910 * Adds an {@link Roo.Element} object to the menu
35911 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35912 * @return {Roo.menu.Item} The menu item that was added
35914 addElement : function(el){
35915 return this.addItem(new Roo.menu.BaseItem(el));
35919 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35920 * @param {Roo.menu.Item} item The menu item to add
35921 * @return {Roo.menu.Item} The menu item that was added
35923 addItem : function(item){
35924 this.items.add(item);
35926 var li = document.createElement("li");
35927 li.className = "x-menu-list-item";
35928 this.ul.dom.appendChild(li);
35929 item.render(li, this);
35930 this.delayAutoWidth();
35936 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35937 * @param {Object} config A MenuItem config object
35938 * @return {Roo.menu.Item} The menu item that was added
35940 addMenuItem : function(config){
35941 if(!(config instanceof Roo.menu.Item)){
35942 if(typeof config.checked == "boolean"){ // must be check menu item config?
35943 config = new Roo.menu.CheckItem(config);
35945 config = new Roo.menu.Item(config);
35948 return this.addItem(config);
35952 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35953 * @param {String} text The text to display in the menu item
35954 * @return {Roo.menu.Item} The menu item that was added
35956 addText : function(text){
35957 return this.addItem(new Roo.menu.TextItem({ text : text }));
35961 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35962 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35963 * @param {Roo.menu.Item} item The menu item to add
35964 * @return {Roo.menu.Item} The menu item that was added
35966 insert : function(index, item){
35967 this.items.insert(index, item);
35969 var li = document.createElement("li");
35970 li.className = "x-menu-list-item";
35971 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35972 item.render(li, this);
35973 this.delayAutoWidth();
35979 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35980 * @param {Roo.menu.Item} item The menu item to remove
35982 remove : function(item){
35983 this.items.removeKey(item.id);
35988 * Removes and destroys all items in the menu
35990 removeAll : function(){
35992 while(f = this.items.first()){
35998 // MenuNav is a private utility class used internally by the Menu
35999 Roo.menu.MenuNav = function(menu){
36000 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36001 this.scope = this.menu = menu;
36004 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36005 doRelay : function(e, h){
36006 var k = e.getKey();
36007 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36008 this.menu.tryActivate(0, 1);
36011 return h.call(this.scope || this, e, this.menu);
36014 up : function(e, m){
36015 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36016 m.tryActivate(m.items.length-1, -1);
36020 down : function(e, m){
36021 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36022 m.tryActivate(0, 1);
36026 right : function(e, m){
36028 m.activeItem.expandMenu(true);
36032 left : function(e, m){
36034 if(m.parentMenu && m.parentMenu.activeItem){
36035 m.parentMenu.activeItem.activate();
36039 enter : function(e, m){
36041 e.stopPropagation();
36042 m.activeItem.onClick(e);
36043 m.fireEvent("click", this, m.activeItem);
36049 * Ext JS Library 1.1.1
36050 * Copyright(c) 2006-2007, Ext JS, LLC.
36052 * Originally Released Under LGPL - original licence link has changed is not relivant.
36055 * <script type="text/javascript">
36059 * @class Roo.menu.MenuMgr
36060 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36063 Roo.menu.MenuMgr = function(){
36064 var menus, active, groups = {}, attached = false, lastShow = new Date();
36066 // private - called when first menu is created
36069 active = new Roo.util.MixedCollection();
36070 Roo.get(document).addKeyListener(27, function(){
36071 if(active.length > 0){
36078 function hideAll(){
36079 if(active && active.length > 0){
36080 var c = active.clone();
36081 c.each(function(m){
36088 function onHide(m){
36090 if(active.length < 1){
36091 Roo.get(document).un("mousedown", onMouseDown);
36097 function onShow(m){
36098 var last = active.last();
36099 lastShow = new Date();
36102 Roo.get(document).on("mousedown", onMouseDown);
36106 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36107 m.parentMenu.activeChild = m;
36108 }else if(last && last.isVisible()){
36109 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36114 function onBeforeHide(m){
36116 m.activeChild.hide();
36118 if(m.autoHideTimer){
36119 clearTimeout(m.autoHideTimer);
36120 delete m.autoHideTimer;
36125 function onBeforeShow(m){
36126 var pm = m.parentMenu;
36127 if(!pm && !m.allowOtherMenus){
36129 }else if(pm && pm.activeChild && active != m){
36130 pm.activeChild.hide();
36135 function onMouseDown(e){
36136 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36142 function onBeforeCheck(mi, state){
36144 var g = groups[mi.group];
36145 for(var i = 0, l = g.length; i < l; i++){
36147 g[i].setChecked(false);
36156 * Hides all menus that are currently visible
36158 hideAll : function(){
36163 register : function(menu){
36167 menus[menu.id] = menu;
36168 menu.on("beforehide", onBeforeHide);
36169 menu.on("hide", onHide);
36170 menu.on("beforeshow", onBeforeShow);
36171 menu.on("show", onShow);
36172 var g = menu.group;
36173 if(g && menu.events["checkchange"]){
36177 groups[g].push(menu);
36178 menu.on("checkchange", onCheck);
36183 * Returns a {@link Roo.menu.Menu} object
36184 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36185 * be used to generate and return a new Menu instance.
36187 get : function(menu){
36188 if(typeof menu == "string"){ // menu id
36189 return menus[menu];
36190 }else if(menu.events){ // menu instance
36192 }else if(typeof menu.length == 'number'){ // array of menu items?
36193 return new Roo.menu.Menu({items:menu});
36194 }else{ // otherwise, must be a config
36195 return new Roo.menu.Menu(menu);
36200 unregister : function(menu){
36201 delete menus[menu.id];
36202 menu.un("beforehide", onBeforeHide);
36203 menu.un("hide", onHide);
36204 menu.un("beforeshow", onBeforeShow);
36205 menu.un("show", onShow);
36206 var g = menu.group;
36207 if(g && menu.events["checkchange"]){
36208 groups[g].remove(menu);
36209 menu.un("checkchange", onCheck);
36214 registerCheckable : function(menuItem){
36215 var g = menuItem.group;
36220 groups[g].push(menuItem);
36221 menuItem.on("beforecheckchange", onBeforeCheck);
36226 unregisterCheckable : function(menuItem){
36227 var g = menuItem.group;
36229 groups[g].remove(menuItem);
36230 menuItem.un("beforecheckchange", onBeforeCheck);
36236 * Ext JS Library 1.1.1
36237 * Copyright(c) 2006-2007, Ext JS, LLC.
36239 * Originally Released Under LGPL - original licence link has changed is not relivant.
36242 * <script type="text/javascript">
36247 * @class Roo.menu.BaseItem
36248 * @extends Roo.Component
36249 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36250 * management and base configuration options shared by all menu components.
36252 * Creates a new BaseItem
36253 * @param {Object} config Configuration options
36255 Roo.menu.BaseItem = function(config){
36256 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36261 * Fires when this item is clicked
36262 * @param {Roo.menu.BaseItem} this
36263 * @param {Roo.EventObject} e
36268 * Fires when this item is activated
36269 * @param {Roo.menu.BaseItem} this
36273 * @event deactivate
36274 * Fires when this item is deactivated
36275 * @param {Roo.menu.BaseItem} this
36281 this.on("click", this.handler, this.scope, true);
36285 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36287 * @cfg {Function} handler
36288 * A function that will handle the click event of this menu item (defaults to undefined)
36291 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36293 canActivate : false,
36296 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36301 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36303 activeClass : "x-menu-item-active",
36305 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36307 hideOnClick : true,
36309 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36314 ctype: "Roo.menu.BaseItem",
36317 actionMode : "container",
36320 render : function(container, parentMenu){
36321 this.parentMenu = parentMenu;
36322 Roo.menu.BaseItem.superclass.render.call(this, container);
36323 this.container.menuItemId = this.id;
36327 onRender : function(container, position){
36328 this.el = Roo.get(this.el);
36329 container.dom.appendChild(this.el.dom);
36333 onClick : function(e){
36334 if(!this.disabled && this.fireEvent("click", this, e) !== false
36335 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36336 this.handleClick(e);
36343 activate : function(){
36347 var li = this.container;
36348 li.addClass(this.activeClass);
36349 this.region = li.getRegion().adjust(2, 2, -2, -2);
36350 this.fireEvent("activate", this);
36355 deactivate : function(){
36356 this.container.removeClass(this.activeClass);
36357 this.fireEvent("deactivate", this);
36361 shouldDeactivate : function(e){
36362 return !this.region || !this.region.contains(e.getPoint());
36366 handleClick : function(e){
36367 if(this.hideOnClick){
36368 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36373 expandMenu : function(autoActivate){
36378 hideMenu : function(){
36383 * Ext JS Library 1.1.1
36384 * Copyright(c) 2006-2007, Ext JS, LLC.
36386 * Originally Released Under LGPL - original licence link has changed is not relivant.
36389 * <script type="text/javascript">
36393 * @class Roo.menu.Adapter
36394 * @extends Roo.menu.BaseItem
36395 * 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.
36396 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36398 * Creates a new Adapter
36399 * @param {Object} config Configuration options
36401 Roo.menu.Adapter = function(component, config){
36402 Roo.menu.Adapter.superclass.constructor.call(this, config);
36403 this.component = component;
36405 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36407 canActivate : true,
36410 onRender : function(container, position){
36411 this.component.render(container);
36412 this.el = this.component.getEl();
36416 activate : function(){
36420 this.component.focus();
36421 this.fireEvent("activate", this);
36426 deactivate : function(){
36427 this.fireEvent("deactivate", this);
36431 disable : function(){
36432 this.component.disable();
36433 Roo.menu.Adapter.superclass.disable.call(this);
36437 enable : function(){
36438 this.component.enable();
36439 Roo.menu.Adapter.superclass.enable.call(this);
36443 * Ext JS Library 1.1.1
36444 * Copyright(c) 2006-2007, Ext JS, LLC.
36446 * Originally Released Under LGPL - original licence link has changed is not relivant.
36449 * <script type="text/javascript">
36453 * @class Roo.menu.TextItem
36454 * @extends Roo.menu.BaseItem
36455 * Adds a static text string to a menu, usually used as either a heading or group separator.
36456 * Note: old style constructor with text is still supported.
36459 * Creates a new TextItem
36460 * @param {Object} cfg Configuration
36462 Roo.menu.TextItem = function(cfg){
36463 if (typeof(cfg) == 'string') {
36466 Roo.apply(this,cfg);
36469 Roo.menu.TextItem.superclass.constructor.call(this);
36472 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36474 * @cfg {Boolean} text Text to show on item.
36479 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36481 hideOnClick : false,
36483 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36485 itemCls : "x-menu-text",
36488 onRender : function(){
36489 var s = document.createElement("span");
36490 s.className = this.itemCls;
36491 s.innerHTML = this.text;
36493 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36497 * Ext JS Library 1.1.1
36498 * Copyright(c) 2006-2007, Ext JS, LLC.
36500 * Originally Released Under LGPL - original licence link has changed is not relivant.
36503 * <script type="text/javascript">
36507 * @class Roo.menu.Separator
36508 * @extends Roo.menu.BaseItem
36509 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36510 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36512 * @param {Object} config Configuration options
36514 Roo.menu.Separator = function(config){
36515 Roo.menu.Separator.superclass.constructor.call(this, config);
36518 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36520 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36522 itemCls : "x-menu-sep",
36524 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36526 hideOnClick : false,
36529 onRender : function(li){
36530 var s = document.createElement("span");
36531 s.className = this.itemCls;
36532 s.innerHTML = " ";
36534 li.addClass("x-menu-sep-li");
36535 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36539 * Ext JS Library 1.1.1
36540 * Copyright(c) 2006-2007, Ext JS, LLC.
36542 * Originally Released Under LGPL - original licence link has changed is not relivant.
36545 * <script type="text/javascript">
36548 * @class Roo.menu.Item
36549 * @extends Roo.menu.BaseItem
36550 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36551 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36552 * activation and click handling.
36554 * Creates a new Item
36555 * @param {Object} config Configuration options
36557 Roo.menu.Item = function(config){
36558 Roo.menu.Item.superclass.constructor.call(this, config);
36560 this.menu = Roo.menu.MenuMgr.get(this.menu);
36563 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36566 * @cfg {String} text
36567 * The text to show on the menu item.
36571 * @cfg {String} HTML to render in menu
36572 * The text to show on the menu item (HTML version).
36576 * @cfg {String} icon
36577 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36581 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36583 itemCls : "x-menu-item",
36585 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36587 canActivate : true,
36589 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36592 // doc'd in BaseItem
36596 ctype: "Roo.menu.Item",
36599 onRender : function(container, position){
36600 var el = document.createElement("a");
36601 el.hideFocus = true;
36602 el.unselectable = "on";
36603 el.href = this.href || "#";
36604 if(this.hrefTarget){
36605 el.target = this.hrefTarget;
36607 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36609 var html = this.html.length ? this.html : String.format('{0}',this.text);
36611 el.innerHTML = String.format(
36612 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36613 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36615 Roo.menu.Item.superclass.onRender.call(this, container, position);
36619 * Sets the text to display in this menu item
36620 * @param {String} text The text to display
36621 * @param {Boolean} isHTML true to indicate text is pure html.
36623 setText : function(text, isHTML){
36631 var html = this.html.length ? this.html : String.format('{0}',this.text);
36633 this.el.update(String.format(
36634 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36635 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36636 this.parentMenu.autoWidth();
36641 handleClick : function(e){
36642 if(!this.href){ // if no link defined, stop the event automatically
36645 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36649 activate : function(autoExpand){
36650 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36660 shouldDeactivate : function(e){
36661 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36662 if(this.menu && this.menu.isVisible()){
36663 return !this.menu.getEl().getRegion().contains(e.getPoint());
36671 deactivate : function(){
36672 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36677 expandMenu : function(autoActivate){
36678 if(!this.disabled && this.menu){
36679 clearTimeout(this.hideTimer);
36680 delete this.hideTimer;
36681 if(!this.menu.isVisible() && !this.showTimer){
36682 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36683 }else if (this.menu.isVisible() && autoActivate){
36684 this.menu.tryActivate(0, 1);
36690 deferExpand : function(autoActivate){
36691 delete this.showTimer;
36692 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36694 this.menu.tryActivate(0, 1);
36699 hideMenu : function(){
36700 clearTimeout(this.showTimer);
36701 delete this.showTimer;
36702 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36703 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36708 deferHide : function(){
36709 delete this.hideTimer;
36714 * Ext JS Library 1.1.1
36715 * Copyright(c) 2006-2007, Ext JS, LLC.
36717 * Originally Released Under LGPL - original licence link has changed is not relivant.
36720 * <script type="text/javascript">
36724 * @class Roo.menu.CheckItem
36725 * @extends Roo.menu.Item
36726 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36728 * Creates a new CheckItem
36729 * @param {Object} config Configuration options
36731 Roo.menu.CheckItem = function(config){
36732 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36735 * @event beforecheckchange
36736 * Fires before the checked value is set, providing an opportunity to cancel if needed
36737 * @param {Roo.menu.CheckItem} this
36738 * @param {Boolean} checked The new checked value that will be set
36740 "beforecheckchange" : true,
36742 * @event checkchange
36743 * Fires after the checked value has been set
36744 * @param {Roo.menu.CheckItem} this
36745 * @param {Boolean} checked The checked value that was set
36747 "checkchange" : true
36749 if(this.checkHandler){
36750 this.on('checkchange', this.checkHandler, this.scope);
36753 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36755 * @cfg {String} group
36756 * All check items with the same group name will automatically be grouped into a single-select
36757 * radio button group (defaults to '')
36760 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36762 itemCls : "x-menu-item x-menu-check-item",
36764 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36766 groupClass : "x-menu-group-item",
36769 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36770 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36771 * initialized with checked = true will be rendered as checked.
36776 ctype: "Roo.menu.CheckItem",
36779 onRender : function(c){
36780 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36782 this.el.addClass(this.groupClass);
36784 Roo.menu.MenuMgr.registerCheckable(this);
36786 this.checked = false;
36787 this.setChecked(true, true);
36792 destroy : function(){
36794 Roo.menu.MenuMgr.unregisterCheckable(this);
36796 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36800 * Set the checked state of this item
36801 * @param {Boolean} checked The new checked value
36802 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36804 setChecked : function(state, suppressEvent){
36805 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36806 if(this.container){
36807 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36809 this.checked = state;
36810 if(suppressEvent !== true){
36811 this.fireEvent("checkchange", this, state);
36817 handleClick : function(e){
36818 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36819 this.setChecked(!this.checked);
36821 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36825 * Ext JS Library 1.1.1
36826 * Copyright(c) 2006-2007, Ext JS, LLC.
36828 * Originally Released Under LGPL - original licence link has changed is not relivant.
36831 * <script type="text/javascript">
36835 * @class Roo.menu.DateItem
36836 * @extends Roo.menu.Adapter
36837 * A menu item that wraps the {@link Roo.DatPicker} component.
36839 * Creates a new DateItem
36840 * @param {Object} config Configuration options
36842 Roo.menu.DateItem = function(config){
36843 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36844 /** The Roo.DatePicker object @type Roo.DatePicker */
36845 this.picker = this.component;
36846 this.addEvents({select: true});
36848 this.picker.on("render", function(picker){
36849 picker.getEl().swallowEvent("click");
36850 picker.container.addClass("x-menu-date-item");
36853 this.picker.on("select", this.onSelect, this);
36856 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36858 onSelect : function(picker, date){
36859 this.fireEvent("select", this, date, picker);
36860 Roo.menu.DateItem.superclass.handleClick.call(this);
36864 * Ext JS Library 1.1.1
36865 * Copyright(c) 2006-2007, Ext JS, LLC.
36867 * Originally Released Under LGPL - original licence link has changed is not relivant.
36870 * <script type="text/javascript">
36874 * @class Roo.menu.ColorItem
36875 * @extends Roo.menu.Adapter
36876 * A menu item that wraps the {@link Roo.ColorPalette} component.
36878 * Creates a new ColorItem
36879 * @param {Object} config Configuration options
36881 Roo.menu.ColorItem = function(config){
36882 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36883 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36884 this.palette = this.component;
36885 this.relayEvents(this.palette, ["select"]);
36886 if(this.selectHandler){
36887 this.on('select', this.selectHandler, this.scope);
36890 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36892 * Ext JS Library 1.1.1
36893 * Copyright(c) 2006-2007, Ext JS, LLC.
36895 * Originally Released Under LGPL - original licence link has changed is not relivant.
36898 * <script type="text/javascript">
36903 * @class Roo.menu.DateMenu
36904 * @extends Roo.menu.Menu
36905 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36907 * Creates a new DateMenu
36908 * @param {Object} config Configuration options
36910 Roo.menu.DateMenu = function(config){
36911 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36913 var di = new Roo.menu.DateItem(config);
36916 * The {@link Roo.DatePicker} instance for this DateMenu
36919 this.picker = di.picker;
36922 * @param {DatePicker} picker
36923 * @param {Date} date
36925 this.relayEvents(di, ["select"]);
36926 this.on('beforeshow', function(){
36928 this.picker.hideMonthPicker(false);
36932 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36936 * Ext JS Library 1.1.1
36937 * Copyright(c) 2006-2007, Ext JS, LLC.
36939 * Originally Released Under LGPL - original licence link has changed is not relivant.
36942 * <script type="text/javascript">
36947 * @class Roo.menu.ColorMenu
36948 * @extends Roo.menu.Menu
36949 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36951 * Creates a new ColorMenu
36952 * @param {Object} config Configuration options
36954 Roo.menu.ColorMenu = function(config){
36955 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36957 var ci = new Roo.menu.ColorItem(config);
36960 * The {@link Roo.ColorPalette} instance for this ColorMenu
36961 * @type ColorPalette
36963 this.palette = ci.palette;
36966 * @param {ColorPalette} palette
36967 * @param {String} color
36969 this.relayEvents(ci, ["select"]);
36971 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36973 * Ext JS Library 1.1.1
36974 * Copyright(c) 2006-2007, Ext JS, LLC.
36976 * Originally Released Under LGPL - original licence link has changed is not relivant.
36979 * <script type="text/javascript">
36983 * @class Roo.form.Field
36984 * @extends Roo.BoxComponent
36985 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36987 * Creates a new Field
36988 * @param {Object} config Configuration options
36990 Roo.form.Field = function(config){
36991 Roo.form.Field.superclass.constructor.call(this, config);
36994 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36996 * @cfg {String} fieldLabel Label to use when rendering a form.
36999 * @cfg {String} qtip Mouse over tip
37003 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37005 invalidClass : "x-form-invalid",
37007 * @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")
37009 invalidText : "The value in this field is invalid",
37011 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37013 focusClass : "x-form-focus",
37015 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37016 automatic validation (defaults to "keyup").
37018 validationEvent : "keyup",
37020 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37022 validateOnBlur : true,
37024 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37026 validationDelay : 250,
37028 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37029 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37031 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
37033 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37035 fieldClass : "x-form-field",
37037 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37040 ----------- ----------------------------------------------------------------------
37041 qtip Display a quick tip when the user hovers over the field
37042 title Display a default browser title attribute popup
37043 under Add a block div beneath the field containing the error text
37044 side Add an error icon to the right of the field with a popup on hover
37045 [element id] Add the error text directly to the innerHTML of the specified element
37048 msgTarget : 'qtip',
37050 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37055 * @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.
37060 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37065 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37067 inputType : undefined,
37070 * @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).
37072 tabIndex : undefined,
37075 isFormField : true,
37080 * @property {Roo.Element} fieldEl
37081 * Element Containing the rendered Field (with label etc.)
37084 * @cfg {Mixed} value A value to initialize this field with.
37089 * @cfg {String} name The field's HTML name attribute.
37092 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37096 initComponent : function(){
37097 Roo.form.Field.superclass.initComponent.call(this);
37101 * Fires when this field receives input focus.
37102 * @param {Roo.form.Field} this
37107 * Fires when this field loses input focus.
37108 * @param {Roo.form.Field} this
37112 * @event specialkey
37113 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37114 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37115 * @param {Roo.form.Field} this
37116 * @param {Roo.EventObject} e The event object
37121 * Fires just before the field blurs if the field value has changed.
37122 * @param {Roo.form.Field} this
37123 * @param {Mixed} newValue The new value
37124 * @param {Mixed} oldValue The original value
37129 * Fires after the field has been marked as invalid.
37130 * @param {Roo.form.Field} this
37131 * @param {String} msg The validation message
37136 * Fires after the field has been validated with no errors.
37137 * @param {Roo.form.Field} this
37142 * Fires after the key up
37143 * @param {Roo.form.Field} this
37144 * @param {Roo.EventObject} e The event Object
37151 * Returns the name attribute of the field if available
37152 * @return {String} name The field name
37154 getName: function(){
37155 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37159 onRender : function(ct, position){
37160 Roo.form.Field.superclass.onRender.call(this, ct, position);
37162 var cfg = this.getAutoCreate();
37164 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37166 if (!cfg.name.length) {
37169 if(this.inputType){
37170 cfg.type = this.inputType;
37172 this.el = ct.createChild(cfg, position);
37174 var type = this.el.dom.type;
37176 if(type == 'password'){
37179 this.el.addClass('x-form-'+type);
37182 this.el.dom.readOnly = true;
37184 if(this.tabIndex !== undefined){
37185 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37188 this.el.addClass([this.fieldClass, this.cls]);
37193 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37194 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37195 * @return {Roo.form.Field} this
37197 applyTo : function(target){
37198 this.allowDomMove = false;
37199 this.el = Roo.get(target);
37200 this.render(this.el.dom.parentNode);
37205 initValue : function(){
37206 if(this.value !== undefined){
37207 this.setValue(this.value);
37208 }else if(this.el.dom.value.length > 0){
37209 this.setValue(this.el.dom.value);
37214 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37216 isDirty : function() {
37217 if(this.disabled) {
37220 return String(this.getValue()) !== String(this.originalValue);
37224 afterRender : function(){
37225 Roo.form.Field.superclass.afterRender.call(this);
37230 fireKey : function(e){
37231 //Roo.log('field ' + e.getKey());
37232 if(e.isNavKeyPress()){
37233 this.fireEvent("specialkey", this, e);
37238 * Resets the current field value to the originally loaded value and clears any validation messages
37240 reset : function(){
37241 this.setValue(this.resetValue);
37242 this.clearInvalid();
37246 initEvents : function(){
37247 // safari killled keypress - so keydown is now used..
37248 this.el.on("keydown" , this.fireKey, this);
37249 this.el.on("focus", this.onFocus, this);
37250 this.el.on("blur", this.onBlur, this);
37251 this.el.relayEvent('keyup', this);
37253 // reference to original value for reset
37254 this.originalValue = this.getValue();
37255 this.resetValue = this.getValue();
37259 onFocus : function(){
37260 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37261 this.el.addClass(this.focusClass);
37263 if(!this.hasFocus){
37264 this.hasFocus = true;
37265 this.startValue = this.getValue();
37266 this.fireEvent("focus", this);
37270 beforeBlur : Roo.emptyFn,
37273 onBlur : function(){
37275 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37276 this.el.removeClass(this.focusClass);
37278 this.hasFocus = false;
37279 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37282 var v = this.getValue();
37283 if(String(v) !== String(this.startValue)){
37284 this.fireEvent('change', this, v, this.startValue);
37286 this.fireEvent("blur", this);
37290 * Returns whether or not the field value is currently valid
37291 * @param {Boolean} preventMark True to disable marking the field invalid
37292 * @return {Boolean} True if the value is valid, else false
37294 isValid : function(preventMark){
37298 var restore = this.preventMark;
37299 this.preventMark = preventMark === true;
37300 var v = this.validateValue(this.processValue(this.getRawValue()));
37301 this.preventMark = restore;
37306 * Validates the field value
37307 * @return {Boolean} True if the value is valid, else false
37309 validate : function(){
37310 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37311 this.clearInvalid();
37317 processValue : function(value){
37322 // Subclasses should provide the validation implementation by overriding this
37323 validateValue : function(value){
37328 * Mark this field as invalid
37329 * @param {String} msg The validation message
37331 markInvalid : function(msg){
37332 if(!this.rendered || this.preventMark){ // not rendered
37336 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37338 obj.el.addClass(this.invalidClass);
37339 msg = msg || this.invalidText;
37340 switch(this.msgTarget){
37342 obj.el.dom.qtip = msg;
37343 obj.el.dom.qclass = 'x-form-invalid-tip';
37344 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37345 Roo.QuickTips.enable();
37349 this.el.dom.title = msg;
37353 var elp = this.el.findParent('.x-form-element', 5, true);
37354 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37355 this.errorEl.setWidth(elp.getWidth(true)-20);
37357 this.errorEl.update(msg);
37358 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37361 if(!this.errorIcon){
37362 var elp = this.el.findParent('.x-form-element', 5, true);
37363 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37365 this.alignErrorIcon();
37366 this.errorIcon.dom.qtip = msg;
37367 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37368 this.errorIcon.show();
37369 this.on('resize', this.alignErrorIcon, this);
37372 var t = Roo.getDom(this.msgTarget);
37374 t.style.display = this.msgDisplay;
37377 this.fireEvent('invalid', this, msg);
37381 alignErrorIcon : function(){
37382 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37386 * Clear any invalid styles/messages for this field
37388 clearInvalid : function(){
37389 if(!this.rendered || this.preventMark){ // not rendered
37392 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37394 obj.el.removeClass(this.invalidClass);
37395 switch(this.msgTarget){
37397 obj.el.dom.qtip = '';
37400 this.el.dom.title = '';
37404 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37408 if(this.errorIcon){
37409 this.errorIcon.dom.qtip = '';
37410 this.errorIcon.hide();
37411 this.un('resize', this.alignErrorIcon, this);
37415 var t = Roo.getDom(this.msgTarget);
37417 t.style.display = 'none';
37420 this.fireEvent('valid', this);
37424 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37425 * @return {Mixed} value The field value
37427 getRawValue : function(){
37428 var v = this.el.getValue();
37434 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37435 * @return {Mixed} value The field value
37437 getValue : function(){
37438 var v = this.el.getValue();
37444 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37445 * @param {Mixed} value The value to set
37447 setRawValue : function(v){
37448 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37452 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37453 * @param {Mixed} value The value to set
37455 setValue : function(v){
37458 this.el.dom.value = (v === null || v === undefined ? '' : v);
37463 adjustSize : function(w, h){
37464 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37465 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37469 adjustWidth : function(tag, w){
37470 tag = tag.toLowerCase();
37471 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37472 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37473 if(tag == 'input'){
37476 if(tag == 'textarea'){
37479 }else if(Roo.isOpera){
37480 if(tag == 'input'){
37483 if(tag == 'textarea'){
37493 // anything other than normal should be considered experimental
37494 Roo.form.Field.msgFx = {
37496 show: function(msgEl, f){
37497 msgEl.setDisplayed('block');
37500 hide : function(msgEl, f){
37501 msgEl.setDisplayed(false).update('');
37506 show: function(msgEl, f){
37507 msgEl.slideIn('t', {stopFx:true});
37510 hide : function(msgEl, f){
37511 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37516 show: function(msgEl, f){
37517 msgEl.fixDisplay();
37518 msgEl.alignTo(f.el, 'tl-tr');
37519 msgEl.slideIn('l', {stopFx:true});
37522 hide : function(msgEl, f){
37523 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37528 * Ext JS Library 1.1.1
37529 * Copyright(c) 2006-2007, Ext JS, LLC.
37531 * Originally Released Under LGPL - original licence link has changed is not relivant.
37534 * <script type="text/javascript">
37539 * @class Roo.form.TextField
37540 * @extends Roo.form.Field
37541 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37542 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37544 * Creates a new TextField
37545 * @param {Object} config Configuration options
37547 Roo.form.TextField = function(config){
37548 Roo.form.TextField.superclass.constructor.call(this, config);
37552 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37553 * according to the default logic, but this event provides a hook for the developer to apply additional
37554 * logic at runtime to resize the field if needed.
37555 * @param {Roo.form.Field} this This text field
37556 * @param {Number} width The new field width
37562 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37564 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37568 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37572 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37576 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37580 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37584 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37586 disableKeyFilter : false,
37588 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37592 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37596 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37598 maxLength : Number.MAX_VALUE,
37600 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37602 minLengthText : "The minimum length for this field is {0}",
37604 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37606 maxLengthText : "The maximum length for this field is {0}",
37608 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37610 selectOnFocus : false,
37612 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37614 blankText : "This field is required",
37616 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37617 * If available, this function will be called only after the basic validators all return true, and will be passed the
37618 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37622 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37623 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37624 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37628 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37632 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37638 initEvents : function()
37640 if (this.emptyText) {
37641 this.el.attr('placeholder', this.emptyText);
37644 Roo.form.TextField.superclass.initEvents.call(this);
37645 if(this.validationEvent == 'keyup'){
37646 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37647 this.el.on('keyup', this.filterValidation, this);
37649 else if(this.validationEvent !== false){
37650 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37653 if(this.selectOnFocus){
37654 this.on("focus", this.preFocus, this);
37657 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37658 this.el.on("keypress", this.filterKeys, this);
37661 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37662 this.el.on("click", this.autoSize, this);
37664 if(this.el.is('input[type=password]') && Roo.isSafari){
37665 this.el.on('keydown', this.SafariOnKeyDown, this);
37669 processValue : function(value){
37670 if(this.stripCharsRe){
37671 var newValue = value.replace(this.stripCharsRe, '');
37672 if(newValue !== value){
37673 this.setRawValue(newValue);
37680 filterValidation : function(e){
37681 if(!e.isNavKeyPress()){
37682 this.validationTask.delay(this.validationDelay);
37687 onKeyUp : function(e){
37688 if(!e.isNavKeyPress()){
37694 * Resets the current field value to the originally-loaded value and clears any validation messages.
37697 reset : function(){
37698 Roo.form.TextField.superclass.reset.call(this);
37704 preFocus : function(){
37706 if(this.selectOnFocus){
37707 this.el.dom.select();
37713 filterKeys : function(e){
37714 var k = e.getKey();
37715 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37718 var c = e.getCharCode(), cc = String.fromCharCode(c);
37719 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37722 if(!this.maskRe.test(cc)){
37727 setValue : function(v){
37729 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37735 * Validates a value according to the field's validation rules and marks the field as invalid
37736 * if the validation fails
37737 * @param {Mixed} value The value to validate
37738 * @return {Boolean} True if the value is valid, else false
37740 validateValue : function(value){
37741 if(value.length < 1) { // if it's blank
37742 if(this.allowBlank){
37743 this.clearInvalid();
37746 this.markInvalid(this.blankText);
37750 if(value.length < this.minLength){
37751 this.markInvalid(String.format(this.minLengthText, this.minLength));
37754 if(value.length > this.maxLength){
37755 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37759 var vt = Roo.form.VTypes;
37760 if(!vt[this.vtype](value, this)){
37761 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37765 if(typeof this.validator == "function"){
37766 var msg = this.validator(value);
37768 this.markInvalid(msg);
37772 if(this.regex && !this.regex.test(value)){
37773 this.markInvalid(this.regexText);
37780 * Selects text in this field
37781 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37782 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37784 selectText : function(start, end){
37785 var v = this.getRawValue();
37787 start = start === undefined ? 0 : start;
37788 end = end === undefined ? v.length : end;
37789 var d = this.el.dom;
37790 if(d.setSelectionRange){
37791 d.setSelectionRange(start, end);
37792 }else if(d.createTextRange){
37793 var range = d.createTextRange();
37794 range.moveStart("character", start);
37795 range.moveEnd("character", v.length-end);
37802 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37803 * This only takes effect if grow = true, and fires the autosize event.
37805 autoSize : function(){
37806 if(!this.grow || !this.rendered){
37810 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37813 var v = el.dom.value;
37814 var d = document.createElement('div');
37815 d.appendChild(document.createTextNode(v));
37819 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37820 this.el.setWidth(w);
37821 this.fireEvent("autosize", this, w);
37825 SafariOnKeyDown : function(event)
37827 // this is a workaround for a password hang bug on chrome/ webkit.
37829 var isSelectAll = false;
37831 if(this.el.dom.selectionEnd > 0){
37832 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37834 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37835 event.preventDefault();
37840 if(isSelectAll){ // backspace and delete key
37842 event.preventDefault();
37843 // this is very hacky as keydown always get's upper case.
37845 var cc = String.fromCharCode(event.getCharCode());
37846 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37854 * Ext JS Library 1.1.1
37855 * Copyright(c) 2006-2007, Ext JS, LLC.
37857 * Originally Released Under LGPL - original licence link has changed is not relivant.
37860 * <script type="text/javascript">
37864 * @class Roo.form.Hidden
37865 * @extends Roo.form.TextField
37866 * Simple Hidden element used on forms
37868 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37871 * Creates a new Hidden form element.
37872 * @param {Object} config Configuration options
37877 // easy hidden field...
37878 Roo.form.Hidden = function(config){
37879 Roo.form.Hidden.superclass.constructor.call(this, config);
37882 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37884 inputType: 'hidden',
37887 labelSeparator: '',
37889 itemCls : 'x-form-item-display-none'
37897 * Ext JS Library 1.1.1
37898 * Copyright(c) 2006-2007, Ext JS, LLC.
37900 * Originally Released Under LGPL - original licence link has changed is not relivant.
37903 * <script type="text/javascript">
37907 * @class Roo.form.TriggerField
37908 * @extends Roo.form.TextField
37909 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37910 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37911 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37912 * for which you can provide a custom implementation. For example:
37914 var trigger = new Roo.form.TriggerField();
37915 trigger.onTriggerClick = myTriggerFn;
37916 trigger.applyTo('my-field');
37919 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37920 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37921 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37922 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37924 * Create a new TriggerField.
37925 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37926 * to the base TextField)
37928 Roo.form.TriggerField = function(config){
37929 this.mimicing = false;
37930 Roo.form.TriggerField.superclass.constructor.call(this, config);
37933 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37935 * @cfg {String} triggerClass A CSS class to apply to the trigger
37938 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37939 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37941 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37943 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37947 /** @cfg {Boolean} grow @hide */
37948 /** @cfg {Number} growMin @hide */
37949 /** @cfg {Number} growMax @hide */
37955 autoSize: Roo.emptyFn,
37959 deferHeight : true,
37962 actionMode : 'wrap',
37964 onResize : function(w, h){
37965 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37966 if(typeof w == 'number'){
37967 var x = w - this.trigger.getWidth();
37968 this.el.setWidth(this.adjustWidth('input', x));
37969 this.trigger.setStyle('left', x+'px');
37974 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37977 getResizeEl : function(){
37982 getPositionEl : function(){
37987 alignErrorIcon : function(){
37988 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37992 onRender : function(ct, position){
37993 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37994 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37995 this.trigger = this.wrap.createChild(this.triggerConfig ||
37996 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37997 if(this.hideTrigger){
37998 this.trigger.setDisplayed(false);
38000 this.initTrigger();
38002 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38007 initTrigger : function(){
38008 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38009 this.trigger.addClassOnOver('x-form-trigger-over');
38010 this.trigger.addClassOnClick('x-form-trigger-click');
38014 onDestroy : function(){
38016 this.trigger.removeAllListeners();
38017 this.trigger.remove();
38020 this.wrap.remove();
38022 Roo.form.TriggerField.superclass.onDestroy.call(this);
38026 onFocus : function(){
38027 Roo.form.TriggerField.superclass.onFocus.call(this);
38028 if(!this.mimicing){
38029 this.wrap.addClass('x-trigger-wrap-focus');
38030 this.mimicing = true;
38031 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38032 if(this.monitorTab){
38033 this.el.on("keydown", this.checkTab, this);
38039 checkTab : function(e){
38040 if(e.getKey() == e.TAB){
38041 this.triggerBlur();
38046 onBlur : function(){
38051 mimicBlur : function(e, t){
38052 if(!this.wrap.contains(t) && this.validateBlur()){
38053 this.triggerBlur();
38058 triggerBlur : function(){
38059 this.mimicing = false;
38060 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38061 if(this.monitorTab){
38062 this.el.un("keydown", this.checkTab, this);
38064 this.wrap.removeClass('x-trigger-wrap-focus');
38065 Roo.form.TriggerField.superclass.onBlur.call(this);
38069 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38070 validateBlur : function(e, t){
38075 onDisable : function(){
38076 Roo.form.TriggerField.superclass.onDisable.call(this);
38078 this.wrap.addClass('x-item-disabled');
38083 onEnable : function(){
38084 Roo.form.TriggerField.superclass.onEnable.call(this);
38086 this.wrap.removeClass('x-item-disabled');
38091 onShow : function(){
38092 var ae = this.getActionEl();
38095 ae.dom.style.display = '';
38096 ae.dom.style.visibility = 'visible';
38102 onHide : function(){
38103 var ae = this.getActionEl();
38104 ae.dom.style.display = 'none';
38108 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38109 * by an implementing function.
38111 * @param {EventObject} e
38113 onTriggerClick : Roo.emptyFn
38116 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38117 // to be extended by an implementing class. For an example of implementing this class, see the custom
38118 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38119 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38120 initComponent : function(){
38121 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38123 this.triggerConfig = {
38124 tag:'span', cls:'x-form-twin-triggers', cn:[
38125 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38126 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38130 getTrigger : function(index){
38131 return this.triggers[index];
38134 initTrigger : function(){
38135 var ts = this.trigger.select('.x-form-trigger', true);
38136 this.wrap.setStyle('overflow', 'hidden');
38137 var triggerField = this;
38138 ts.each(function(t, all, index){
38139 t.hide = function(){
38140 var w = triggerField.wrap.getWidth();
38141 this.dom.style.display = 'none';
38142 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38144 t.show = function(){
38145 var w = triggerField.wrap.getWidth();
38146 this.dom.style.display = '';
38147 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38149 var triggerIndex = 'Trigger'+(index+1);
38151 if(this['hide'+triggerIndex]){
38152 t.dom.style.display = 'none';
38154 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38155 t.addClassOnOver('x-form-trigger-over');
38156 t.addClassOnClick('x-form-trigger-click');
38158 this.triggers = ts.elements;
38161 onTrigger1Click : Roo.emptyFn,
38162 onTrigger2Click : Roo.emptyFn
38165 * Ext JS Library 1.1.1
38166 * Copyright(c) 2006-2007, Ext JS, LLC.
38168 * Originally Released Under LGPL - original licence link has changed is not relivant.
38171 * <script type="text/javascript">
38175 * @class Roo.form.TextArea
38176 * @extends Roo.form.TextField
38177 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38178 * support for auto-sizing.
38180 * Creates a new TextArea
38181 * @param {Object} config Configuration options
38183 Roo.form.TextArea = function(config){
38184 Roo.form.TextArea.superclass.constructor.call(this, config);
38185 // these are provided exchanges for backwards compat
38186 // minHeight/maxHeight were replaced by growMin/growMax to be
38187 // compatible with TextField growing config values
38188 if(this.minHeight !== undefined){
38189 this.growMin = this.minHeight;
38191 if(this.maxHeight !== undefined){
38192 this.growMax = this.maxHeight;
38196 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38198 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38202 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38206 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38207 * in the field (equivalent to setting overflow: hidden, defaults to false)
38209 preventScrollbars: false,
38211 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38212 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38216 onRender : function(ct, position){
38218 this.defaultAutoCreate = {
38220 style:"width:300px;height:60px;",
38221 autocomplete: "off"
38224 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38226 this.textSizeEl = Roo.DomHelper.append(document.body, {
38227 tag: "pre", cls: "x-form-grow-sizer"
38229 if(this.preventScrollbars){
38230 this.el.setStyle("overflow", "hidden");
38232 this.el.setHeight(this.growMin);
38236 onDestroy : function(){
38237 if(this.textSizeEl){
38238 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38240 Roo.form.TextArea.superclass.onDestroy.call(this);
38244 onKeyUp : function(e){
38245 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38251 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38252 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38254 autoSize : function(){
38255 if(!this.grow || !this.textSizeEl){
38259 var v = el.dom.value;
38260 var ts = this.textSizeEl;
38263 ts.appendChild(document.createTextNode(v));
38266 Roo.fly(ts).setWidth(this.el.getWidth());
38268 v = "  ";
38271 v = v.replace(/\n/g, '<p> </p>');
38273 v += " \n ";
38276 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38277 if(h != this.lastHeight){
38278 this.lastHeight = h;
38279 this.el.setHeight(h);
38280 this.fireEvent("autosize", this, h);
38285 * Ext JS Library 1.1.1
38286 * Copyright(c) 2006-2007, Ext JS, LLC.
38288 * Originally Released Under LGPL - original licence link has changed is not relivant.
38291 * <script type="text/javascript">
38296 * @class Roo.form.NumberField
38297 * @extends Roo.form.TextField
38298 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38300 * Creates a new NumberField
38301 * @param {Object} config Configuration options
38303 Roo.form.NumberField = function(config){
38304 Roo.form.NumberField.superclass.constructor.call(this, config);
38307 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38309 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38311 fieldClass: "x-form-field x-form-num-field",
38313 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38315 allowDecimals : true,
38317 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38319 decimalSeparator : ".",
38321 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38323 decimalPrecision : 2,
38325 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38327 allowNegative : true,
38329 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38331 minValue : Number.NEGATIVE_INFINITY,
38333 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38335 maxValue : Number.MAX_VALUE,
38337 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38339 minText : "The minimum value for this field is {0}",
38341 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38343 maxText : "The maximum value for this field is {0}",
38345 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38346 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38348 nanText : "{0} is not a valid number",
38351 initEvents : function(){
38352 Roo.form.NumberField.superclass.initEvents.call(this);
38353 var allowed = "0123456789";
38354 if(this.allowDecimals){
38355 allowed += this.decimalSeparator;
38357 if(this.allowNegative){
38360 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38361 var keyPress = function(e){
38362 var k = e.getKey();
38363 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38366 var c = e.getCharCode();
38367 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38371 this.el.on("keypress", keyPress, this);
38375 validateValue : function(value){
38376 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38379 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38382 var num = this.parseValue(value);
38384 this.markInvalid(String.format(this.nanText, value));
38387 if(num < this.minValue){
38388 this.markInvalid(String.format(this.minText, this.minValue));
38391 if(num > this.maxValue){
38392 this.markInvalid(String.format(this.maxText, this.maxValue));
38398 getValue : function(){
38399 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38403 parseValue : function(value){
38404 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38405 return isNaN(value) ? '' : value;
38409 fixPrecision : function(value){
38410 var nan = isNaN(value);
38411 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38412 return nan ? '' : value;
38414 return parseFloat(value).toFixed(this.decimalPrecision);
38417 setValue : function(v){
38418 v = this.fixPrecision(v);
38419 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38423 decimalPrecisionFcn : function(v){
38424 return Math.floor(v);
38427 beforeBlur : function(){
38428 var v = this.parseValue(this.getRawValue());
38435 * Ext JS Library 1.1.1
38436 * Copyright(c) 2006-2007, Ext JS, LLC.
38438 * Originally Released Under LGPL - original licence link has changed is not relivant.
38441 * <script type="text/javascript">
38445 * @class Roo.form.DateField
38446 * @extends Roo.form.TriggerField
38447 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38449 * Create a new DateField
38450 * @param {Object} config
38452 Roo.form.DateField = function(config){
38453 Roo.form.DateField.superclass.constructor.call(this, config);
38459 * Fires when a date is selected
38460 * @param {Roo.form.DateField} combo This combo box
38461 * @param {Date} date The date selected
38468 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38469 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38470 this.ddMatch = null;
38471 if(this.disabledDates){
38472 var dd = this.disabledDates;
38474 for(var i = 0; i < dd.length; i++){
38476 if(i != dd.length-1) re += "|";
38478 this.ddMatch = new RegExp(re + ")");
38482 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38484 * @cfg {String} format
38485 * The default date format string which can be overriden for localization support. The format must be
38486 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38490 * @cfg {String} altFormats
38491 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38492 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38494 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38496 * @cfg {Array} disabledDays
38497 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38499 disabledDays : null,
38501 * @cfg {String} disabledDaysText
38502 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38504 disabledDaysText : "Disabled",
38506 * @cfg {Array} disabledDates
38507 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38508 * expression so they are very powerful. Some examples:
38510 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38511 * <li>["03/08", "09/16"] would disable those days for every year</li>
38512 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38513 * <li>["03/../2006"] would disable every day in March 2006</li>
38514 * <li>["^03"] would disable every day in every March</li>
38516 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38517 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38519 disabledDates : null,
38521 * @cfg {String} disabledDatesText
38522 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38524 disabledDatesText : "Disabled",
38526 * @cfg {Date/String} minValue
38527 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38528 * valid format (defaults to null).
38532 * @cfg {Date/String} maxValue
38533 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38534 * valid format (defaults to null).
38538 * @cfg {String} minText
38539 * The error text to display when the date in the cell is before minValue (defaults to
38540 * 'The date in this field must be after {minValue}').
38542 minText : "The date in this field must be equal to or after {0}",
38544 * @cfg {String} maxText
38545 * The error text to display when the date in the cell is after maxValue (defaults to
38546 * 'The date in this field must be before {maxValue}').
38548 maxText : "The date in this field must be equal to or before {0}",
38550 * @cfg {String} invalidText
38551 * The error text to display when the date in the field is invalid (defaults to
38552 * '{value} is not a valid date - it must be in the format {format}').
38554 invalidText : "{0} is not a valid date - it must be in the format {1}",
38556 * @cfg {String} triggerClass
38557 * An additional CSS class used to style the trigger button. The trigger will always get the
38558 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38559 * which displays a calendar icon).
38561 triggerClass : 'x-form-date-trigger',
38565 * @cfg {Boolean} useIso
38566 * if enabled, then the date field will use a hidden field to store the
38567 * real value as iso formated date. default (false)
38571 * @cfg {String/Object} autoCreate
38572 * A DomHelper element spec, or true for a default element spec (defaults to
38573 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38576 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38579 hiddenField: false,
38581 onRender : function(ct, position)
38583 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38585 //this.el.dom.removeAttribute('name');
38586 Roo.log("Changing name?");
38587 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38588 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38590 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38591 // prevent input submission
38592 this.hiddenName = this.name;
38599 validateValue : function(value)
38601 value = this.formatDate(value);
38602 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38603 Roo.log('super failed');
38606 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38609 var svalue = value;
38610 value = this.parseDate(value);
38612 Roo.log('parse date failed' + svalue);
38613 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38616 var time = value.getTime();
38617 if(this.minValue && time < this.minValue.getTime()){
38618 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38621 if(this.maxValue && time > this.maxValue.getTime()){
38622 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38625 if(this.disabledDays){
38626 var day = value.getDay();
38627 for(var i = 0; i < this.disabledDays.length; i++) {
38628 if(day === this.disabledDays[i]){
38629 this.markInvalid(this.disabledDaysText);
38634 var fvalue = this.formatDate(value);
38635 if(this.ddMatch && this.ddMatch.test(fvalue)){
38636 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38643 // Provides logic to override the default TriggerField.validateBlur which just returns true
38644 validateBlur : function(){
38645 return !this.menu || !this.menu.isVisible();
38648 getName: function()
38650 // returns hidden if it's set..
38651 if (!this.rendered) {return ''};
38652 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38657 * Returns the current date value of the date field.
38658 * @return {Date} The date value
38660 getValue : function(){
38662 return this.hiddenField ?
38663 this.hiddenField.value :
38664 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38668 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38669 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38670 * (the default format used is "m/d/y").
38673 //All of these calls set the same date value (May 4, 2006)
38675 //Pass a date object:
38676 var dt = new Date('5/4/06');
38677 dateField.setValue(dt);
38679 //Pass a date string (default format):
38680 dateField.setValue('5/4/06');
38682 //Pass a date string (custom format):
38683 dateField.format = 'Y-m-d';
38684 dateField.setValue('2006-5-4');
38686 * @param {String/Date} date The date or valid date string
38688 setValue : function(date){
38689 if (this.hiddenField) {
38690 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38692 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38693 // make sure the value field is always stored as a date..
38694 this.value = this.parseDate(date);
38700 parseDate : function(value){
38701 if(!value || value instanceof Date){
38704 var v = Date.parseDate(value, this.format);
38705 if (!v && this.useIso) {
38706 v = Date.parseDate(value, 'Y-m-d');
38708 if(!v && this.altFormats){
38709 if(!this.altFormatsArray){
38710 this.altFormatsArray = this.altFormats.split("|");
38712 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38713 v = Date.parseDate(value, this.altFormatsArray[i]);
38720 formatDate : function(date, fmt){
38721 return (!date || !(date instanceof Date)) ?
38722 date : date.dateFormat(fmt || this.format);
38727 select: function(m, d){
38730 this.fireEvent('select', this, d);
38732 show : function(){ // retain focus styling
38736 this.focus.defer(10, this);
38737 var ml = this.menuListeners;
38738 this.menu.un("select", ml.select, this);
38739 this.menu.un("show", ml.show, this);
38740 this.menu.un("hide", ml.hide, this);
38745 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38746 onTriggerClick : function(){
38750 if(this.menu == null){
38751 this.menu = new Roo.menu.DateMenu();
38753 Roo.apply(this.menu.picker, {
38754 showClear: this.allowBlank,
38755 minDate : this.minValue,
38756 maxDate : this.maxValue,
38757 disabledDatesRE : this.ddMatch,
38758 disabledDatesText : this.disabledDatesText,
38759 disabledDays : this.disabledDays,
38760 disabledDaysText : this.disabledDaysText,
38761 format : this.useIso ? 'Y-m-d' : this.format,
38762 minText : String.format(this.minText, this.formatDate(this.minValue)),
38763 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38765 this.menu.on(Roo.apply({}, this.menuListeners, {
38768 this.menu.picker.setValue(this.getValue() || new Date());
38769 this.menu.show(this.el, "tl-bl?");
38772 beforeBlur : function(){
38773 var v = this.parseDate(this.getRawValue());
38783 isDirty : function() {
38784 if(this.disabled) {
38788 if(typeof(this.startValue) === 'undefined'){
38792 return String(this.getValue()) !== String(this.startValue);
38797 * Ext JS Library 1.1.1
38798 * Copyright(c) 2006-2007, Ext JS, LLC.
38800 * Originally Released Under LGPL - original licence link has changed is not relivant.
38803 * <script type="text/javascript">
38807 * @class Roo.form.MonthField
38808 * @extends Roo.form.TriggerField
38809 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38811 * Create a new MonthField
38812 * @param {Object} config
38814 Roo.form.MonthField = function(config){
38816 Roo.form.MonthField.superclass.constructor.call(this, config);
38822 * Fires when a date is selected
38823 * @param {Roo.form.MonthFieeld} combo This combo box
38824 * @param {Date} date The date selected
38831 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38832 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38833 this.ddMatch = null;
38834 if(this.disabledDates){
38835 var dd = this.disabledDates;
38837 for(var i = 0; i < dd.length; i++){
38839 if(i != dd.length-1) re += "|";
38841 this.ddMatch = new RegExp(re + ")");
38845 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38847 * @cfg {String} format
38848 * The default date format string which can be overriden for localization support. The format must be
38849 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38853 * @cfg {String} altFormats
38854 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38855 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38857 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38859 * @cfg {Array} disabledDays
38860 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38862 disabledDays : [0,1,2,3,4,5,6],
38864 * @cfg {String} disabledDaysText
38865 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38867 disabledDaysText : "Disabled",
38869 * @cfg {Array} disabledDates
38870 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38871 * expression so they are very powerful. Some examples:
38873 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38874 * <li>["03/08", "09/16"] would disable those days for every year</li>
38875 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38876 * <li>["03/../2006"] would disable every day in March 2006</li>
38877 * <li>["^03"] would disable every day in every March</li>
38879 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38880 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38882 disabledDates : null,
38884 * @cfg {String} disabledDatesText
38885 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38887 disabledDatesText : "Disabled",
38889 * @cfg {Date/String} minValue
38890 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38891 * valid format (defaults to null).
38895 * @cfg {Date/String} maxValue
38896 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38897 * valid format (defaults to null).
38901 * @cfg {String} minText
38902 * The error text to display when the date in the cell is before minValue (defaults to
38903 * 'The date in this field must be after {minValue}').
38905 minText : "The date in this field must be equal to or after {0}",
38907 * @cfg {String} maxTextf
38908 * The error text to display when the date in the cell is after maxValue (defaults to
38909 * 'The date in this field must be before {maxValue}').
38911 maxText : "The date in this field must be equal to or before {0}",
38913 * @cfg {String} invalidText
38914 * The error text to display when the date in the field is invalid (defaults to
38915 * '{value} is not a valid date - it must be in the format {format}').
38917 invalidText : "{0} is not a valid date - it must be in the format {1}",
38919 * @cfg {String} triggerClass
38920 * An additional CSS class used to style the trigger button. The trigger will always get the
38921 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38922 * which displays a calendar icon).
38924 triggerClass : 'x-form-date-trigger',
38928 * @cfg {Boolean} useIso
38929 * if enabled, then the date field will use a hidden field to store the
38930 * real value as iso formated date. default (true)
38934 * @cfg {String/Object} autoCreate
38935 * A DomHelper element spec, or true for a default element spec (defaults to
38936 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38939 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38942 hiddenField: false,
38944 hideMonthPicker : false,
38946 onRender : function(ct, position)
38948 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38950 this.el.dom.removeAttribute('name');
38951 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38953 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38954 // prevent input submission
38955 this.hiddenName = this.name;
38962 validateValue : function(value)
38964 value = this.formatDate(value);
38965 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38968 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38971 var svalue = value;
38972 value = this.parseDate(value);
38974 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38977 var time = value.getTime();
38978 if(this.minValue && time < this.minValue.getTime()){
38979 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38982 if(this.maxValue && time > this.maxValue.getTime()){
38983 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38986 /*if(this.disabledDays){
38987 var day = value.getDay();
38988 for(var i = 0; i < this.disabledDays.length; i++) {
38989 if(day === this.disabledDays[i]){
38990 this.markInvalid(this.disabledDaysText);
38996 var fvalue = this.formatDate(value);
38997 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38998 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39006 // Provides logic to override the default TriggerField.validateBlur which just returns true
39007 validateBlur : function(){
39008 return !this.menu || !this.menu.isVisible();
39012 * Returns the current date value of the date field.
39013 * @return {Date} The date value
39015 getValue : function(){
39019 return this.hiddenField ?
39020 this.hiddenField.value :
39021 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39025 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39026 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39027 * (the default format used is "m/d/y").
39030 //All of these calls set the same date value (May 4, 2006)
39032 //Pass a date object:
39033 var dt = new Date('5/4/06');
39034 monthField.setValue(dt);
39036 //Pass a date string (default format):
39037 monthField.setValue('5/4/06');
39039 //Pass a date string (custom format):
39040 monthField.format = 'Y-m-d';
39041 monthField.setValue('2006-5-4');
39043 * @param {String/Date} date The date or valid date string
39045 setValue : function(date){
39046 Roo.log('month setValue' + date);
39047 // can only be first of month..
39049 var val = this.parseDate(date);
39051 if (this.hiddenField) {
39052 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39054 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39055 this.value = this.parseDate(date);
39059 parseDate : function(value){
39060 if(!value || value instanceof Date){
39061 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39064 var v = Date.parseDate(value, this.format);
39065 if (!v && this.useIso) {
39066 v = Date.parseDate(value, 'Y-m-d');
39070 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39074 if(!v && this.altFormats){
39075 if(!this.altFormatsArray){
39076 this.altFormatsArray = this.altFormats.split("|");
39078 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39079 v = Date.parseDate(value, this.altFormatsArray[i]);
39086 formatDate : function(date, fmt){
39087 return (!date || !(date instanceof Date)) ?
39088 date : date.dateFormat(fmt || this.format);
39093 select: function(m, d){
39095 this.fireEvent('select', this, d);
39097 show : function(){ // retain focus styling
39101 this.focus.defer(10, this);
39102 var ml = this.menuListeners;
39103 this.menu.un("select", ml.select, this);
39104 this.menu.un("show", ml.show, this);
39105 this.menu.un("hide", ml.hide, this);
39109 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39110 onTriggerClick : function(){
39114 if(this.menu == null){
39115 this.menu = new Roo.menu.DateMenu();
39119 Roo.apply(this.menu.picker, {
39121 showClear: this.allowBlank,
39122 minDate : this.minValue,
39123 maxDate : this.maxValue,
39124 disabledDatesRE : this.ddMatch,
39125 disabledDatesText : this.disabledDatesText,
39127 format : this.useIso ? 'Y-m-d' : this.format,
39128 minText : String.format(this.minText, this.formatDate(this.minValue)),
39129 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39132 this.menu.on(Roo.apply({}, this.menuListeners, {
39140 // hide month picker get's called when we called by 'before hide';
39142 var ignorehide = true;
39143 p.hideMonthPicker = function(disableAnim){
39147 if(this.monthPicker){
39148 Roo.log("hideMonthPicker called");
39149 if(disableAnim === true){
39150 this.monthPicker.hide();
39152 this.monthPicker.slideOut('t', {duration:.2});
39153 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39154 p.fireEvent("select", this, this.value);
39160 Roo.log('picker set value');
39161 Roo.log(this.getValue());
39162 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39163 m.show(this.el, 'tl-bl?');
39164 ignorehide = false;
39165 // this will trigger hideMonthPicker..
39168 // hidden the day picker
39169 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39175 p.showMonthPicker.defer(100, p);
39181 beforeBlur : function(){
39182 var v = this.parseDate(this.getRawValue());
39188 /** @cfg {Boolean} grow @hide */
39189 /** @cfg {Number} growMin @hide */
39190 /** @cfg {Number} growMax @hide */
39197 * Ext JS Library 1.1.1
39198 * Copyright(c) 2006-2007, Ext JS, LLC.
39200 * Originally Released Under LGPL - original licence link has changed is not relivant.
39203 * <script type="text/javascript">
39208 * @class Roo.form.ComboBox
39209 * @extends Roo.form.TriggerField
39210 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39212 * Create a new ComboBox.
39213 * @param {Object} config Configuration options
39215 Roo.form.ComboBox = function(config){
39216 Roo.form.ComboBox.superclass.constructor.call(this, config);
39220 * Fires when the dropdown list is expanded
39221 * @param {Roo.form.ComboBox} combo This combo box
39226 * Fires when the dropdown list is collapsed
39227 * @param {Roo.form.ComboBox} combo This combo box
39231 * @event beforeselect
39232 * Fires before a list item is selected. Return false to cancel the selection.
39233 * @param {Roo.form.ComboBox} combo This combo box
39234 * @param {Roo.data.Record} record The data record returned from the underlying store
39235 * @param {Number} index The index of the selected item in the dropdown list
39237 'beforeselect' : true,
39240 * Fires when a list item is selected
39241 * @param {Roo.form.ComboBox} combo This combo box
39242 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39243 * @param {Number} index The index of the selected item in the dropdown list
39247 * @event beforequery
39248 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39249 * The event object passed has these properties:
39250 * @param {Roo.form.ComboBox} combo This combo box
39251 * @param {String} query The query
39252 * @param {Boolean} forceAll true to force "all" query
39253 * @param {Boolean} cancel true to cancel the query
39254 * @param {Object} e The query event object
39256 'beforequery': true,
39259 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39260 * @param {Roo.form.ComboBox} combo This combo box
39265 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39266 * @param {Roo.form.ComboBox} combo This combo box
39267 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39273 if(this.transform){
39274 this.allowDomMove = false;
39275 var s = Roo.getDom(this.transform);
39276 if(!this.hiddenName){
39277 this.hiddenName = s.name;
39280 this.mode = 'local';
39281 var d = [], opts = s.options;
39282 for(var i = 0, len = opts.length;i < len; i++){
39284 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39286 this.value = value;
39288 d.push([value, o.text]);
39290 this.store = new Roo.data.SimpleStore({
39292 fields: ['value', 'text'],
39295 this.valueField = 'value';
39296 this.displayField = 'text';
39298 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39299 if(!this.lazyRender){
39300 this.target = true;
39301 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39302 s.parentNode.removeChild(s); // remove it
39303 this.render(this.el.parentNode);
39305 s.parentNode.removeChild(s); // remove it
39310 this.store = Roo.factory(this.store, Roo.data);
39313 this.selectedIndex = -1;
39314 if(this.mode == 'local'){
39315 if(config.queryDelay === undefined){
39316 this.queryDelay = 10;
39318 if(config.minChars === undefined){
39324 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39326 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39329 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39330 * rendering into an Roo.Editor, defaults to false)
39333 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39334 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39337 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39340 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39341 * the dropdown list (defaults to undefined, with no header element)
39345 * @cfg {String/Roo.Template} tpl The template to use to render the output
39349 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39351 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39353 listWidth: undefined,
39355 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39356 * mode = 'remote' or 'text' if mode = 'local')
39358 displayField: undefined,
39360 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39361 * mode = 'remote' or 'value' if mode = 'local').
39362 * Note: use of a valueField requires the user make a selection
39363 * in order for a value to be mapped.
39365 valueField: undefined,
39369 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39370 * field's data value (defaults to the underlying DOM element's name)
39372 hiddenName: undefined,
39374 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39378 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39380 selectedClass: 'x-combo-selected',
39382 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39383 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39384 * which displays a downward arrow icon).
39386 triggerClass : 'x-form-arrow-trigger',
39388 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39392 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39393 * anchor positions (defaults to 'tl-bl')
39395 listAlign: 'tl-bl?',
39397 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39401 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39402 * query specified by the allQuery config option (defaults to 'query')
39404 triggerAction: 'query',
39406 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39407 * (defaults to 4, does not apply if editable = false)
39411 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39412 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39416 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39417 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39421 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39422 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39426 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39427 * when editable = true (defaults to false)
39429 selectOnFocus:false,
39431 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39433 queryParam: 'query',
39435 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39436 * when mode = 'remote' (defaults to 'Loading...')
39438 loadingText: 'Loading...',
39440 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39444 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39448 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39449 * traditional select (defaults to true)
39453 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39457 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39461 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39462 * listWidth has a higher value)
39466 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39467 * allow the user to set arbitrary text into the field (defaults to false)
39469 forceSelection:false,
39471 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39472 * if typeAhead = true (defaults to 250)
39474 typeAheadDelay : 250,
39476 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39477 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39479 valueNotFoundText : undefined,
39481 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39483 blockFocus : false,
39486 * @cfg {Boolean} disableClear Disable showing of clear button.
39488 disableClear : false,
39490 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39492 alwaysQuery : false,
39498 // element that contains real text value.. (when hidden is used..)
39501 onRender : function(ct, position){
39502 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39503 if(this.hiddenName){
39504 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39506 this.hiddenField.value =
39507 this.hiddenValue !== undefined ? this.hiddenValue :
39508 this.value !== undefined ? this.value : '';
39510 // prevent input submission
39511 this.el.dom.removeAttribute('name');
39516 this.el.dom.setAttribute('autocomplete', 'off');
39519 var cls = 'x-combo-list';
39521 this.list = new Roo.Layer({
39522 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39525 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39526 this.list.setWidth(lw);
39527 this.list.swallowEvent('mousewheel');
39528 this.assetHeight = 0;
39531 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39532 this.assetHeight += this.header.getHeight();
39535 this.innerList = this.list.createChild({cls:cls+'-inner'});
39536 this.innerList.on('mouseover', this.onViewOver, this);
39537 this.innerList.on('mousemove', this.onViewMove, this);
39538 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39540 if(this.allowBlank && !this.pageSize && !this.disableClear){
39541 this.footer = this.list.createChild({cls:cls+'-ft'});
39542 this.pageTb = new Roo.Toolbar(this.footer);
39546 this.footer = this.list.createChild({cls:cls+'-ft'});
39547 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39548 {pageSize: this.pageSize});
39552 if (this.pageTb && this.allowBlank && !this.disableClear) {
39554 this.pageTb.add(new Roo.Toolbar.Fill(), {
39555 cls: 'x-btn-icon x-btn-clear',
39557 handler: function()
39560 _this.clearValue();
39561 _this.onSelect(false, -1);
39566 this.assetHeight += this.footer.getHeight();
39571 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39574 this.view = new Roo.View(this.innerList, this.tpl, {
39575 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39578 this.view.on('click', this.onViewClick, this);
39580 this.store.on('beforeload', this.onBeforeLoad, this);
39581 this.store.on('load', this.onLoad, this);
39582 this.store.on('loadexception', this.onLoadException, this);
39584 if(this.resizable){
39585 this.resizer = new Roo.Resizable(this.list, {
39586 pinned:true, handles:'se'
39588 this.resizer.on('resize', function(r, w, h){
39589 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39590 this.listWidth = w;
39591 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39592 this.restrictHeight();
39594 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39596 if(!this.editable){
39597 this.editable = true;
39598 this.setEditable(false);
39602 if (typeof(this.events.add.listeners) != 'undefined') {
39604 this.addicon = this.wrap.createChild(
39605 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39607 this.addicon.on('click', function(e) {
39608 this.fireEvent('add', this);
39611 if (typeof(this.events.edit.listeners) != 'undefined') {
39613 this.editicon = this.wrap.createChild(
39614 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39615 if (this.addicon) {
39616 this.editicon.setStyle('margin-left', '40px');
39618 this.editicon.on('click', function(e) {
39620 // we fire even if inothing is selected..
39621 this.fireEvent('edit', this, this.lastData );
39631 initEvents : function(){
39632 Roo.form.ComboBox.superclass.initEvents.call(this);
39634 this.keyNav = new Roo.KeyNav(this.el, {
39635 "up" : function(e){
39636 this.inKeyMode = true;
39640 "down" : function(e){
39641 if(!this.isExpanded()){
39642 this.onTriggerClick();
39644 this.inKeyMode = true;
39649 "enter" : function(e){
39650 this.onViewClick();
39654 "esc" : function(e){
39658 "tab" : function(e){
39659 this.onViewClick(false);
39660 this.fireEvent("specialkey", this, e);
39666 doRelay : function(foo, bar, hname){
39667 if(hname == 'down' || this.scope.isExpanded()){
39668 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39675 this.queryDelay = Math.max(this.queryDelay || 10,
39676 this.mode == 'local' ? 10 : 250);
39677 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39678 if(this.typeAhead){
39679 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39681 if(this.editable !== false){
39682 this.el.on("keyup", this.onKeyUp, this);
39684 if(this.forceSelection){
39685 this.on('blur', this.doForce, this);
39689 onDestroy : function(){
39691 this.view.setStore(null);
39692 this.view.el.removeAllListeners();
39693 this.view.el.remove();
39694 this.view.purgeListeners();
39697 this.list.destroy();
39700 this.store.un('beforeload', this.onBeforeLoad, this);
39701 this.store.un('load', this.onLoad, this);
39702 this.store.un('loadexception', this.onLoadException, this);
39704 Roo.form.ComboBox.superclass.onDestroy.call(this);
39708 fireKey : function(e){
39709 if(e.isNavKeyPress() && !this.list.isVisible()){
39710 this.fireEvent("specialkey", this, e);
39715 onResize: function(w, h){
39716 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39718 if(typeof w != 'number'){
39719 // we do not handle it!?!?
39722 var tw = this.trigger.getWidth();
39723 tw += this.addicon ? this.addicon.getWidth() : 0;
39724 tw += this.editicon ? this.editicon.getWidth() : 0;
39726 this.el.setWidth( this.adjustWidth('input', x));
39728 this.trigger.setStyle('left', x+'px');
39730 if(this.list && this.listWidth === undefined){
39731 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39732 this.list.setWidth(lw);
39733 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39741 * Allow or prevent the user from directly editing the field text. If false is passed,
39742 * the user will only be able to select from the items defined in the dropdown list. This method
39743 * is the runtime equivalent of setting the 'editable' config option at config time.
39744 * @param {Boolean} value True to allow the user to directly edit the field text
39746 setEditable : function(value){
39747 if(value == this.editable){
39750 this.editable = value;
39752 this.el.dom.setAttribute('readOnly', true);
39753 this.el.on('mousedown', this.onTriggerClick, this);
39754 this.el.addClass('x-combo-noedit');
39756 this.el.dom.setAttribute('readOnly', false);
39757 this.el.un('mousedown', this.onTriggerClick, this);
39758 this.el.removeClass('x-combo-noedit');
39763 onBeforeLoad : function(){
39764 if(!this.hasFocus){
39767 this.innerList.update(this.loadingText ?
39768 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39769 this.restrictHeight();
39770 this.selectedIndex = -1;
39774 onLoad : function(){
39775 if(!this.hasFocus){
39778 if(this.store.getCount() > 0){
39780 this.restrictHeight();
39781 if(this.lastQuery == this.allQuery){
39783 this.el.dom.select();
39785 if(!this.selectByValue(this.value, true)){
39786 this.select(0, true);
39790 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39791 this.taTask.delay(this.typeAheadDelay);
39795 this.onEmptyResults();
39800 onLoadException : function()
39803 Roo.log(this.store.reader.jsonData);
39804 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39805 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39811 onTypeAhead : function(){
39812 if(this.store.getCount() > 0){
39813 var r = this.store.getAt(0);
39814 var newValue = r.data[this.displayField];
39815 var len = newValue.length;
39816 var selStart = this.getRawValue().length;
39817 if(selStart != len){
39818 this.setRawValue(newValue);
39819 this.selectText(selStart, newValue.length);
39825 onSelect : function(record, index){
39826 if(this.fireEvent('beforeselect', this, record, index) !== false){
39827 this.setFromData(index > -1 ? record.data : false);
39829 this.fireEvent('select', this, record, index);
39834 * Returns the currently selected field value or empty string if no value is set.
39835 * @return {String} value The selected value
39837 getValue : function(){
39838 if(this.valueField){
39839 return typeof this.value != 'undefined' ? this.value : '';
39841 return Roo.form.ComboBox.superclass.getValue.call(this);
39845 * Clears any text/value currently set in the field
39847 clearValue : function(){
39848 if(this.hiddenField){
39849 this.hiddenField.value = '';
39852 this.setRawValue('');
39853 this.lastSelectionText = '';
39858 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39859 * will be displayed in the field. If the value does not match the data value of an existing item,
39860 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39861 * Otherwise the field will be blank (although the value will still be set).
39862 * @param {String} value The value to match
39864 setValue : function(v){
39866 if(this.valueField){
39867 var r = this.findRecord(this.valueField, v);
39869 text = r.data[this.displayField];
39870 }else if(this.valueNotFoundText !== undefined){
39871 text = this.valueNotFoundText;
39874 this.lastSelectionText = text;
39875 if(this.hiddenField){
39876 this.hiddenField.value = v;
39878 Roo.form.ComboBox.superclass.setValue.call(this, text);
39882 * @property {Object} the last set data for the element
39887 * Sets the value of the field based on a object which is related to the record format for the store.
39888 * @param {Object} value the value to set as. or false on reset?
39890 setFromData : function(o){
39891 var dv = ''; // display value
39892 var vv = ''; // value value..
39894 if (this.displayField) {
39895 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39897 // this is an error condition!!!
39898 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39901 if(this.valueField){
39902 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39904 if(this.hiddenField){
39905 this.hiddenField.value = vv;
39907 this.lastSelectionText = dv;
39908 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39912 // no hidden field.. - we store the value in 'value', but still display
39913 // display field!!!!
39914 this.lastSelectionText = dv;
39915 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39921 reset : function(){
39922 // overridden so that last data is reset..
39923 this.setValue(this.resetValue);
39924 this.clearInvalid();
39925 this.lastData = false;
39927 this.view.clearSelections();
39931 findRecord : function(prop, value){
39933 if(this.store.getCount() > 0){
39934 this.store.each(function(r){
39935 if(r.data[prop] == value){
39945 getName: function()
39947 // returns hidden if it's set..
39948 if (!this.rendered) {return ''};
39949 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39953 onViewMove : function(e, t){
39954 this.inKeyMode = false;
39958 onViewOver : function(e, t){
39959 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39962 var item = this.view.findItemFromChild(t);
39964 var index = this.view.indexOf(item);
39965 this.select(index, false);
39970 onViewClick : function(doFocus)
39972 var index = this.view.getSelectedIndexes()[0];
39973 var r = this.store.getAt(index);
39975 this.onSelect(r, index);
39977 if(doFocus !== false && !this.blockFocus){
39983 restrictHeight : function(){
39984 this.innerList.dom.style.height = '';
39985 var inner = this.innerList.dom;
39986 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39987 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39988 this.list.beginUpdate();
39989 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39990 this.list.alignTo(this.el, this.listAlign);
39991 this.list.endUpdate();
39995 onEmptyResults : function(){
40000 * Returns true if the dropdown list is expanded, else false.
40002 isExpanded : function(){
40003 return this.list.isVisible();
40007 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40008 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40009 * @param {String} value The data value of the item to select
40010 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40011 * selected item if it is not currently in view (defaults to true)
40012 * @return {Boolean} True if the value matched an item in the list, else false
40014 selectByValue : function(v, scrollIntoView){
40015 if(v !== undefined && v !== null){
40016 var r = this.findRecord(this.valueField || this.displayField, v);
40018 this.select(this.store.indexOf(r), scrollIntoView);
40026 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40027 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40028 * @param {Number} index The zero-based index of the list item to select
40029 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40030 * selected item if it is not currently in view (defaults to true)
40032 select : function(index, scrollIntoView){
40033 this.selectedIndex = index;
40034 this.view.select(index);
40035 if(scrollIntoView !== false){
40036 var el = this.view.getNode(index);
40038 this.innerList.scrollChildIntoView(el, false);
40044 selectNext : function(){
40045 var ct = this.store.getCount();
40047 if(this.selectedIndex == -1){
40049 }else if(this.selectedIndex < ct-1){
40050 this.select(this.selectedIndex+1);
40056 selectPrev : function(){
40057 var ct = this.store.getCount();
40059 if(this.selectedIndex == -1){
40061 }else if(this.selectedIndex != 0){
40062 this.select(this.selectedIndex-1);
40068 onKeyUp : function(e){
40069 if(this.editable !== false && !e.isSpecialKey()){
40070 this.lastKey = e.getKey();
40071 this.dqTask.delay(this.queryDelay);
40076 validateBlur : function(){
40077 return !this.list || !this.list.isVisible();
40081 initQuery : function(){
40082 this.doQuery(this.getRawValue());
40086 doForce : function(){
40087 if(this.el.dom.value.length > 0){
40088 this.el.dom.value =
40089 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40095 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40096 * query allowing the query action to be canceled if needed.
40097 * @param {String} query The SQL query to execute
40098 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40099 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40100 * saved in the current store (defaults to false)
40102 doQuery : function(q, forceAll){
40103 if(q === undefined || q === null){
40108 forceAll: forceAll,
40112 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40116 forceAll = qe.forceAll;
40117 if(forceAll === true || (q.length >= this.minChars)){
40118 if(this.lastQuery != q || this.alwaysQuery){
40119 this.lastQuery = q;
40120 if(this.mode == 'local'){
40121 this.selectedIndex = -1;
40123 this.store.clearFilter();
40125 this.store.filter(this.displayField, q);
40129 this.store.baseParams[this.queryParam] = q;
40131 params: this.getParams(q)
40136 this.selectedIndex = -1;
40143 getParams : function(q){
40145 //p[this.queryParam] = q;
40148 p.limit = this.pageSize;
40154 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40156 collapse : function(){
40157 if(!this.isExpanded()){
40161 Roo.get(document).un('mousedown', this.collapseIf, this);
40162 Roo.get(document).un('mousewheel', this.collapseIf, this);
40163 if (!this.editable) {
40164 Roo.get(document).un('keydown', this.listKeyPress, this);
40166 this.fireEvent('collapse', this);
40170 collapseIf : function(e){
40171 if(!e.within(this.wrap) && !e.within(this.list)){
40177 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40179 expand : function(){
40180 if(this.isExpanded() || !this.hasFocus){
40183 this.list.alignTo(this.el, this.listAlign);
40185 Roo.get(document).on('mousedown', this.collapseIf, this);
40186 Roo.get(document).on('mousewheel', this.collapseIf, this);
40187 if (!this.editable) {
40188 Roo.get(document).on('keydown', this.listKeyPress, this);
40191 this.fireEvent('expand', this);
40195 // Implements the default empty TriggerField.onTriggerClick function
40196 onTriggerClick : function(){
40200 if(this.isExpanded()){
40202 if (!this.blockFocus) {
40207 this.hasFocus = true;
40208 if(this.triggerAction == 'all') {
40209 this.doQuery(this.allQuery, true);
40211 this.doQuery(this.getRawValue());
40213 if (!this.blockFocus) {
40218 listKeyPress : function(e)
40220 //Roo.log('listkeypress');
40221 // scroll to first matching element based on key pres..
40222 if (e.isSpecialKey()) {
40225 var k = String.fromCharCode(e.getKey()).toUpperCase();
40228 var csel = this.view.getSelectedNodes();
40229 var cselitem = false;
40231 var ix = this.view.indexOf(csel[0]);
40232 cselitem = this.store.getAt(ix);
40233 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40239 this.store.each(function(v) {
40241 // start at existing selection.
40242 if (cselitem.id == v.id) {
40248 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40249 match = this.store.indexOf(v);
40254 if (match === false) {
40255 return true; // no more action?
40258 this.view.select(match);
40259 var sn = Roo.get(this.view.getSelectedNodes()[0])
40260 sn.scrollIntoView(sn.dom.parentNode, false);
40264 * @cfg {Boolean} grow
40268 * @cfg {Number} growMin
40272 * @cfg {Number} growMax
40280 * Copyright(c) 2010-2012, Roo J Solutions Limited
40287 * @class Roo.form.ComboBoxArray
40288 * @extends Roo.form.TextField
40289 * A facebook style adder... for lists of email / people / countries etc...
40290 * pick multiple items from a combo box, and shows each one.
40292 * Fred [x] Brian [x] [Pick another |v]
40295 * For this to work: it needs various extra information
40296 * - normal combo problay has
40298 * + displayField, valueField
40300 * For our purpose...
40303 * If we change from 'extends' to wrapping...
40310 * Create a new ComboBoxArray.
40311 * @param {Object} config Configuration options
40315 Roo.form.ComboBoxArray = function(config)
40320 * Fires when remove the value from the list
40321 * @param {Roo.form.ComboBoxArray} _self This combo box array
40322 * @param {Roo.form.ComboBoxArray.Item} item removed item
40329 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40331 this.items = new Roo.util.MixedCollection(false);
40333 // construct the child combo...
40343 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40346 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40351 // behavies liek a hiddne field
40352 inputType: 'hidden',
40354 * @cfg {Number} width The width of the box that displays the selected element
40361 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40365 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40367 hiddenName : false,
40370 // private the array of items that are displayed..
40372 // private - the hidden field el.
40374 // private - the filed el..
40377 //validateValue : function() { return true; }, // all values are ok!
40378 //onAddClick: function() { },
40380 onRender : function(ct, position)
40383 // create the standard hidden element
40384 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40387 // give fake names to child combo;
40388 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40389 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40391 this.combo = Roo.factory(this.combo, Roo.form);
40392 this.combo.onRender(ct, position);
40393 if (typeof(this.combo.width) != 'undefined') {
40394 this.combo.onResize(this.combo.width,0);
40397 this.combo.initEvents();
40399 // assigned so form know we need to do this..
40400 this.store = this.combo.store;
40401 this.valueField = this.combo.valueField;
40402 this.displayField = this.combo.displayField ;
40405 this.combo.wrap.addClass('x-cbarray-grp');
40407 var cbwrap = this.combo.wrap.createChild(
40408 {tag: 'div', cls: 'x-cbarray-cb'},
40413 this.hiddenEl = this.combo.wrap.createChild({
40414 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40416 this.el = this.combo.wrap.createChild({
40417 tag: 'input', type:'hidden' , name: this.name, value : ''
40419 // this.el.dom.removeAttribute("name");
40422 this.outerWrap = this.combo.wrap;
40423 this.wrap = cbwrap;
40425 this.outerWrap.setWidth(this.width);
40426 this.outerWrap.dom.removeChild(this.el.dom);
40428 this.wrap.dom.appendChild(this.el.dom);
40429 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40430 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40432 this.combo.trigger.setStyle('position','relative');
40433 this.combo.trigger.setStyle('left', '0px');
40434 this.combo.trigger.setStyle('top', '2px');
40436 this.combo.el.setStyle('vertical-align', 'text-bottom');
40438 //this.trigger.setStyle('vertical-align', 'top');
40440 // this should use the code from combo really... on('add' ....)
40444 this.adder = this.outerWrap.createChild(
40445 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40447 this.adder.on('click', function(e) {
40448 _t.fireEvent('adderclick', this, e);
40452 //this.adder.on('click', this.onAddClick, _t);
40455 this.combo.on('select', function(cb, rec, ix) {
40456 this.addItem(rec.data);
40459 cb.el.dom.value = '';
40460 //cb.lastData = rec.data;
40469 getName: function()
40471 // returns hidden if it's set..
40472 if (!this.rendered) {return ''};
40473 return this.hiddenName ? this.hiddenName : this.name;
40478 onResize: function(w, h){
40481 // not sure if this is needed..
40482 //this.combo.onResize(w,h);
40484 if(typeof w != 'number'){
40485 // we do not handle it!?!?
40488 var tw = this.combo.trigger.getWidth();
40489 tw += this.addicon ? this.addicon.getWidth() : 0;
40490 tw += this.editicon ? this.editicon.getWidth() : 0;
40492 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40494 this.combo.trigger.setStyle('left', '0px');
40496 if(this.list && this.listWidth === undefined){
40497 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40498 this.list.setWidth(lw);
40499 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40506 addItem: function(rec)
40508 var valueField = this.combo.valueField;
40509 var displayField = this.combo.displayField;
40510 if (this.items.indexOfKey(rec[valueField]) > -1) {
40511 //console.log("GOT " + rec.data.id);
40515 var x = new Roo.form.ComboBoxArray.Item({
40516 //id : rec[this.idField],
40518 displayField : displayField ,
40519 tipField : displayField ,
40523 this.items.add(rec[valueField],x);
40524 // add it before the element..
40525 this.updateHiddenEl();
40526 x.render(this.outerWrap, this.wrap.dom);
40527 // add the image handler..
40530 updateHiddenEl : function()
40533 if (!this.hiddenEl) {
40537 var idField = this.combo.valueField;
40539 this.items.each(function(f) {
40540 ar.push(f.data[idField]);
40543 this.hiddenEl.dom.value = ar.join(',');
40549 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40550 this.items.each(function(f) {
40553 this.el.dom.value = '';
40554 if (this.hiddenEl) {
40555 this.hiddenEl.dom.value = '';
40559 getValue: function()
40561 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40563 setValue: function(v) // not a valid action - must use addItems..
40570 if (this.store.isLocal && (typeof(v) == 'string')) {
40571 // then we can use the store to find the values..
40572 // comma seperated at present.. this needs to allow JSON based encoding..
40573 this.hiddenEl.value = v;
40575 Roo.each(v.split(','), function(k) {
40576 Roo.log("CHECK " + this.valueField + ',' + k);
40577 var li = this.store.query(this.valueField, k);
40582 add[this.valueField] = k;
40583 add[this.displayField] = li.item(0).data[this.displayField];
40589 if (typeof(v) == 'object' ) {
40590 // then let's assume it's an array of objects..
40591 Roo.each(v, function(l) {
40599 setFromData: function(v)
40601 // this recieves an object, if setValues is called.
40603 this.el.dom.value = v[this.displayField];
40604 this.hiddenEl.dom.value = v[this.valueField];
40605 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40608 var kv = v[this.valueField];
40609 var dv = v[this.displayField];
40610 kv = typeof(kv) != 'string' ? '' : kv;
40611 dv = typeof(dv) != 'string' ? '' : dv;
40614 var keys = kv.split(',');
40615 var display = dv.split(',');
40616 for (var i = 0 ; i < keys.length; i++) {
40619 add[this.valueField] = keys[i];
40620 add[this.displayField] = display[i];
40628 * Validates the combox array value
40629 * @return {Boolean} True if the value is valid, else false
40631 validate : function(){
40632 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40633 this.clearInvalid();
40639 validateValue : function(value){
40640 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40648 isDirty : function() {
40649 if(this.disabled) {
40654 var d = Roo.decode(String(this.originalValue));
40656 return String(this.getValue()) !== String(this.originalValue);
40659 var originalValue = [];
40661 for (var i = 0; i < d.length; i++){
40662 originalValue.push(d[i][this.valueField]);
40665 return String(this.getValue()) !== String(originalValue.join(','));
40674 * @class Roo.form.ComboBoxArray.Item
40675 * @extends Roo.BoxComponent
40676 * A selected item in the list
40677 * Fred [x] Brian [x] [Pick another |v]
40680 * Create a new item.
40681 * @param {Object} config Configuration options
40684 Roo.form.ComboBoxArray.Item = function(config) {
40685 config.id = Roo.id();
40686 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40689 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40692 displayField : false,
40696 defaultAutoCreate : {
40698 cls: 'x-cbarray-item',
40705 src : Roo.BLANK_IMAGE_URL ,
40713 onRender : function(ct, position)
40715 Roo.form.Field.superclass.onRender.call(this, ct, position);
40718 var cfg = this.getAutoCreate();
40719 this.el = ct.createChild(cfg, position);
40722 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40724 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40725 this.cb.renderer(this.data) :
40726 String.format('{0}',this.data[this.displayField]);
40729 this.el.child('div').dom.setAttribute('qtip',
40730 String.format('{0}',this.data[this.tipField])
40733 this.el.child('img').on('click', this.remove, this);
40737 remove : function()
40739 if(this.cb.disabled){
40742 this.cb.items.remove(this);
40743 this.el.child('img').un('click', this.remove, this);
40745 this.cb.updateHiddenEl();
40747 this.cb.fireEvent('remove', this.cb, this);
40751 * Ext JS Library 1.1.1
40752 * Copyright(c) 2006-2007, Ext JS, LLC.
40754 * Originally Released Under LGPL - original licence link has changed is not relivant.
40757 * <script type="text/javascript">
40760 * @class Roo.form.Checkbox
40761 * @extends Roo.form.Field
40762 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40764 * Creates a new Checkbox
40765 * @param {Object} config Configuration options
40767 Roo.form.Checkbox = function(config){
40768 Roo.form.Checkbox.superclass.constructor.call(this, config);
40772 * Fires when the checkbox is checked or unchecked.
40773 * @param {Roo.form.Checkbox} this This checkbox
40774 * @param {Boolean} checked The new checked value
40780 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40782 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40784 focusClass : undefined,
40786 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40788 fieldClass: "x-form-field",
40790 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40794 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40795 * {tag: "input", type: "checkbox", autocomplete: "off"})
40797 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40799 * @cfg {String} boxLabel The text that appears beside the checkbox
40803 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40807 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40809 valueOff: '0', // value when not checked..
40811 actionMode : 'viewEl',
40814 itemCls : 'x-menu-check-item x-form-item',
40815 groupClass : 'x-menu-group-item',
40816 inputType : 'hidden',
40819 inSetChecked: false, // check that we are not calling self...
40821 inputElement: false, // real input element?
40822 basedOn: false, // ????
40824 isFormField: true, // not sure where this is needed!!!!
40826 onResize : function(){
40827 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40828 if(!this.boxLabel){
40829 this.el.alignTo(this.wrap, 'c-c');
40833 initEvents : function(){
40834 Roo.form.Checkbox.superclass.initEvents.call(this);
40835 this.el.on("click", this.onClick, this);
40836 this.el.on("change", this.onClick, this);
40840 getResizeEl : function(){
40844 getPositionEl : function(){
40849 onRender : function(ct, position){
40850 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40852 if(this.inputValue !== undefined){
40853 this.el.dom.value = this.inputValue;
40856 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40857 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40858 var viewEl = this.wrap.createChild({
40859 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40860 this.viewEl = viewEl;
40861 this.wrap.on('click', this.onClick, this);
40863 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40864 this.el.on('propertychange', this.setFromHidden, this); //ie
40869 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40870 // viewEl.on('click', this.onClick, this);
40872 //if(this.checked){
40873 this.setChecked(this.checked);
40875 //this.checked = this.el.dom;
40881 initValue : Roo.emptyFn,
40884 * Returns the checked state of the checkbox.
40885 * @return {Boolean} True if checked, else false
40887 getValue : function(){
40889 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40891 return this.valueOff;
40896 onClick : function(){
40897 if (this.disabled) {
40900 this.setChecked(!this.checked);
40902 //if(this.el.dom.checked != this.checked){
40903 // this.setValue(this.el.dom.checked);
40908 * Sets the checked state of the checkbox.
40909 * On is always based on a string comparison between inputValue and the param.
40910 * @param {Boolean/String} value - the value to set
40911 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40913 setValue : function(v,suppressEvent){
40916 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40917 //if(this.el && this.el.dom){
40918 // this.el.dom.checked = this.checked;
40919 // this.el.dom.defaultChecked = this.checked;
40921 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40922 //this.fireEvent("check", this, this.checked);
40925 setChecked : function(state,suppressEvent)
40927 if (this.inSetChecked) {
40928 this.checked = state;
40934 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40936 this.checked = state;
40937 if(suppressEvent !== true){
40938 this.fireEvent('check', this, state);
40940 this.inSetChecked = true;
40941 this.el.dom.value = state ? this.inputValue : this.valueOff;
40942 this.inSetChecked = false;
40945 // handle setting of hidden value by some other method!!?!?
40946 setFromHidden: function()
40951 //console.log("SET FROM HIDDEN");
40952 //alert('setFrom hidden');
40953 this.setValue(this.el.dom.value);
40956 onDestroy : function()
40959 Roo.get(this.viewEl).remove();
40962 Roo.form.Checkbox.superclass.onDestroy.call(this);
40967 * Ext JS Library 1.1.1
40968 * Copyright(c) 2006-2007, Ext JS, LLC.
40970 * Originally Released Under LGPL - original licence link has changed is not relivant.
40973 * <script type="text/javascript">
40977 * @class Roo.form.Radio
40978 * @extends Roo.form.Checkbox
40979 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40980 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40982 * Creates a new Radio
40983 * @param {Object} config Configuration options
40985 Roo.form.Radio = function(){
40986 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40988 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40989 inputType: 'radio',
40992 * If this radio is part of a group, it will return the selected value
40995 getGroupValue : function(){
40996 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41000 onRender : function(ct, position){
41001 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41003 if(this.inputValue !== undefined){
41004 this.el.dom.value = this.inputValue;
41007 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41008 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41009 //var viewEl = this.wrap.createChild({
41010 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41011 //this.viewEl = viewEl;
41012 //this.wrap.on('click', this.onClick, this);
41014 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41015 //this.el.on('propertychange', this.setFromHidden, this); //ie
41020 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41021 // viewEl.on('click', this.onClick, this);
41024 this.el.dom.checked = 'checked' ;
41030 });//<script type="text/javascript">
41033 * Based Ext JS Library 1.1.1
41034 * Copyright(c) 2006-2007, Ext JS, LLC.
41040 * @class Roo.HtmlEditorCore
41041 * @extends Roo.Component
41042 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41044 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41047 Roo.HtmlEditorCore = function(config){
41050 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41055 * @event initialize
41056 * Fires when the editor is fully initialized (including the iframe)
41057 * @param {Roo.HtmlEditorCore} this
41062 * Fires when the editor is first receives the focus. Any insertion must wait
41063 * until after this event.
41064 * @param {Roo.HtmlEditorCore} this
41068 * @event beforesync
41069 * Fires before the textarea is updated with content from the editor iframe. Return false
41070 * to cancel the sync.
41071 * @param {Roo.HtmlEditorCore} this
41072 * @param {String} html
41076 * @event beforepush
41077 * Fires before the iframe editor is updated with content from the textarea. Return false
41078 * to cancel the push.
41079 * @param {Roo.HtmlEditorCore} this
41080 * @param {String} html
41085 * Fires when the textarea is updated with content from the editor iframe.
41086 * @param {Roo.HtmlEditorCore} this
41087 * @param {String} html
41092 * Fires when the iframe editor is updated with content from the textarea.
41093 * @param {Roo.HtmlEditorCore} this
41094 * @param {String} html
41099 * @event editorevent
41100 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41101 * @param {Roo.HtmlEditorCore} this
41106 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41108 // defaults : white / black...
41109 this.applyBlacklists();
41116 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41120 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41126 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41131 * @cfg {Number} height (in pixels)
41135 * @cfg {Number} width (in pixels)
41140 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41143 stylesheets: false,
41148 // private properties
41149 validationEvent : false,
41151 initialized : false,
41153 sourceEditMode : false,
41154 onFocus : Roo.emptyFn,
41156 hideMode:'offsets',
41160 // blacklist + whitelisted elements..
41167 * Protected method that will not generally be called directly. It
41168 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41169 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41171 getDocMarkup : function(){
41174 Roo.log(this.stylesheets);
41176 // inherit styels from page...??
41177 if (this.stylesheets === false) {
41179 Roo.get(document.head).select('style').each(function(node) {
41180 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41183 Roo.get(document.head).select('link').each(function(node) {
41184 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41187 } else if (!this.stylesheets.length) {
41189 st = '<style type="text/css">' +
41190 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41193 Roo.each(this.stylesheets, function(s) {
41194 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41199 st += '<style type="text/css">' +
41200 'IMG { cursor: pointer } ' +
41204 return '<html><head>' + st +
41205 //<style type="text/css">' +
41206 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41208 ' </head><body class="roo-htmleditor-body"></body></html>';
41212 onRender : function(ct, position)
41215 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41216 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41219 this.el.dom.style.border = '0 none';
41220 this.el.dom.setAttribute('tabIndex', -1);
41221 this.el.addClass('x-hidden hide');
41225 if(Roo.isIE){ // fix IE 1px bogus margin
41226 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41230 this.frameId = Roo.id();
41234 var iframe = this.owner.wrap.createChild({
41236 cls: 'form-control', // bootstrap..
41238 name: this.frameId,
41239 frameBorder : 'no',
41240 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41245 this.iframe = iframe.dom;
41247 this.assignDocWin();
41249 this.doc.designMode = 'on';
41252 this.doc.write(this.getDocMarkup());
41256 var task = { // must defer to wait for browser to be ready
41258 //console.log("run task?" + this.doc.readyState);
41259 this.assignDocWin();
41260 if(this.doc.body || this.doc.readyState == 'complete'){
41262 this.doc.designMode="on";
41266 Roo.TaskMgr.stop(task);
41267 this.initEditor.defer(10, this);
41274 Roo.TaskMgr.start(task);
41281 onResize : function(w, h)
41283 Roo.log('resize: ' +w + ',' + h );
41284 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41288 if(typeof w == 'number'){
41290 this.iframe.style.width = w + 'px';
41292 if(typeof h == 'number'){
41294 this.iframe.style.height = h + 'px';
41296 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41303 * Toggles the editor between standard and source edit mode.
41304 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41306 toggleSourceEdit : function(sourceEditMode){
41308 this.sourceEditMode = sourceEditMode === true;
41310 if(this.sourceEditMode){
41312 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41315 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41316 //this.iframe.className = '';
41319 //this.setSize(this.owner.wrap.getSize());
41320 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41327 * Protected method that will not generally be called directly. If you need/want
41328 * custom HTML cleanup, this is the method you should override.
41329 * @param {String} html The HTML to be cleaned
41330 * return {String} The cleaned HTML
41332 cleanHtml : function(html){
41333 html = String(html);
41334 if(html.length > 5){
41335 if(Roo.isSafari){ // strip safari nonsense
41336 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41339 if(html == ' '){
41346 * HTML Editor -> Textarea
41347 * Protected method that will not generally be called directly. Syncs the contents
41348 * of the editor iframe with the textarea.
41350 syncValue : function(){
41351 if(this.initialized){
41352 var bd = (this.doc.body || this.doc.documentElement);
41353 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41354 var html = bd.innerHTML;
41356 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41357 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41359 html = '<div style="'+m[0]+'">' + html + '</div>';
41362 html = this.cleanHtml(html);
41363 // fix up the special chars.. normaly like back quotes in word...
41364 // however we do not want to do this with chinese..
41365 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41366 var cc = b.charCodeAt();
41368 (cc >= 0x4E00 && cc < 0xA000 ) ||
41369 (cc >= 0x3400 && cc < 0x4E00 ) ||
41370 (cc >= 0xf900 && cc < 0xfb00 )
41376 if(this.owner.fireEvent('beforesync', this, html) !== false){
41377 this.el.dom.value = html;
41378 this.owner.fireEvent('sync', this, html);
41384 * Protected method that will not generally be called directly. Pushes the value of the textarea
41385 * into the iframe editor.
41387 pushValue : function(){
41388 if(this.initialized){
41389 var v = this.el.dom.value.trim();
41391 // if(v.length < 1){
41395 if(this.owner.fireEvent('beforepush', this, v) !== false){
41396 var d = (this.doc.body || this.doc.documentElement);
41398 this.cleanUpPaste();
41399 this.el.dom.value = d.innerHTML;
41400 this.owner.fireEvent('push', this, v);
41406 deferFocus : function(){
41407 this.focus.defer(10, this);
41411 focus : function(){
41412 if(this.win && !this.sourceEditMode){
41419 assignDocWin: function()
41421 var iframe = this.iframe;
41424 this.doc = iframe.contentWindow.document;
41425 this.win = iframe.contentWindow;
41427 // if (!Roo.get(this.frameId)) {
41430 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41431 // this.win = Roo.get(this.frameId).dom.contentWindow;
41433 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41437 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41438 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41443 initEditor : function(){
41444 //console.log("INIT EDITOR");
41445 this.assignDocWin();
41449 this.doc.designMode="on";
41451 this.doc.write(this.getDocMarkup());
41454 var dbody = (this.doc.body || this.doc.documentElement);
41455 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41456 // this copies styles from the containing element into thsi one..
41457 // not sure why we need all of this..
41458 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41460 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41461 //ss['background-attachment'] = 'fixed'; // w3c
41462 dbody.bgProperties = 'fixed'; // ie
41463 //Roo.DomHelper.applyStyles(dbody, ss);
41464 Roo.EventManager.on(this.doc, {
41465 //'mousedown': this.onEditorEvent,
41466 'mouseup': this.onEditorEvent,
41467 'dblclick': this.onEditorEvent,
41468 'click': this.onEditorEvent,
41469 'keyup': this.onEditorEvent,
41474 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41476 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41477 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41479 this.initialized = true;
41481 this.owner.fireEvent('initialize', this);
41486 onDestroy : function(){
41492 //for (var i =0; i < this.toolbars.length;i++) {
41493 // // fixme - ask toolbars for heights?
41494 // this.toolbars[i].onDestroy();
41497 //this.wrap.dom.innerHTML = '';
41498 //this.wrap.remove();
41503 onFirstFocus : function(){
41505 this.assignDocWin();
41508 this.activated = true;
41511 if(Roo.isGecko){ // prevent silly gecko errors
41513 var s = this.win.getSelection();
41514 if(!s.focusNode || s.focusNode.nodeType != 3){
41515 var r = s.getRangeAt(0);
41516 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41521 this.execCmd('useCSS', true);
41522 this.execCmd('styleWithCSS', false);
41525 this.owner.fireEvent('activate', this);
41529 adjustFont: function(btn){
41530 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41531 //if(Roo.isSafari){ // safari
41534 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41535 if(Roo.isSafari){ // safari
41536 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41537 v = (v < 10) ? 10 : v;
41538 v = (v > 48) ? 48 : v;
41539 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41544 v = Math.max(1, v+adjust);
41546 this.execCmd('FontSize', v );
41549 onEditorEvent : function(e){
41550 this.owner.fireEvent('editorevent', this, e);
41551 // this.updateToolbar();
41552 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41555 insertTag : function(tg)
41557 // could be a bit smarter... -> wrap the current selected tRoo..
41558 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41560 range = this.createRange(this.getSelection());
41561 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41562 wrappingNode.appendChild(range.extractContents());
41563 range.insertNode(wrappingNode);
41570 this.execCmd("formatblock", tg);
41574 insertText : function(txt)
41578 var range = this.createRange();
41579 range.deleteContents();
41580 //alert(Sender.getAttribute('label'));
41582 range.insertNode(this.doc.createTextNode(txt));
41588 * Executes a Midas editor command on the editor document and performs necessary focus and
41589 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41590 * @param {String} cmd The Midas command
41591 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41593 relayCmd : function(cmd, value){
41595 this.execCmd(cmd, value);
41596 this.owner.fireEvent('editorevent', this);
41597 //this.updateToolbar();
41598 this.owner.deferFocus();
41602 * Executes a Midas editor command directly on the editor document.
41603 * For visual commands, you should use {@link #relayCmd} instead.
41604 * <b>This should only be called after the editor is initialized.</b>
41605 * @param {String} cmd The Midas command
41606 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41608 execCmd : function(cmd, value){
41609 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41616 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41618 * @param {String} text | dom node..
41620 insertAtCursor : function(text)
41625 if(!this.activated){
41631 var r = this.doc.selection.createRange();
41642 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41646 // from jquery ui (MIT licenced)
41648 var win = this.win;
41650 if (win.getSelection && win.getSelection().getRangeAt) {
41651 range = win.getSelection().getRangeAt(0);
41652 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41653 range.insertNode(node);
41654 } else if (win.document.selection && win.document.selection.createRange) {
41655 // no firefox support
41656 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41657 win.document.selection.createRange().pasteHTML(txt);
41659 // no firefox support
41660 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41661 this.execCmd('InsertHTML', txt);
41670 mozKeyPress : function(e){
41672 var c = e.getCharCode(), cmd;
41675 c = String.fromCharCode(c).toLowerCase();
41689 this.cleanUpPaste.defer(100, this);
41697 e.preventDefault();
41705 fixKeys : function(){ // load time branching for fastest keydown performance
41707 return function(e){
41708 var k = e.getKey(), r;
41711 r = this.doc.selection.createRange();
41714 r.pasteHTML('    ');
41721 r = this.doc.selection.createRange();
41723 var target = r.parentElement();
41724 if(!target || target.tagName.toLowerCase() != 'li'){
41726 r.pasteHTML('<br />');
41732 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41733 this.cleanUpPaste.defer(100, this);
41739 }else if(Roo.isOpera){
41740 return function(e){
41741 var k = e.getKey();
41745 this.execCmd('InsertHTML','    ');
41748 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41749 this.cleanUpPaste.defer(100, this);
41754 }else if(Roo.isSafari){
41755 return function(e){
41756 var k = e.getKey();
41760 this.execCmd('InsertText','\t');
41764 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41765 this.cleanUpPaste.defer(100, this);
41773 getAllAncestors: function()
41775 var p = this.getSelectedNode();
41778 a.push(p); // push blank onto stack..
41779 p = this.getParentElement();
41783 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41787 a.push(this.doc.body);
41791 lastSelNode : false,
41794 getSelection : function()
41796 this.assignDocWin();
41797 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41800 getSelectedNode: function()
41802 // this may only work on Gecko!!!
41804 // should we cache this!!!!
41809 var range = this.createRange(this.getSelection()).cloneRange();
41812 var parent = range.parentElement();
41814 var testRange = range.duplicate();
41815 testRange.moveToElementText(parent);
41816 if (testRange.inRange(range)) {
41819 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41822 parent = parent.parentElement;
41827 // is ancestor a text element.
41828 var ac = range.commonAncestorContainer;
41829 if (ac.nodeType == 3) {
41830 ac = ac.parentNode;
41833 var ar = ac.childNodes;
41836 var other_nodes = [];
41837 var has_other_nodes = false;
41838 for (var i=0;i<ar.length;i++) {
41839 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41842 // fullly contained node.
41844 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41849 // probably selected..
41850 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41851 other_nodes.push(ar[i]);
41855 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41860 has_other_nodes = true;
41862 if (!nodes.length && other_nodes.length) {
41863 nodes= other_nodes;
41865 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41871 createRange: function(sel)
41873 // this has strange effects when using with
41874 // top toolbar - not sure if it's a great idea.
41875 //this.editor.contentWindow.focus();
41876 if (typeof sel != "undefined") {
41878 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41880 return this.doc.createRange();
41883 return this.doc.createRange();
41886 getParentElement: function()
41889 this.assignDocWin();
41890 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41892 var range = this.createRange(sel);
41895 var p = range.commonAncestorContainer;
41896 while (p.nodeType == 3) { // text node
41907 * Range intersection.. the hard stuff...
41911 * [ -- selected range --- ]
41915 * if end is before start or hits it. fail.
41916 * if start is after end or hits it fail.
41918 * if either hits (but other is outside. - then it's not
41924 // @see http://www.thismuchiknow.co.uk/?p=64.
41925 rangeIntersectsNode : function(range, node)
41927 var nodeRange = node.ownerDocument.createRange();
41929 nodeRange.selectNode(node);
41931 nodeRange.selectNodeContents(node);
41934 var rangeStartRange = range.cloneRange();
41935 rangeStartRange.collapse(true);
41937 var rangeEndRange = range.cloneRange();
41938 rangeEndRange.collapse(false);
41940 var nodeStartRange = nodeRange.cloneRange();
41941 nodeStartRange.collapse(true);
41943 var nodeEndRange = nodeRange.cloneRange();
41944 nodeEndRange.collapse(false);
41946 return rangeStartRange.compareBoundaryPoints(
41947 Range.START_TO_START, nodeEndRange) == -1 &&
41948 rangeEndRange.compareBoundaryPoints(
41949 Range.START_TO_START, nodeStartRange) == 1;
41953 rangeCompareNode : function(range, node)
41955 var nodeRange = node.ownerDocument.createRange();
41957 nodeRange.selectNode(node);
41959 nodeRange.selectNodeContents(node);
41963 range.collapse(true);
41965 nodeRange.collapse(true);
41967 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41968 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41970 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41972 var nodeIsBefore = ss == 1;
41973 var nodeIsAfter = ee == -1;
41975 if (nodeIsBefore && nodeIsAfter)
41977 if (!nodeIsBefore && nodeIsAfter)
41978 return 1; //right trailed.
41980 if (nodeIsBefore && !nodeIsAfter)
41981 return 2; // left trailed.
41986 // private? - in a new class?
41987 cleanUpPaste : function()
41989 // cleans up the whole document..
41990 Roo.log('cleanuppaste');
41992 this.cleanUpChildren(this.doc.body);
41993 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41994 if (clean != this.doc.body.innerHTML) {
41995 this.doc.body.innerHTML = clean;
42000 cleanWordChars : function(input) {// change the chars to hex code
42001 var he = Roo.HtmlEditorCore;
42003 var output = input;
42004 Roo.each(he.swapCodes, function(sw) {
42005 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42007 output = output.replace(swapper, sw[1]);
42014 cleanUpChildren : function (n)
42016 if (!n.childNodes.length) {
42019 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42020 this.cleanUpChild(n.childNodes[i]);
42027 cleanUpChild : function (node)
42030 //console.log(node);
42031 if (node.nodeName == "#text") {
42032 // clean up silly Windows -- stuff?
42035 if (node.nodeName == "#comment") {
42036 node.parentNode.removeChild(node);
42037 // clean up silly Windows -- stuff?
42040 var lcname = node.tagName.toLowerCase();
42041 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42042 // whitelist of tags..
42044 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42046 node.parentNode.removeChild(node);
42051 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42053 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42054 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42056 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42057 // remove_keep_children = true;
42060 if (remove_keep_children) {
42061 this.cleanUpChildren(node);
42062 // inserts everything just before this node...
42063 while (node.childNodes.length) {
42064 var cn = node.childNodes[0];
42065 node.removeChild(cn);
42066 node.parentNode.insertBefore(cn, node);
42068 node.parentNode.removeChild(node);
42072 if (!node.attributes || !node.attributes.length) {
42073 this.cleanUpChildren(node);
42077 function cleanAttr(n,v)
42080 if (v.match(/^\./) || v.match(/^\//)) {
42083 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42086 if (v.match(/^#/)) {
42089 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42090 node.removeAttribute(n);
42094 var cwhite = this.cwhite;
42095 var cblack = this.cblack;
42097 function cleanStyle(n,v)
42099 if (v.match(/expression/)) { //XSS?? should we even bother..
42100 node.removeAttribute(n);
42104 var parts = v.split(/;/);
42107 Roo.each(parts, function(p) {
42108 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42112 var l = p.split(':').shift().replace(/\s+/g,'');
42113 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42115 if ( cwhite.length && cblack.indexOf(l) > -1) {
42116 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42117 //node.removeAttribute(n);
42121 // only allow 'c whitelisted system attributes'
42122 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42123 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42124 //node.removeAttribute(n);
42134 if (clean.length) {
42135 node.setAttribute(n, clean.join(';'));
42137 node.removeAttribute(n);
42143 for (var i = node.attributes.length-1; i > -1 ; i--) {
42144 var a = node.attributes[i];
42147 if (a.name.toLowerCase().substr(0,2)=='on') {
42148 node.removeAttribute(a.name);
42151 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42152 node.removeAttribute(a.name);
42155 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42156 cleanAttr(a.name,a.value); // fixme..
42159 if (a.name == 'style') {
42160 cleanStyle(a.name,a.value);
42163 /// clean up MS crap..
42164 // tecnically this should be a list of valid class'es..
42167 if (a.name == 'class') {
42168 if (a.value.match(/^Mso/)) {
42169 node.className = '';
42172 if (a.value.match(/body/)) {
42173 node.className = '';
42184 this.cleanUpChildren(node);
42189 * Clean up MS wordisms...
42191 cleanWord : function(node)
42194 var cleanWordChildren = function()
42196 if (!node.childNodes.length) {
42199 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42200 _t.cleanWord(node.childNodes[i]);
42206 this.cleanWord(this.doc.body);
42209 if (node.nodeName == "#text") {
42210 // clean up silly Windows -- stuff?
42213 if (node.nodeName == "#comment") {
42214 node.parentNode.removeChild(node);
42215 // clean up silly Windows -- stuff?
42219 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42220 node.parentNode.removeChild(node);
42224 // remove - but keep children..
42225 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42226 while (node.childNodes.length) {
42227 var cn = node.childNodes[0];
42228 node.removeChild(cn);
42229 node.parentNode.insertBefore(cn, node);
42231 node.parentNode.removeChild(node);
42232 cleanWordChildren();
42236 if (node.className.length) {
42238 var cn = node.className.split(/\W+/);
42240 Roo.each(cn, function(cls) {
42241 if (cls.match(/Mso[a-zA-Z]+/)) {
42246 node.className = cna.length ? cna.join(' ') : '';
42248 node.removeAttribute("class");
42252 if (node.hasAttribute("lang")) {
42253 node.removeAttribute("lang");
42256 if (node.hasAttribute("style")) {
42258 var styles = node.getAttribute("style").split(";");
42260 Roo.each(styles, function(s) {
42261 if (!s.match(/:/)) {
42264 var kv = s.split(":");
42265 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42268 // what ever is left... we allow.
42271 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42272 if (!nstyle.length) {
42273 node.removeAttribute('style');
42277 cleanWordChildren();
42281 domToHTML : function(currentElement, depth, nopadtext) {
42283 depth = depth || 0;
42284 nopadtext = nopadtext || false;
42286 if (!currentElement) {
42287 return this.domToHTML(this.doc.body);
42290 //Roo.log(currentElement);
42292 var allText = false;
42293 var nodeName = currentElement.nodeName;
42294 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42296 if (nodeName == '#text') {
42297 return currentElement.nodeValue;
42302 if (nodeName != 'BODY') {
42305 // Prints the node tagName, such as <A>, <IMG>, etc
42308 for(i = 0; i < currentElement.attributes.length;i++) {
42310 var aname = currentElement.attributes.item(i).name;
42311 if (!currentElement.attributes.item(i).value.length) {
42314 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42317 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42326 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42329 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42334 // Traverse the tree
42336 var currentElementChild = currentElement.childNodes.item(i);
42337 var allText = true;
42338 var innerHTML = '';
42340 while (currentElementChild) {
42341 // Formatting code (indent the tree so it looks nice on the screen)
42342 var nopad = nopadtext;
42343 if (lastnode == 'SPAN') {
42347 if (currentElementChild.nodeName == '#text') {
42348 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42349 if (!nopad && toadd.length > 80) {
42350 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42352 innerHTML += toadd;
42355 currentElementChild = currentElement.childNodes.item(i);
42361 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42363 // Recursively traverse the tree structure of the child node
42364 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42365 lastnode = currentElementChild.nodeName;
42367 currentElementChild=currentElement.childNodes.item(i);
42373 // The remaining code is mostly for formatting the tree
42374 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42379 ret+= "</"+tagName+">";
42385 applyBlacklists : function()
42387 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42388 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42392 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42393 if (b.indexOf(tag) > -1) {
42396 this.white.push(tag);
42400 Roo.each(w, function(tag) {
42401 if (b.indexOf(tag) > -1) {
42404 if (this.white.indexOf(tag) > -1) {
42407 this.white.push(tag);
42412 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42413 if (w.indexOf(tag) > -1) {
42416 this.black.push(tag);
42420 Roo.each(b, function(tag) {
42421 if (w.indexOf(tag) > -1) {
42424 if (this.black.indexOf(tag) > -1) {
42427 this.black.push(tag);
42432 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42433 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42437 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42438 if (b.indexOf(tag) > -1) {
42441 this.cwhite.push(tag);
42445 Roo.each(w, function(tag) {
42446 if (b.indexOf(tag) > -1) {
42449 if (this.cwhite.indexOf(tag) > -1) {
42452 this.cwhite.push(tag);
42457 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42458 if (w.indexOf(tag) > -1) {
42461 this.cblack.push(tag);
42465 Roo.each(b, function(tag) {
42466 if (w.indexOf(tag) > -1) {
42469 if (this.cblack.indexOf(tag) > -1) {
42472 this.cblack.push(tag);
42477 // hide stuff that is not compatible
42491 * @event specialkey
42495 * @cfg {String} fieldClass @hide
42498 * @cfg {String} focusClass @hide
42501 * @cfg {String} autoCreate @hide
42504 * @cfg {String} inputType @hide
42507 * @cfg {String} invalidClass @hide
42510 * @cfg {String} invalidText @hide
42513 * @cfg {String} msgFx @hide
42516 * @cfg {String} validateOnBlur @hide
42520 Roo.HtmlEditorCore.white = [
42521 'area', 'br', 'img', 'input', 'hr', 'wbr',
42523 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42524 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42525 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42526 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42527 'table', 'ul', 'xmp',
42529 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42532 'dir', 'menu', 'ol', 'ul', 'dl',
42538 Roo.HtmlEditorCore.black = [
42539 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42541 'base', 'basefont', 'bgsound', 'blink', 'body',
42542 'frame', 'frameset', 'head', 'html', 'ilayer',
42543 'iframe', 'layer', 'link', 'meta', 'object',
42544 'script', 'style' ,'title', 'xml' // clean later..
42546 Roo.HtmlEditorCore.clean = [
42547 'script', 'style', 'title', 'xml'
42549 Roo.HtmlEditorCore.remove = [
42554 Roo.HtmlEditorCore.ablack = [
42558 Roo.HtmlEditorCore.aclean = [
42559 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42563 Roo.HtmlEditorCore.pwhite= [
42564 'http', 'https', 'mailto'
42567 // white listed style attributes.
42568 Roo.HtmlEditorCore.cwhite= [
42569 // 'text-align', /// default is to allow most things..
42575 // black listed style attributes.
42576 Roo.HtmlEditorCore.cblack= [
42577 // 'font-size' -- this can be set by the project
42581 Roo.HtmlEditorCore.swapCodes =[
42592 //<script type="text/javascript">
42595 * Ext JS Library 1.1.1
42596 * Copyright(c) 2006-2007, Ext JS, LLC.
42602 Roo.form.HtmlEditor = function(config){
42606 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42608 if (!this.toolbars) {
42609 this.toolbars = [];
42611 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42617 * @class Roo.form.HtmlEditor
42618 * @extends Roo.form.Field
42619 * Provides a lightweight HTML Editor component.
42621 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42623 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42624 * supported by this editor.</b><br/><br/>
42625 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42626 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42628 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42630 * @cfg {Boolean} clearUp
42634 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42639 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42644 * @cfg {Number} height (in pixels)
42648 * @cfg {Number} width (in pixels)
42653 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42656 stylesheets: false,
42660 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42665 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42671 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42676 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42684 // private properties
42685 validationEvent : false,
42687 initialized : false,
42690 onFocus : Roo.emptyFn,
42692 hideMode:'offsets',
42694 actionMode : 'container', // defaults to hiding it...
42696 defaultAutoCreate : { // modified by initCompnoent..
42698 style:"width:500px;height:300px;",
42699 autocomplete: "off"
42703 initComponent : function(){
42706 * @event initialize
42707 * Fires when the editor is fully initialized (including the iframe)
42708 * @param {HtmlEditor} this
42713 * Fires when the editor is first receives the focus. Any insertion must wait
42714 * until after this event.
42715 * @param {HtmlEditor} this
42719 * @event beforesync
42720 * Fires before the textarea is updated with content from the editor iframe. Return false
42721 * to cancel the sync.
42722 * @param {HtmlEditor} this
42723 * @param {String} html
42727 * @event beforepush
42728 * Fires before the iframe editor is updated with content from the textarea. Return false
42729 * to cancel the push.
42730 * @param {HtmlEditor} this
42731 * @param {String} html
42736 * Fires when the textarea is updated with content from the editor iframe.
42737 * @param {HtmlEditor} this
42738 * @param {String} html
42743 * Fires when the iframe editor is updated with content from the textarea.
42744 * @param {HtmlEditor} this
42745 * @param {String} html
42749 * @event editmodechange
42750 * Fires when the editor switches edit modes
42751 * @param {HtmlEditor} this
42752 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42754 editmodechange: true,
42756 * @event editorevent
42757 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42758 * @param {HtmlEditor} this
42762 * @event firstfocus
42763 * Fires when on first focus - needed by toolbars..
42764 * @param {HtmlEditor} this
42769 * Auto save the htmlEditor value as a file into Events
42770 * @param {HtmlEditor} this
42774 * @event savedpreview
42775 * preview the saved version of htmlEditor
42776 * @param {HtmlEditor} this
42780 this.defaultAutoCreate = {
42782 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42783 autocomplete: "off"
42788 * Protected method that will not generally be called directly. It
42789 * is called when the editor creates its toolbar. Override this method if you need to
42790 * add custom toolbar buttons.
42791 * @param {HtmlEditor} editor
42793 createToolbar : function(editor){
42794 Roo.log("create toolbars");
42795 if (!editor.toolbars || !editor.toolbars.length) {
42796 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42799 for (var i =0 ; i < editor.toolbars.length;i++) {
42800 editor.toolbars[i] = Roo.factory(
42801 typeof(editor.toolbars[i]) == 'string' ?
42802 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42803 Roo.form.HtmlEditor);
42804 editor.toolbars[i].init(editor);
42812 onRender : function(ct, position)
42815 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42817 this.wrap = this.el.wrap({
42818 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42821 this.editorcore.onRender(ct, position);
42823 if (this.resizable) {
42824 this.resizeEl = new Roo.Resizable(this.wrap, {
42828 minHeight : this.height,
42829 height: this.height,
42830 handles : this.resizable,
42833 resize : function(r, w, h) {
42834 _t.onResize(w,h); // -something
42840 this.createToolbar(this);
42844 this.setSize(this.wrap.getSize());
42846 if (this.resizeEl) {
42847 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42848 // should trigger onReize..
42851 // if(this.autosave && this.w){
42852 // this.autoSaveFn = setInterval(this.autosave, 1000);
42857 onResize : function(w, h)
42859 //Roo.log('resize: ' +w + ',' + h );
42860 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42865 if(typeof w == 'number'){
42866 var aw = w - this.wrap.getFrameWidth('lr');
42867 this.el.setWidth(this.adjustWidth('textarea', aw));
42870 if(typeof h == 'number'){
42872 for (var i =0; i < this.toolbars.length;i++) {
42873 // fixme - ask toolbars for heights?
42874 tbh += this.toolbars[i].tb.el.getHeight();
42875 if (this.toolbars[i].footer) {
42876 tbh += this.toolbars[i].footer.el.getHeight();
42883 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42884 ah -= 5; // knock a few pixes off for look..
42885 this.el.setHeight(this.adjustWidth('textarea', ah));
42889 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42890 this.editorcore.onResize(ew,eh);
42895 * Toggles the editor between standard and source edit mode.
42896 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42898 toggleSourceEdit : function(sourceEditMode)
42900 this.editorcore.toggleSourceEdit(sourceEditMode);
42902 if(this.editorcore.sourceEditMode){
42903 Roo.log('editor - showing textarea');
42906 // Roo.log(this.syncValue());
42907 this.editorcore.syncValue();
42908 this.el.removeClass('x-hidden');
42909 this.el.dom.removeAttribute('tabIndex');
42912 Roo.log('editor - hiding textarea');
42914 // Roo.log(this.pushValue());
42915 this.editorcore.pushValue();
42917 this.el.addClass('x-hidden');
42918 this.el.dom.setAttribute('tabIndex', -1);
42919 //this.deferFocus();
42922 this.setSize(this.wrap.getSize());
42923 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42926 // private (for BoxComponent)
42927 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42929 // private (for BoxComponent)
42930 getResizeEl : function(){
42934 // private (for BoxComponent)
42935 getPositionEl : function(){
42940 initEvents : function(){
42941 this.originalValue = this.getValue();
42945 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42948 markInvalid : Roo.emptyFn,
42950 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42953 clearInvalid : Roo.emptyFn,
42955 setValue : function(v){
42956 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42957 this.editorcore.pushValue();
42962 deferFocus : function(){
42963 this.focus.defer(10, this);
42967 focus : function(){
42968 this.editorcore.focus();
42974 onDestroy : function(){
42980 for (var i =0; i < this.toolbars.length;i++) {
42981 // fixme - ask toolbars for heights?
42982 this.toolbars[i].onDestroy();
42985 this.wrap.dom.innerHTML = '';
42986 this.wrap.remove();
42991 onFirstFocus : function(){
42992 //Roo.log("onFirstFocus");
42993 this.editorcore.onFirstFocus();
42994 for (var i =0; i < this.toolbars.length;i++) {
42995 this.toolbars[i].onFirstFocus();
43001 syncValue : function()
43003 this.editorcore.syncValue();
43006 pushValue : function()
43008 this.editorcore.pushValue();
43012 // hide stuff that is not compatible
43026 * @event specialkey
43030 * @cfg {String} fieldClass @hide
43033 * @cfg {String} focusClass @hide
43036 * @cfg {String} autoCreate @hide
43039 * @cfg {String} inputType @hide
43042 * @cfg {String} invalidClass @hide
43045 * @cfg {String} invalidText @hide
43048 * @cfg {String} msgFx @hide
43051 * @cfg {String} validateOnBlur @hide
43055 // <script type="text/javascript">
43058 * Ext JS Library 1.1.1
43059 * Copyright(c) 2006-2007, Ext JS, LLC.
43065 * @class Roo.form.HtmlEditorToolbar1
43070 new Roo.form.HtmlEditor({
43073 new Roo.form.HtmlEditorToolbar1({
43074 disable : { fonts: 1 , format: 1, ..., ... , ...],
43080 * @cfg {Object} disable List of elements to disable..
43081 * @cfg {Array} btns List of additional buttons.
43085 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43088 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43091 Roo.apply(this, config);
43093 // default disabled, based on 'good practice'..
43094 this.disable = this.disable || {};
43095 Roo.applyIf(this.disable, {
43098 specialElements : true
43102 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43103 // dont call parent... till later.
43106 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43113 editorcore : false,
43115 * @cfg {Object} disable List of toolbar elements to disable
43122 * @cfg {String} createLinkText The default text for the create link prompt
43124 createLinkText : 'Please enter the URL for the link:',
43126 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43128 defaultLinkValue : 'http:/'+'/',
43132 * @cfg {Array} fontFamilies An array of available font families
43150 // "á" , ?? a acute?
43155 "°" // , // degrees
43157 // "é" , // e ecute
43158 // "ú" , // u ecute?
43161 specialElements : [
43163 text: "Insert Table",
43166 ihtml : '<table><tr><td>Cell</td></tr></table>'
43170 text: "Insert Image",
43173 ihtml : '<img src="about:blank"/>'
43182 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43183 "input:submit", "input:button", "select", "textarea", "label" ],
43186 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43188 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43196 * @cfg {String} defaultFont default font to use.
43198 defaultFont: 'tahoma',
43200 fontSelect : false,
43203 formatCombo : false,
43205 init : function(editor)
43207 this.editor = editor;
43208 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43209 var editorcore = this.editorcore;
43213 var fid = editorcore.frameId;
43215 function btn(id, toggle, handler){
43216 var xid = fid + '-'+ id ;
43220 cls : 'x-btn-icon x-edit-'+id,
43221 enableToggle:toggle !== false,
43222 scope: _t, // was editor...
43223 handler:handler||_t.relayBtnCmd,
43224 clickEvent:'mousedown',
43225 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43232 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43234 // stop form submits
43235 tb.el.on('click', function(e){
43236 e.preventDefault(); // what does this do?
43239 if(!this.disable.font) { // && !Roo.isSafari){
43240 /* why no safari for fonts
43241 editor.fontSelect = tb.el.createChild({
43244 cls:'x-font-select',
43245 html: this.createFontOptions()
43248 editor.fontSelect.on('change', function(){
43249 var font = editor.fontSelect.dom.value;
43250 editor.relayCmd('fontname', font);
43251 editor.deferFocus();
43255 editor.fontSelect.dom,
43261 if(!this.disable.formats){
43262 this.formatCombo = new Roo.form.ComboBox({
43263 store: new Roo.data.SimpleStore({
43266 data : this.formats // from states.js
43270 //autoCreate : {tag: "div", size: "20"},
43271 displayField:'tag',
43275 triggerAction: 'all',
43276 emptyText:'Add tag',
43277 selectOnFocus:true,
43280 'select': function(c, r, i) {
43281 editorcore.insertTag(r.get('tag'));
43287 tb.addField(this.formatCombo);
43291 if(!this.disable.format){
43298 if(!this.disable.fontSize){
43303 btn('increasefontsize', false, editorcore.adjustFont),
43304 btn('decreasefontsize', false, editorcore.adjustFont)
43309 if(!this.disable.colors){
43312 id:editorcore.frameId +'-forecolor',
43313 cls:'x-btn-icon x-edit-forecolor',
43314 clickEvent:'mousedown',
43315 tooltip: this.buttonTips['forecolor'] || undefined,
43317 menu : new Roo.menu.ColorMenu({
43318 allowReselect: true,
43319 focus: Roo.emptyFn,
43322 selectHandler: function(cp, color){
43323 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43324 editor.deferFocus();
43327 clickEvent:'mousedown'
43330 id:editorcore.frameId +'backcolor',
43331 cls:'x-btn-icon x-edit-backcolor',
43332 clickEvent:'mousedown',
43333 tooltip: this.buttonTips['backcolor'] || undefined,
43335 menu : new Roo.menu.ColorMenu({
43336 focus: Roo.emptyFn,
43339 allowReselect: true,
43340 selectHandler: function(cp, color){
43342 editorcore.execCmd('useCSS', false);
43343 editorcore.execCmd('hilitecolor', color);
43344 editorcore.execCmd('useCSS', true);
43345 editor.deferFocus();
43347 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43348 Roo.isSafari || Roo.isIE ? '#'+color : color);
43349 editor.deferFocus();
43353 clickEvent:'mousedown'
43358 // now add all the items...
43361 if(!this.disable.alignments){
43364 btn('justifyleft'),
43365 btn('justifycenter'),
43366 btn('justifyright')
43370 //if(!Roo.isSafari){
43371 if(!this.disable.links){
43374 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43378 if(!this.disable.lists){
43381 btn('insertorderedlist'),
43382 btn('insertunorderedlist')
43385 if(!this.disable.sourceEdit){
43388 btn('sourceedit', true, function(btn){
43390 this.toggleSourceEdit(btn.pressed);
43397 // special menu.. - needs to be tidied up..
43398 if (!this.disable.special) {
43401 cls: 'x-edit-none',
43407 for (var i =0; i < this.specialChars.length; i++) {
43408 smenu.menu.items.push({
43410 html: this.specialChars[i],
43411 handler: function(a,b) {
43412 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43413 //editor.insertAtCursor(a.html);
43427 if (!this.disable.cleanStyles) {
43429 cls: 'x-btn-icon x-btn-clear',
43435 for (var i =0; i < this.cleanStyles.length; i++) {
43436 cmenu.menu.items.push({
43437 actiontype : this.cleanStyles[i],
43438 html: 'Remove ' + this.cleanStyles[i],
43439 handler: function(a,b) {
43442 var c = Roo.get(editorcore.doc.body);
43443 c.select('[style]').each(function(s) {
43444 s.dom.style.removeProperty(a.actiontype);
43446 editorcore.syncValue();
43451 cmenu.menu.items.push({
43452 actiontype : 'word',
43453 html: 'Remove MS Word Formating',
43454 handler: function(a,b) {
43455 editorcore.cleanWord();
43456 editorcore.syncValue();
43461 cmenu.menu.items.push({
43462 actiontype : 'all',
43463 html: 'Remove All Styles',
43464 handler: function(a,b) {
43466 var c = Roo.get(editorcore.doc.body);
43467 c.select('[style]').each(function(s) {
43468 s.dom.removeAttribute('style');
43470 editorcore.syncValue();
43474 cmenu.menu.items.push({
43475 actiontype : 'word',
43476 html: 'Tidy HTML Source',
43477 handler: function(a,b) {
43478 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43479 editorcore.syncValue();
43488 if (!this.disable.specialElements) {
43491 cls: 'x-edit-none',
43496 for (var i =0; i < this.specialElements.length; i++) {
43497 semenu.menu.items.push(
43499 handler: function(a,b) {
43500 editor.insertAtCursor(this.ihtml);
43502 }, this.specialElements[i])
43514 for(var i =0; i< this.btns.length;i++) {
43515 var b = Roo.factory(this.btns[i],Roo.form);
43516 b.cls = 'x-edit-none';
43517 b.scope = editorcore;
43525 // disable everything...
43527 this.tb.items.each(function(item){
43528 if(item.id != editorcore.frameId+ '-sourceedit'){
43532 this.rendered = true;
43534 // the all the btns;
43535 editor.on('editorevent', this.updateToolbar, this);
43536 // other toolbars need to implement this..
43537 //editor.on('editmodechange', this.updateToolbar, this);
43541 relayBtnCmd : function(btn) {
43542 this.editorcore.relayCmd(btn.cmd);
43544 // private used internally
43545 createLink : function(){
43546 Roo.log("create link?");
43547 var url = prompt(this.createLinkText, this.defaultLinkValue);
43548 if(url && url != 'http:/'+'/'){
43549 this.editorcore.relayCmd('createlink', url);
43555 * Protected method that will not generally be called directly. It triggers
43556 * a toolbar update by reading the markup state of the current selection in the editor.
43558 updateToolbar: function(){
43560 if(!this.editorcore.activated){
43561 this.editor.onFirstFocus();
43565 var btns = this.tb.items.map,
43566 doc = this.editorcore.doc,
43567 frameId = this.editorcore.frameId;
43569 if(!this.disable.font && !Roo.isSafari){
43571 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43572 if(name != this.fontSelect.dom.value){
43573 this.fontSelect.dom.value = name;
43577 if(!this.disable.format){
43578 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43579 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43580 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43582 if(!this.disable.alignments){
43583 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43584 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43585 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43587 if(!Roo.isSafari && !this.disable.lists){
43588 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43589 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43592 var ans = this.editorcore.getAllAncestors();
43593 if (this.formatCombo) {
43596 var store = this.formatCombo.store;
43597 this.formatCombo.setValue("");
43598 for (var i =0; i < ans.length;i++) {
43599 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43601 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43609 // hides menus... - so this cant be on a menu...
43610 Roo.menu.MenuMgr.hideAll();
43612 //this.editorsyncValue();
43616 createFontOptions : function(){
43617 var buf = [], fs = this.fontFamilies, ff, lc;
43621 for(var i = 0, len = fs.length; i< len; i++){
43623 lc = ff.toLowerCase();
43625 '<option value="',lc,'" style="font-family:',ff,';"',
43626 (this.defaultFont == lc ? ' selected="true">' : '>'),
43631 return buf.join('');
43634 toggleSourceEdit : function(sourceEditMode){
43636 Roo.log("toolbar toogle");
43637 if(sourceEditMode === undefined){
43638 sourceEditMode = !this.sourceEditMode;
43640 this.sourceEditMode = sourceEditMode === true;
43641 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43642 // just toggle the button?
43643 if(btn.pressed !== this.sourceEditMode){
43644 btn.toggle(this.sourceEditMode);
43648 if(sourceEditMode){
43649 Roo.log("disabling buttons");
43650 this.tb.items.each(function(item){
43651 if(item.cmd != 'sourceedit'){
43657 Roo.log("enabling buttons");
43658 if(this.editorcore.initialized){
43659 this.tb.items.each(function(item){
43665 Roo.log("calling toggole on editor");
43666 // tell the editor that it's been pressed..
43667 this.editor.toggleSourceEdit(sourceEditMode);
43671 * Object collection of toolbar tooltips for the buttons in the editor. The key
43672 * is the command id associated with that button and the value is a valid QuickTips object.
43677 title: 'Bold (Ctrl+B)',
43678 text: 'Make the selected text bold.',
43679 cls: 'x-html-editor-tip'
43682 title: 'Italic (Ctrl+I)',
43683 text: 'Make the selected text italic.',
43684 cls: 'x-html-editor-tip'
43692 title: 'Bold (Ctrl+B)',
43693 text: 'Make the selected text bold.',
43694 cls: 'x-html-editor-tip'
43697 title: 'Italic (Ctrl+I)',
43698 text: 'Make the selected text italic.',
43699 cls: 'x-html-editor-tip'
43702 title: 'Underline (Ctrl+U)',
43703 text: 'Underline the selected text.',
43704 cls: 'x-html-editor-tip'
43706 increasefontsize : {
43707 title: 'Grow Text',
43708 text: 'Increase the font size.',
43709 cls: 'x-html-editor-tip'
43711 decreasefontsize : {
43712 title: 'Shrink Text',
43713 text: 'Decrease the font size.',
43714 cls: 'x-html-editor-tip'
43717 title: 'Text Highlight Color',
43718 text: 'Change the background color of the selected text.',
43719 cls: 'x-html-editor-tip'
43722 title: 'Font Color',
43723 text: 'Change the color of the selected text.',
43724 cls: 'x-html-editor-tip'
43727 title: 'Align Text Left',
43728 text: 'Align text to the left.',
43729 cls: 'x-html-editor-tip'
43732 title: 'Center Text',
43733 text: 'Center text in the editor.',
43734 cls: 'x-html-editor-tip'
43737 title: 'Align Text Right',
43738 text: 'Align text to the right.',
43739 cls: 'x-html-editor-tip'
43741 insertunorderedlist : {
43742 title: 'Bullet List',
43743 text: 'Start a bulleted list.',
43744 cls: 'x-html-editor-tip'
43746 insertorderedlist : {
43747 title: 'Numbered List',
43748 text: 'Start a numbered list.',
43749 cls: 'x-html-editor-tip'
43752 title: 'Hyperlink',
43753 text: 'Make the selected text a hyperlink.',
43754 cls: 'x-html-editor-tip'
43757 title: 'Source Edit',
43758 text: 'Switch to source editing mode.',
43759 cls: 'x-html-editor-tip'
43763 onDestroy : function(){
43766 this.tb.items.each(function(item){
43768 item.menu.removeAll();
43770 item.menu.el.destroy();
43778 onFirstFocus: function() {
43779 this.tb.items.each(function(item){
43788 // <script type="text/javascript">
43791 * Ext JS Library 1.1.1
43792 * Copyright(c) 2006-2007, Ext JS, LLC.
43799 * @class Roo.form.HtmlEditor.ToolbarContext
43804 new Roo.form.HtmlEditor({
43807 { xtype: 'ToolbarStandard', styles : {} }
43808 { xtype: 'ToolbarContext', disable : {} }
43814 * @config : {Object} disable List of elements to disable.. (not done yet.)
43815 * @config : {Object} styles Map of styles available.
43819 Roo.form.HtmlEditor.ToolbarContext = function(config)
43822 Roo.apply(this, config);
43823 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43824 // dont call parent... till later.
43825 this.styles = this.styles || {};
43830 Roo.form.HtmlEditor.ToolbarContext.types = {
43842 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43908 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43913 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43923 style : 'fontFamily',
43924 displayField: 'display',
43925 optname : 'font-family',
43974 // should we really allow this??
43975 // should this just be
43986 style : 'fontFamily',
43987 displayField: 'display',
43988 optname : 'font-family',
43995 style : 'fontFamily',
43996 displayField: 'display',
43997 optname : 'font-family',
44004 style : 'fontFamily',
44005 displayField: 'display',
44006 optname : 'font-family',
44017 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44018 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44020 Roo.form.HtmlEditor.ToolbarContext.options = {
44022 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44023 [ 'Courier New', 'Courier New'],
44024 [ 'Tahoma', 'Tahoma'],
44025 [ 'Times New Roman,serif', 'Times'],
44026 [ 'Verdana','Verdana' ]
44030 // fixme - these need to be configurable..
44033 Roo.form.HtmlEditor.ToolbarContext.types
44036 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44043 editorcore : false,
44045 * @cfg {Object} disable List of toolbar elements to disable
44050 * @cfg {Object} styles List of styles
44051 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44053 * These must be defined in the page, so they get rendered correctly..
44064 init : function(editor)
44066 this.editor = editor;
44067 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44068 var editorcore = this.editorcore;
44070 var fid = editorcore.frameId;
44072 function btn(id, toggle, handler){
44073 var xid = fid + '-'+ id ;
44077 cls : 'x-btn-icon x-edit-'+id,
44078 enableToggle:toggle !== false,
44079 scope: editorcore, // was editor...
44080 handler:handler||editorcore.relayBtnCmd,
44081 clickEvent:'mousedown',
44082 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44086 // create a new element.
44087 var wdiv = editor.wrap.createChild({
44089 }, editor.wrap.dom.firstChild.nextSibling, true);
44091 // can we do this more than once??
44093 // stop form submits
44096 // disable everything...
44097 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44098 this.toolbars = {};
44100 for (var i in ty) {
44102 this.toolbars[i] = this.buildToolbar(ty[i],i);
44104 this.tb = this.toolbars.BODY;
44106 this.buildFooter();
44107 this.footer.show();
44108 editor.on('hide', function( ) { this.footer.hide() }, this);
44109 editor.on('show', function( ) { this.footer.show() }, this);
44112 this.rendered = true;
44114 // the all the btns;
44115 editor.on('editorevent', this.updateToolbar, this);
44116 // other toolbars need to implement this..
44117 //editor.on('editmodechange', this.updateToolbar, this);
44123 * Protected method that will not generally be called directly. It triggers
44124 * a toolbar update by reading the markup state of the current selection in the editor.
44126 updateToolbar: function(editor,ev,sel){
44129 // capture mouse up - this is handy for selecting images..
44130 // perhaps should go somewhere else...
44131 if(!this.editorcore.activated){
44132 this.editor.onFirstFocus();
44136 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44137 // selectNode - might want to handle IE?
44139 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44140 ev.target && ev.target.tagName == 'IMG') {
44141 // they have click on an image...
44142 // let's see if we can change the selection...
44145 var nodeRange = sel.ownerDocument.createRange();
44147 nodeRange.selectNode(sel);
44149 nodeRange.selectNodeContents(sel);
44151 //nodeRange.collapse(true);
44152 var s = this.editorcore.win.getSelection();
44153 s.removeAllRanges();
44154 s.addRange(nodeRange);
44158 var updateFooter = sel ? false : true;
44161 var ans = this.editorcore.getAllAncestors();
44164 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44167 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44168 sel = sel ? sel : this.editorcore.doc.body;
44169 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44172 // pick a menu that exists..
44173 var tn = sel.tagName.toUpperCase();
44174 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44176 tn = sel.tagName.toUpperCase();
44178 var lastSel = this.tb.selectedNode
44180 this.tb.selectedNode = sel;
44182 // if current menu does not match..
44183 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
44186 ///console.log("show: " + tn);
44187 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44190 this.tb.items.first().el.innerHTML = tn + ': ';
44193 // update attributes
44194 if (this.tb.fields) {
44195 this.tb.fields.each(function(e) {
44197 e.setValue(sel.style[e.stylename]);
44200 e.setValue(sel.getAttribute(e.attrname));
44204 var hasStyles = false;
44205 for(var i in this.styles) {
44212 var st = this.tb.fields.item(0);
44214 st.store.removeAll();
44217 var cn = sel.className.split(/\s+/);
44220 if (this.styles['*']) {
44222 Roo.each(this.styles['*'], function(v) {
44223 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44226 if (this.styles[tn]) {
44227 Roo.each(this.styles[tn], function(v) {
44228 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44232 st.store.loadData(avs);
44236 // flag our selected Node.
44237 this.tb.selectedNode = sel;
44240 Roo.menu.MenuMgr.hideAll();
44244 if (!updateFooter) {
44245 //this.footDisp.dom.innerHTML = '';
44248 // update the footer
44252 this.footerEls = ans.reverse();
44253 Roo.each(this.footerEls, function(a,i) {
44254 if (!a) { return; }
44255 html += html.length ? ' > ' : '';
44257 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44262 var sz = this.footDisp.up('td').getSize();
44263 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44264 this.footDisp.dom.style.marginLeft = '5px';
44266 this.footDisp.dom.style.overflow = 'hidden';
44268 this.footDisp.dom.innerHTML = html;
44270 //this.editorsyncValue();
44277 onDestroy : function(){
44280 this.tb.items.each(function(item){
44282 item.menu.removeAll();
44284 item.menu.el.destroy();
44292 onFirstFocus: function() {
44293 // need to do this for all the toolbars..
44294 this.tb.items.each(function(item){
44298 buildToolbar: function(tlist, nm)
44300 var editor = this.editor;
44301 var editorcore = this.editorcore;
44302 // create a new element.
44303 var wdiv = editor.wrap.createChild({
44305 }, editor.wrap.dom.firstChild.nextSibling, true);
44308 var tb = new Roo.Toolbar(wdiv);
44311 tb.add(nm+ ": ");
44314 for(var i in this.styles) {
44319 if (styles && styles.length) {
44321 // this needs a multi-select checkbox...
44322 tb.addField( new Roo.form.ComboBox({
44323 store: new Roo.data.SimpleStore({
44325 fields: ['val', 'selected'],
44328 name : '-roo-edit-className',
44329 attrname : 'className',
44330 displayField: 'val',
44334 triggerAction: 'all',
44335 emptyText:'Select Style',
44336 selectOnFocus:true,
44339 'select': function(c, r, i) {
44340 // initial support only for on class per el..
44341 tb.selectedNode.className = r ? r.get('val') : '';
44342 editorcore.syncValue();
44349 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44350 var tbops = tbc.options;
44352 for (var i in tlist) {
44354 var item = tlist[i];
44355 tb.add(item.title + ": ");
44358 //optname == used so you can configure the options available..
44359 var opts = item.opts ? item.opts : false;
44360 if (item.optname) {
44361 opts = tbops[item.optname];
44366 // opts == pulldown..
44367 tb.addField( new Roo.form.ComboBox({
44368 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44370 fields: ['val', 'display'],
44373 name : '-roo-edit-' + i,
44375 stylename : item.style ? item.style : false,
44376 displayField: item.displayField ? item.displayField : 'val',
44377 valueField : 'val',
44379 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44381 triggerAction: 'all',
44382 emptyText:'Select',
44383 selectOnFocus:true,
44384 width: item.width ? item.width : 130,
44386 'select': function(c, r, i) {
44388 tb.selectedNode.style[c.stylename] = r.get('val');
44391 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44400 tb.addField( new Roo.form.TextField({
44403 //allowBlank:false,
44408 tb.addField( new Roo.form.TextField({
44409 name: '-roo-edit-' + i,
44416 'change' : function(f, nv, ov) {
44417 tb.selectedNode.setAttribute(f.attrname, nv);
44426 text: 'Remove Tag',
44429 click : function ()
44432 // undo does not work.
44434 var sn = tb.selectedNode;
44436 var pn = sn.parentNode;
44438 var stn = sn.childNodes[0];
44439 var en = sn.childNodes[sn.childNodes.length - 1 ];
44440 while (sn.childNodes.length) {
44441 var node = sn.childNodes[0];
44442 sn.removeChild(node);
44444 pn.insertBefore(node, sn);
44447 pn.removeChild(sn);
44448 var range = editorcore.createRange();
44450 range.setStart(stn,0);
44451 range.setEnd(en,0); //????
44452 //range.selectNode(sel);
44455 var selection = editorcore.getSelection();
44456 selection.removeAllRanges();
44457 selection.addRange(range);
44461 //_this.updateToolbar(null, null, pn);
44462 _this.updateToolbar(null, null, null);
44463 _this.footDisp.dom.innerHTML = '';
44473 tb.el.on('click', function(e){
44474 e.preventDefault(); // what does this do?
44476 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44479 // dont need to disable them... as they will get hidden
44484 buildFooter : function()
44487 var fel = this.editor.wrap.createChild();
44488 this.footer = new Roo.Toolbar(fel);
44489 // toolbar has scrolly on left / right?
44490 var footDisp= new Roo.Toolbar.Fill();
44496 handler : function() {
44497 _t.footDisp.scrollTo('left',0,true)
44501 this.footer.add( footDisp );
44506 handler : function() {
44508 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44512 var fel = Roo.get(footDisp.el);
44513 fel.addClass('x-editor-context');
44514 this.footDispWrap = fel;
44515 this.footDispWrap.overflow = 'hidden';
44517 this.footDisp = fel.createChild();
44518 this.footDispWrap.on('click', this.onContextClick, this)
44522 onContextClick : function (ev,dom)
44524 ev.preventDefault();
44525 var cn = dom.className;
44527 if (!cn.match(/x-ed-loc-/)) {
44530 var n = cn.split('-').pop();
44531 var ans = this.footerEls;
44535 var range = this.editorcore.createRange();
44537 range.selectNodeContents(sel);
44538 //range.selectNode(sel);
44541 var selection = this.editorcore.getSelection();
44542 selection.removeAllRanges();
44543 selection.addRange(range);
44547 this.updateToolbar(null, null, sel);
44564 * Ext JS Library 1.1.1
44565 * Copyright(c) 2006-2007, Ext JS, LLC.
44567 * Originally Released Under LGPL - original licence link has changed is not relivant.
44570 * <script type="text/javascript">
44574 * @class Roo.form.BasicForm
44575 * @extends Roo.util.Observable
44576 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44578 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44579 * @param {Object} config Configuration options
44581 Roo.form.BasicForm = function(el, config){
44582 this.allItems = [];
44583 this.childForms = [];
44584 Roo.apply(this, config);
44586 * The Roo.form.Field items in this form.
44587 * @type MixedCollection
44591 this.items = new Roo.util.MixedCollection(false, function(o){
44592 return o.id || (o.id = Roo.id());
44596 * @event beforeaction
44597 * Fires before any action is performed. Return false to cancel the action.
44598 * @param {Form} this
44599 * @param {Action} action The action to be performed
44601 beforeaction: true,
44603 * @event actionfailed
44604 * Fires when an action fails.
44605 * @param {Form} this
44606 * @param {Action} action The action that failed
44608 actionfailed : true,
44610 * @event actioncomplete
44611 * Fires when an action is completed.
44612 * @param {Form} this
44613 * @param {Action} action The action that completed
44615 actioncomplete : true
44620 Roo.form.BasicForm.superclass.constructor.call(this);
44623 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44625 * @cfg {String} method
44626 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44629 * @cfg {DataReader} reader
44630 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44631 * This is optional as there is built-in support for processing JSON.
44634 * @cfg {DataReader} errorReader
44635 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44636 * This is completely optional as there is built-in support for processing JSON.
44639 * @cfg {String} url
44640 * The URL to use for form actions if one isn't supplied in the action options.
44643 * @cfg {Boolean} fileUpload
44644 * Set to true if this form is a file upload.
44648 * @cfg {Object} baseParams
44649 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44654 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44659 activeAction : null,
44662 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44663 * or setValues() data instead of when the form was first created.
44665 trackResetOnLoad : false,
44669 * childForms - used for multi-tab forms
44672 childForms : false,
44675 * allItems - full list of fields.
44681 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44682 * element by passing it or its id or mask the form itself by passing in true.
44685 waitMsgTarget : false,
44688 initEl : function(el){
44689 this.el = Roo.get(el);
44690 this.id = this.el.id || Roo.id();
44691 this.el.on('submit', this.onSubmit, this);
44692 this.el.addClass('x-form');
44696 onSubmit : function(e){
44701 * Returns true if client-side validation on the form is successful.
44704 isValid : function(){
44706 this.items.each(function(f){
44715 * Returns true if any fields in this form have changed since their original load.
44718 isDirty : function(){
44720 this.items.each(function(f){
44730 * Performs a predefined action (submit or load) or custom actions you define on this form.
44731 * @param {String} actionName The name of the action type
44732 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44733 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44734 * accept other config options):
44736 Property Type Description
44737 ---------------- --------------- ----------------------------------------------------------------------------------
44738 url String The url for the action (defaults to the form's url)
44739 method String The form method to use (defaults to the form's method, or POST if not defined)
44740 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44741 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44742 validate the form on the client (defaults to false)
44744 * @return {BasicForm} this
44746 doAction : function(action, options){
44747 if(typeof action == 'string'){
44748 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44750 if(this.fireEvent('beforeaction', this, action) !== false){
44751 this.beforeAction(action);
44752 action.run.defer(100, action);
44758 * Shortcut to do a submit action.
44759 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44760 * @return {BasicForm} this
44762 submit : function(options){
44763 this.doAction('submit', options);
44768 * Shortcut to do a load action.
44769 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44770 * @return {BasicForm} this
44772 load : function(options){
44773 this.doAction('load', options);
44778 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44779 * @param {Record} record The record to edit
44780 * @return {BasicForm} this
44782 updateRecord : function(record){
44783 record.beginEdit();
44784 var fs = record.fields;
44785 fs.each(function(f){
44786 var field = this.findField(f.name);
44788 record.set(f.name, field.getValue());
44796 * Loads an Roo.data.Record into this form.
44797 * @param {Record} record The record to load
44798 * @return {BasicForm} this
44800 loadRecord : function(record){
44801 this.setValues(record.data);
44806 beforeAction : function(action){
44807 var o = action.options;
44810 if(this.waitMsgTarget === true){
44811 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44812 }else if(this.waitMsgTarget){
44813 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44814 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44816 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44822 afterAction : function(action, success){
44823 this.activeAction = null;
44824 var o = action.options;
44826 if(this.waitMsgTarget === true){
44828 }else if(this.waitMsgTarget){
44829 this.waitMsgTarget.unmask();
44831 Roo.MessageBox.updateProgress(1);
44832 Roo.MessageBox.hide();
44839 Roo.callback(o.success, o.scope, [this, action]);
44840 this.fireEvent('actioncomplete', this, action);
44844 // failure condition..
44845 // we have a scenario where updates need confirming.
44846 // eg. if a locking scenario exists..
44847 // we look for { errors : { needs_confirm : true }} in the response.
44849 (typeof(action.result) != 'undefined') &&
44850 (typeof(action.result.errors) != 'undefined') &&
44851 (typeof(action.result.errors.needs_confirm) != 'undefined')
44854 Roo.MessageBox.confirm(
44855 "Change requires confirmation",
44856 action.result.errorMsg,
44861 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44871 Roo.callback(o.failure, o.scope, [this, action]);
44872 // show an error message if no failed handler is set..
44873 if (!this.hasListener('actionfailed')) {
44874 Roo.MessageBox.alert("Error",
44875 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44876 action.result.errorMsg :
44877 "Saving Failed, please check your entries or try again"
44881 this.fireEvent('actionfailed', this, action);
44887 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44888 * @param {String} id The value to search for
44891 findField : function(id){
44892 var field = this.items.get(id);
44894 this.items.each(function(f){
44895 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44901 return field || null;
44905 * Add a secondary form to this one,
44906 * Used to provide tabbed forms. One form is primary, with hidden values
44907 * which mirror the elements from the other forms.
44909 * @param {Roo.form.Form} form to add.
44912 addForm : function(form)
44915 if (this.childForms.indexOf(form) > -1) {
44919 this.childForms.push(form);
44921 Roo.each(form.allItems, function (fe) {
44923 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44924 if (this.findField(n)) { // already added..
44927 var add = new Roo.form.Hidden({
44930 add.render(this.el);
44937 * Mark fields in this form invalid in bulk.
44938 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44939 * @return {BasicForm} this
44941 markInvalid : function(errors){
44942 if(errors instanceof Array){
44943 for(var i = 0, len = errors.length; i < len; i++){
44944 var fieldError = errors[i];
44945 var f = this.findField(fieldError.id);
44947 f.markInvalid(fieldError.msg);
44953 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44954 field.markInvalid(errors[id]);
44958 Roo.each(this.childForms || [], function (f) {
44959 f.markInvalid(errors);
44966 * Set values for fields in this form in bulk.
44967 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44968 * @return {BasicForm} this
44970 setValues : function(values){
44971 if(values instanceof Array){ // array of objects
44972 for(var i = 0, len = values.length; i < len; i++){
44974 var f = this.findField(v.id);
44976 f.setValue(v.value);
44977 if(this.trackResetOnLoad){
44978 f.originalValue = f.getValue();
44982 }else{ // object hash
44985 if(typeof values[id] != 'function' && (field = this.findField(id))){
44987 if (field.setFromData &&
44988 field.valueField &&
44989 field.displayField &&
44990 // combos' with local stores can
44991 // be queried via setValue()
44992 // to set their value..
44993 (field.store && !field.store.isLocal)
44997 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44998 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44999 field.setFromData(sd);
45002 field.setValue(values[id]);
45006 if(this.trackResetOnLoad){
45007 field.originalValue = field.getValue();
45013 Roo.each(this.childForms || [], function (f) {
45014 f.setValues(values);
45021 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45022 * they are returned as an array.
45023 * @param {Boolean} asString
45026 getValues : function(asString){
45027 if (this.childForms) {
45028 // copy values from the child forms
45029 Roo.each(this.childForms, function (f) {
45030 this.setValues(f.getValues());
45036 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45037 if(asString === true){
45040 return Roo.urlDecode(fs);
45044 * Returns the fields in this form as an object with key/value pairs.
45045 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45048 getFieldValues : function(with_hidden)
45050 if (this.childForms) {
45051 // copy values from the child forms
45052 // should this call getFieldValues - probably not as we do not currently copy
45053 // hidden fields when we generate..
45054 Roo.each(this.childForms, function (f) {
45055 this.setValues(f.getValues());
45060 this.items.each(function(f){
45061 if (!f.getName()) {
45064 var v = f.getValue();
45065 if (f.inputType =='radio') {
45066 if (typeof(ret[f.getName()]) == 'undefined') {
45067 ret[f.getName()] = ''; // empty..
45070 if (!f.el.dom.checked) {
45074 v = f.el.dom.value;
45078 // not sure if this supported any more..
45079 if ((typeof(v) == 'object') && f.getRawValue) {
45080 v = f.getRawValue() ; // dates..
45082 // combo boxes where name != hiddenName...
45083 if (f.name != f.getName()) {
45084 ret[f.name] = f.getRawValue();
45086 ret[f.getName()] = v;
45093 * Clears all invalid messages in this form.
45094 * @return {BasicForm} this
45096 clearInvalid : function(){
45097 this.items.each(function(f){
45101 Roo.each(this.childForms || [], function (f) {
45110 * Resets this form.
45111 * @return {BasicForm} this
45113 reset : function(){
45114 this.items.each(function(f){
45118 Roo.each(this.childForms || [], function (f) {
45127 * Add Roo.form components to this form.
45128 * @param {Field} field1
45129 * @param {Field} field2 (optional)
45130 * @param {Field} etc (optional)
45131 * @return {BasicForm} this
45134 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45140 * Removes a field from the items collection (does NOT remove its markup).
45141 * @param {Field} field
45142 * @return {BasicForm} this
45144 remove : function(field){
45145 this.items.remove(field);
45150 * Looks at the fields in this form, checks them for an id attribute,
45151 * and calls applyTo on the existing dom element with that id.
45152 * @return {BasicForm} this
45154 render : function(){
45155 this.items.each(function(f){
45156 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45164 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45165 * @param {Object} values
45166 * @return {BasicForm} this
45168 applyToFields : function(o){
45169 this.items.each(function(f){
45176 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45177 * @param {Object} values
45178 * @return {BasicForm} this
45180 applyIfToFields : function(o){
45181 this.items.each(function(f){
45189 Roo.BasicForm = Roo.form.BasicForm;/*
45191 * Ext JS Library 1.1.1
45192 * Copyright(c) 2006-2007, Ext JS, LLC.
45194 * Originally Released Under LGPL - original licence link has changed is not relivant.
45197 * <script type="text/javascript">
45201 * @class Roo.form.Form
45202 * @extends Roo.form.BasicForm
45203 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45205 * @param {Object} config Configuration options
45207 Roo.form.Form = function(config){
45209 if (config.items) {
45210 xitems = config.items;
45211 delete config.items;
45215 Roo.form.Form.superclass.constructor.call(this, null, config);
45216 this.url = this.url || this.action;
45218 this.root = new Roo.form.Layout(Roo.applyIf({
45222 this.active = this.root;
45224 * Array of all the buttons that have been added to this form via {@link addButton}
45228 this.allItems = [];
45231 * @event clientvalidation
45232 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45233 * @param {Form} this
45234 * @param {Boolean} valid true if the form has passed client-side validation
45236 clientvalidation: true,
45239 * Fires when the form is rendered
45240 * @param {Roo.form.Form} form
45245 if (this.progressUrl) {
45246 // push a hidden field onto the list of fields..
45250 name : 'UPLOAD_IDENTIFIER'
45255 Roo.each(xitems, this.addxtype, this);
45261 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45263 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45266 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45269 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45271 buttonAlign:'center',
45274 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45279 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45280 * This property cascades to child containers if not set.
45285 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45286 * fires a looping event with that state. This is required to bind buttons to the valid
45287 * state using the config value formBind:true on the button.
45289 monitorValid : false,
45292 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45297 * @cfg {String} progressUrl - Url to return progress data
45300 progressUrl : false,
45303 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45304 * fields are added and the column is closed. If no fields are passed the column remains open
45305 * until end() is called.
45306 * @param {Object} config The config to pass to the column
45307 * @param {Field} field1 (optional)
45308 * @param {Field} field2 (optional)
45309 * @param {Field} etc (optional)
45310 * @return Column The column container object
45312 column : function(c){
45313 var col = new Roo.form.Column(c);
45315 if(arguments.length > 1){ // duplicate code required because of Opera
45316 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45323 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45324 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45325 * until end() is called.
45326 * @param {Object} config The config to pass to the fieldset
45327 * @param {Field} field1 (optional)
45328 * @param {Field} field2 (optional)
45329 * @param {Field} etc (optional)
45330 * @return FieldSet The fieldset container object
45332 fieldset : function(c){
45333 var fs = new Roo.form.FieldSet(c);
45335 if(arguments.length > 1){ // duplicate code required because of Opera
45336 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45343 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45344 * fields are added and the container is closed. If no fields are passed the container remains open
45345 * until end() is called.
45346 * @param {Object} config The config to pass to the Layout
45347 * @param {Field} field1 (optional)
45348 * @param {Field} field2 (optional)
45349 * @param {Field} etc (optional)
45350 * @return Layout The container object
45352 container : function(c){
45353 var l = new Roo.form.Layout(c);
45355 if(arguments.length > 1){ // duplicate code required because of Opera
45356 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45363 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45364 * @param {Object} container A Roo.form.Layout or subclass of Layout
45365 * @return {Form} this
45367 start : function(c){
45368 // cascade label info
45369 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45370 this.active.stack.push(c);
45371 c.ownerCt = this.active;
45377 * Closes the current open container
45378 * @return {Form} this
45381 if(this.active == this.root){
45384 this.active = this.active.ownerCt;
45389 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45390 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45391 * as the label of the field.
45392 * @param {Field} field1
45393 * @param {Field} field2 (optional)
45394 * @param {Field} etc. (optional)
45395 * @return {Form} this
45398 this.active.stack.push.apply(this.active.stack, arguments);
45399 this.allItems.push.apply(this.allItems,arguments);
45401 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45402 if(a[i].isFormField){
45407 Roo.form.Form.superclass.add.apply(this, r);
45417 * Find any element that has been added to a form, using it's ID or name
45418 * This can include framesets, columns etc. along with regular fields..
45419 * @param {String} id - id or name to find.
45421 * @return {Element} e - or false if nothing found.
45423 findbyId : function(id)
45429 Roo.each(this.allItems, function(f){
45430 if (f.id == id || f.name == id ){
45441 * Render this form into the passed container. This should only be called once!
45442 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45443 * @return {Form} this
45445 render : function(ct)
45451 var o = this.autoCreate || {
45453 method : this.method || 'POST',
45454 id : this.id || Roo.id()
45456 this.initEl(ct.createChild(o));
45458 this.root.render(this.el);
45462 this.items.each(function(f){
45463 f.render('x-form-el-'+f.id);
45466 if(this.buttons.length > 0){
45467 // tables are required to maintain order and for correct IE layout
45468 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45469 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45470 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45472 var tr = tb.getElementsByTagName('tr')[0];
45473 for(var i = 0, len = this.buttons.length; i < len; i++) {
45474 var b = this.buttons[i];
45475 var td = document.createElement('td');
45476 td.className = 'x-form-btn-td';
45477 b.render(tr.appendChild(td));
45480 if(this.monitorValid){ // initialize after render
45481 this.startMonitoring();
45483 this.fireEvent('rendered', this);
45488 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45489 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45490 * object or a valid Roo.DomHelper element config
45491 * @param {Function} handler The function called when the button is clicked
45492 * @param {Object} scope (optional) The scope of the handler function
45493 * @return {Roo.Button}
45495 addButton : function(config, handler, scope){
45499 minWidth: this.minButtonWidth,
45502 if(typeof config == "string"){
45505 Roo.apply(bc, config);
45507 var btn = new Roo.Button(null, bc);
45508 this.buttons.push(btn);
45513 * Adds a series of form elements (using the xtype property as the factory method.
45514 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45515 * @param {Object} config
45518 addxtype : function()
45520 var ar = Array.prototype.slice.call(arguments, 0);
45522 for(var i = 0; i < ar.length; i++) {
45524 continue; // skip -- if this happends something invalid got sent, we
45525 // should ignore it, as basically that interface element will not show up
45526 // and that should be pretty obvious!!
45529 if (Roo.form[ar[i].xtype]) {
45531 var fe = Roo.factory(ar[i], Roo.form);
45537 fe.store.form = this;
45542 this.allItems.push(fe);
45543 if (fe.items && fe.addxtype) {
45544 fe.addxtype.apply(fe, fe.items);
45554 // console.log('adding ' + ar[i].xtype);
45556 if (ar[i].xtype == 'Button') {
45557 //console.log('adding button');
45558 //console.log(ar[i]);
45559 this.addButton(ar[i]);
45560 this.allItems.push(fe);
45564 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45565 alert('end is not supported on xtype any more, use items');
45567 // //console.log('adding end');
45575 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45576 * option "monitorValid"
45578 startMonitoring : function(){
45581 Roo.TaskMgr.start({
45582 run : this.bindHandler,
45583 interval : this.monitorPoll || 200,
45590 * Stops monitoring of the valid state of this form
45592 stopMonitoring : function(){
45593 this.bound = false;
45597 bindHandler : function(){
45599 return false; // stops binding
45602 this.items.each(function(f){
45603 if(!f.isValid(true)){
45608 for(var i = 0, len = this.buttons.length; i < len; i++){
45609 var btn = this.buttons[i];
45610 if(btn.formBind === true && btn.disabled === valid){
45611 btn.setDisabled(!valid);
45614 this.fireEvent('clientvalidation', this, valid);
45628 Roo.Form = Roo.form.Form;
45631 * Ext JS Library 1.1.1
45632 * Copyright(c) 2006-2007, Ext JS, LLC.
45634 * Originally Released Under LGPL - original licence link has changed is not relivant.
45637 * <script type="text/javascript">
45640 // as we use this in bootstrap.
45641 Roo.namespace('Roo.form');
45643 * @class Roo.form.Action
45644 * Internal Class used to handle form actions
45646 * @param {Roo.form.BasicForm} el The form element or its id
45647 * @param {Object} config Configuration options
45652 // define the action interface
45653 Roo.form.Action = function(form, options){
45655 this.options = options || {};
45658 * Client Validation Failed
45661 Roo.form.Action.CLIENT_INVALID = 'client';
45663 * Server Validation Failed
45666 Roo.form.Action.SERVER_INVALID = 'server';
45668 * Connect to Server Failed
45671 Roo.form.Action.CONNECT_FAILURE = 'connect';
45673 * Reading Data from Server Failed
45676 Roo.form.Action.LOAD_FAILURE = 'load';
45678 Roo.form.Action.prototype = {
45680 failureType : undefined,
45681 response : undefined,
45682 result : undefined,
45684 // interface method
45685 run : function(options){
45689 // interface method
45690 success : function(response){
45694 // interface method
45695 handleResponse : function(response){
45699 // default connection failure
45700 failure : function(response){
45702 this.response = response;
45703 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45704 this.form.afterAction(this, false);
45707 processResponse : function(response){
45708 this.response = response;
45709 if(!response.responseText){
45712 this.result = this.handleResponse(response);
45713 return this.result;
45716 // utility functions used internally
45717 getUrl : function(appendParams){
45718 var url = this.options.url || this.form.url || this.form.el.dom.action;
45720 var p = this.getParams();
45722 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45728 getMethod : function(){
45729 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45732 getParams : function(){
45733 var bp = this.form.baseParams;
45734 var p = this.options.params;
45736 if(typeof p == "object"){
45737 p = Roo.urlEncode(Roo.applyIf(p, bp));
45738 }else if(typeof p == 'string' && bp){
45739 p += '&' + Roo.urlEncode(bp);
45742 p = Roo.urlEncode(bp);
45747 createCallback : function(){
45749 success: this.success,
45750 failure: this.failure,
45752 timeout: (this.form.timeout*1000),
45753 upload: this.form.fileUpload ? this.success : undefined
45758 Roo.form.Action.Submit = function(form, options){
45759 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45762 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45765 haveProgress : false,
45766 uploadComplete : false,
45768 // uploadProgress indicator.
45769 uploadProgress : function()
45771 if (!this.form.progressUrl) {
45775 if (!this.haveProgress) {
45776 Roo.MessageBox.progress("Uploading", "Uploading");
45778 if (this.uploadComplete) {
45779 Roo.MessageBox.hide();
45783 this.haveProgress = true;
45785 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45787 var c = new Roo.data.Connection();
45789 url : this.form.progressUrl,
45794 success : function(req){
45795 //console.log(data);
45799 rdata = Roo.decode(req.responseText)
45801 Roo.log("Invalid data from server..");
45805 if (!rdata || !rdata.success) {
45807 Roo.MessageBox.alert(Roo.encode(rdata));
45810 var data = rdata.data;
45812 if (this.uploadComplete) {
45813 Roo.MessageBox.hide();
45818 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45819 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45822 this.uploadProgress.defer(2000,this);
45825 failure: function(data) {
45826 Roo.log('progress url failed ');
45837 // run get Values on the form, so it syncs any secondary forms.
45838 this.form.getValues();
45840 var o = this.options;
45841 var method = this.getMethod();
45842 var isPost = method == 'POST';
45843 if(o.clientValidation === false || this.form.isValid()){
45845 if (this.form.progressUrl) {
45846 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45847 (new Date() * 1) + '' + Math.random());
45852 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45853 form:this.form.el.dom,
45854 url:this.getUrl(!isPost),
45856 params:isPost ? this.getParams() : null,
45857 isUpload: this.form.fileUpload
45860 this.uploadProgress();
45862 }else if (o.clientValidation !== false){ // client validation failed
45863 this.failureType = Roo.form.Action.CLIENT_INVALID;
45864 this.form.afterAction(this, false);
45868 success : function(response)
45870 this.uploadComplete= true;
45871 if (this.haveProgress) {
45872 Roo.MessageBox.hide();
45876 var result = this.processResponse(response);
45877 if(result === true || result.success){
45878 this.form.afterAction(this, true);
45882 this.form.markInvalid(result.errors);
45883 this.failureType = Roo.form.Action.SERVER_INVALID;
45885 this.form.afterAction(this, false);
45887 failure : function(response)
45889 this.uploadComplete= true;
45890 if (this.haveProgress) {
45891 Roo.MessageBox.hide();
45894 this.response = response;
45895 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45896 this.form.afterAction(this, false);
45899 handleResponse : function(response){
45900 if(this.form.errorReader){
45901 var rs = this.form.errorReader.read(response);
45904 for(var i = 0, len = rs.records.length; i < len; i++) {
45905 var r = rs.records[i];
45906 errors[i] = r.data;
45909 if(errors.length < 1){
45913 success : rs.success,
45919 ret = Roo.decode(response.responseText);
45923 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45933 Roo.form.Action.Load = function(form, options){
45934 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45935 this.reader = this.form.reader;
45938 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45943 Roo.Ajax.request(Roo.apply(
45944 this.createCallback(), {
45945 method:this.getMethod(),
45946 url:this.getUrl(false),
45947 params:this.getParams()
45951 success : function(response){
45953 var result = this.processResponse(response);
45954 if(result === true || !result.success || !result.data){
45955 this.failureType = Roo.form.Action.LOAD_FAILURE;
45956 this.form.afterAction(this, false);
45959 this.form.clearInvalid();
45960 this.form.setValues(result.data);
45961 this.form.afterAction(this, true);
45964 handleResponse : function(response){
45965 if(this.form.reader){
45966 var rs = this.form.reader.read(response);
45967 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45969 success : rs.success,
45973 return Roo.decode(response.responseText);
45977 Roo.form.Action.ACTION_TYPES = {
45978 'load' : Roo.form.Action.Load,
45979 'submit' : Roo.form.Action.Submit
45982 * Ext JS Library 1.1.1
45983 * Copyright(c) 2006-2007, Ext JS, LLC.
45985 * Originally Released Under LGPL - original licence link has changed is not relivant.
45988 * <script type="text/javascript">
45992 * @class Roo.form.Layout
45993 * @extends Roo.Component
45994 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45996 * @param {Object} config Configuration options
45998 Roo.form.Layout = function(config){
46000 if (config.items) {
46001 xitems = config.items;
46002 delete config.items;
46004 Roo.form.Layout.superclass.constructor.call(this, config);
46006 Roo.each(xitems, this.addxtype, this);
46010 Roo.extend(Roo.form.Layout, Roo.Component, {
46012 * @cfg {String/Object} autoCreate
46013 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46016 * @cfg {String/Object/Function} style
46017 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46018 * a function which returns such a specification.
46021 * @cfg {String} labelAlign
46022 * Valid values are "left," "top" and "right" (defaults to "left")
46025 * @cfg {Number} labelWidth
46026 * Fixed width in pixels of all field labels (defaults to undefined)
46029 * @cfg {Boolean} clear
46030 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46034 * @cfg {String} labelSeparator
46035 * The separator to use after field labels (defaults to ':')
46037 labelSeparator : ':',
46039 * @cfg {Boolean} hideLabels
46040 * True to suppress the display of field labels in this layout (defaults to false)
46042 hideLabels : false,
46045 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46050 onRender : function(ct, position){
46051 if(this.el){ // from markup
46052 this.el = Roo.get(this.el);
46053 }else { // generate
46054 var cfg = this.getAutoCreate();
46055 this.el = ct.createChild(cfg, position);
46058 this.el.applyStyles(this.style);
46060 if(this.labelAlign){
46061 this.el.addClass('x-form-label-'+this.labelAlign);
46063 if(this.hideLabels){
46064 this.labelStyle = "display:none";
46065 this.elementStyle = "padding-left:0;";
46067 if(typeof this.labelWidth == 'number'){
46068 this.labelStyle = "width:"+this.labelWidth+"px;";
46069 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46071 if(this.labelAlign == 'top'){
46072 this.labelStyle = "width:auto;";
46073 this.elementStyle = "padding-left:0;";
46076 var stack = this.stack;
46077 var slen = stack.length;
46079 if(!this.fieldTpl){
46080 var t = new Roo.Template(
46081 '<div class="x-form-item {5}">',
46082 '<label for="{0}" style="{2}">{1}{4}</label>',
46083 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46085 '</div><div class="x-form-clear-left"></div>'
46087 t.disableFormats = true;
46089 Roo.form.Layout.prototype.fieldTpl = t;
46091 for(var i = 0; i < slen; i++) {
46092 if(stack[i].isFormField){
46093 this.renderField(stack[i]);
46095 this.renderComponent(stack[i]);
46100 this.el.createChild({cls:'x-form-clear'});
46105 renderField : function(f){
46106 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46109 f.labelStyle||this.labelStyle||'', //2
46110 this.elementStyle||'', //3
46111 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46112 f.itemCls||this.itemCls||'' //5
46113 ], true).getPrevSibling());
46117 renderComponent : function(c){
46118 c.render(c.isLayout ? this.el : this.el.createChild());
46121 * Adds a object form elements (using the xtype property as the factory method.)
46122 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46123 * @param {Object} config
46125 addxtype : function(o)
46127 // create the lement.
46128 o.form = this.form;
46129 var fe = Roo.factory(o, Roo.form);
46130 this.form.allItems.push(fe);
46131 this.stack.push(fe);
46133 if (fe.isFormField) {
46134 this.form.items.add(fe);
46142 * @class Roo.form.Column
46143 * @extends Roo.form.Layout
46144 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46146 * @param {Object} config Configuration options
46148 Roo.form.Column = function(config){
46149 Roo.form.Column.superclass.constructor.call(this, config);
46152 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46154 * @cfg {Number/String} width
46155 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46158 * @cfg {String/Object} autoCreate
46159 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46163 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46166 onRender : function(ct, position){
46167 Roo.form.Column.superclass.onRender.call(this, ct, position);
46169 this.el.setWidth(this.width);
46176 * @class Roo.form.Row
46177 * @extends Roo.form.Layout
46178 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46180 * @param {Object} config Configuration options
46184 Roo.form.Row = function(config){
46185 Roo.form.Row.superclass.constructor.call(this, config);
46188 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46190 * @cfg {Number/String} width
46191 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46194 * @cfg {Number/String} height
46195 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46197 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46201 onRender : function(ct, position){
46202 //console.log('row render');
46204 var t = new Roo.Template(
46205 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46206 '<label for="{0}" style="{2}">{1}{4}</label>',
46207 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46211 t.disableFormats = true;
46213 Roo.form.Layout.prototype.rowTpl = t;
46215 this.fieldTpl = this.rowTpl;
46217 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46218 var labelWidth = 100;
46220 if ((this.labelAlign != 'top')) {
46221 if (typeof this.labelWidth == 'number') {
46222 labelWidth = this.labelWidth
46224 this.padWidth = 20 + labelWidth;
46228 Roo.form.Column.superclass.onRender.call(this, ct, position);
46230 this.el.setWidth(this.width);
46233 this.el.setHeight(this.height);
46238 renderField : function(f){
46239 f.fieldEl = this.fieldTpl.append(this.el, [
46240 f.id, f.fieldLabel,
46241 f.labelStyle||this.labelStyle||'',
46242 this.elementStyle||'',
46243 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46244 f.itemCls||this.itemCls||'',
46245 f.width ? f.width + this.padWidth : 160 + this.padWidth
46252 * @class Roo.form.FieldSet
46253 * @extends Roo.form.Layout
46254 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46256 * @param {Object} config Configuration options
46258 Roo.form.FieldSet = function(config){
46259 Roo.form.FieldSet.superclass.constructor.call(this, config);
46262 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46264 * @cfg {String} legend
46265 * The text to display as the legend for the FieldSet (defaults to '')
46268 * @cfg {String/Object} autoCreate
46269 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46273 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46276 onRender : function(ct, position){
46277 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46279 this.setLegend(this.legend);
46284 setLegend : function(text){
46286 this.el.child('legend').update(text);
46291 * Ext JS Library 1.1.1
46292 * Copyright(c) 2006-2007, Ext JS, LLC.
46294 * Originally Released Under LGPL - original licence link has changed is not relivant.
46297 * <script type="text/javascript">
46300 * @class Roo.form.VTypes
46301 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46304 Roo.form.VTypes = function(){
46305 // closure these in so they are only created once.
46306 var alpha = /^[a-zA-Z_]+$/;
46307 var alphanum = /^[a-zA-Z0-9_]+$/;
46308 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46309 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46311 // All these messages and functions are configurable
46314 * The function used to validate email addresses
46315 * @param {String} value The email address
46317 'email' : function(v){
46318 return email.test(v);
46321 * The error text to display when the email validation function returns false
46324 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46326 * The keystroke filter mask to be applied on email input
46329 'emailMask' : /[a-z0-9_\.\-@]/i,
46332 * The function used to validate URLs
46333 * @param {String} value The URL
46335 'url' : function(v){
46336 return url.test(v);
46339 * The error text to display when the url validation function returns false
46342 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46345 * The function used to validate alpha values
46346 * @param {String} value The value
46348 'alpha' : function(v){
46349 return alpha.test(v);
46352 * The error text to display when the alpha validation function returns false
46355 'alphaText' : 'This field should only contain letters and _',
46357 * The keystroke filter mask to be applied on alpha input
46360 'alphaMask' : /[a-z_]/i,
46363 * The function used to validate alphanumeric values
46364 * @param {String} value The value
46366 'alphanum' : function(v){
46367 return alphanum.test(v);
46370 * The error text to display when the alphanumeric validation function returns false
46373 'alphanumText' : 'This field should only contain letters, numbers and _',
46375 * The keystroke filter mask to be applied on alphanumeric input
46378 'alphanumMask' : /[a-z0-9_]/i
46380 }();//<script type="text/javascript">
46383 * @class Roo.form.FCKeditor
46384 * @extends Roo.form.TextArea
46385 * Wrapper around the FCKEditor http://www.fckeditor.net
46387 * Creates a new FCKeditor
46388 * @param {Object} config Configuration options
46390 Roo.form.FCKeditor = function(config){
46391 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46394 * @event editorinit
46395 * Fired when the editor is initialized - you can add extra handlers here..
46396 * @param {FCKeditor} this
46397 * @param {Object} the FCK object.
46404 Roo.form.FCKeditor.editors = { };
46405 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46407 //defaultAutoCreate : {
46408 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46412 * @cfg {Object} fck options - see fck manual for details.
46417 * @cfg {Object} fck toolbar set (Basic or Default)
46419 toolbarSet : 'Basic',
46421 * @cfg {Object} fck BasePath
46423 basePath : '/fckeditor/',
46431 onRender : function(ct, position)
46434 this.defaultAutoCreate = {
46436 style:"width:300px;height:60px;",
46437 autocomplete: "off"
46440 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46443 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46444 if(this.preventScrollbars){
46445 this.el.setStyle("overflow", "hidden");
46447 this.el.setHeight(this.growMin);
46450 //console.log('onrender' + this.getId() );
46451 Roo.form.FCKeditor.editors[this.getId()] = this;
46454 this.replaceTextarea() ;
46458 getEditor : function() {
46459 return this.fckEditor;
46462 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46463 * @param {Mixed} value The value to set
46467 setValue : function(value)
46469 //console.log('setValue: ' + value);
46471 if(typeof(value) == 'undefined') { // not sure why this is happending...
46474 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46476 //if(!this.el || !this.getEditor()) {
46477 // this.value = value;
46478 //this.setValue.defer(100,this,[value]);
46482 if(!this.getEditor()) {
46486 this.getEditor().SetData(value);
46493 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46494 * @return {Mixed} value The field value
46496 getValue : function()
46499 if (this.frame && this.frame.dom.style.display == 'none') {
46500 return Roo.form.FCKeditor.superclass.getValue.call(this);
46503 if(!this.el || !this.getEditor()) {
46505 // this.getValue.defer(100,this);
46510 var value=this.getEditor().GetData();
46511 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46512 return Roo.form.FCKeditor.superclass.getValue.call(this);
46518 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46519 * @return {Mixed} value The field value
46521 getRawValue : function()
46523 if (this.frame && this.frame.dom.style.display == 'none') {
46524 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46527 if(!this.el || !this.getEditor()) {
46528 //this.getRawValue.defer(100,this);
46535 var value=this.getEditor().GetData();
46536 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46537 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46541 setSize : function(w,h) {
46545 //if (this.frame && this.frame.dom.style.display == 'none') {
46546 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46549 //if(!this.el || !this.getEditor()) {
46550 // this.setSize.defer(100,this, [w,h]);
46556 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46558 this.frame.dom.setAttribute('width', w);
46559 this.frame.dom.setAttribute('height', h);
46560 this.frame.setSize(w,h);
46564 toggleSourceEdit : function(value) {
46568 this.el.dom.style.display = value ? '' : 'none';
46569 this.frame.dom.style.display = value ? 'none' : '';
46574 focus: function(tag)
46576 if (this.frame.dom.style.display == 'none') {
46577 return Roo.form.FCKeditor.superclass.focus.call(this);
46579 if(!this.el || !this.getEditor()) {
46580 this.focus.defer(100,this, [tag]);
46587 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46588 this.getEditor().Focus();
46590 if (!this.getEditor().Selection.GetSelection()) {
46591 this.focus.defer(100,this, [tag]);
46596 var r = this.getEditor().EditorDocument.createRange();
46597 r.setStart(tgs[0],0);
46598 r.setEnd(tgs[0],0);
46599 this.getEditor().Selection.GetSelection().removeAllRanges();
46600 this.getEditor().Selection.GetSelection().addRange(r);
46601 this.getEditor().Focus();
46608 replaceTextarea : function()
46610 if ( document.getElementById( this.getId() + '___Frame' ) )
46612 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46614 // We must check the elements firstly using the Id and then the name.
46615 var oTextarea = document.getElementById( this.getId() );
46617 var colElementsByName = document.getElementsByName( this.getId() ) ;
46619 oTextarea.style.display = 'none' ;
46621 if ( oTextarea.tabIndex ) {
46622 this.TabIndex = oTextarea.tabIndex ;
46625 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46626 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46627 this.frame = Roo.get(this.getId() + '___Frame')
46630 _getConfigHtml : function()
46634 for ( var o in this.fckconfig ) {
46635 sConfig += sConfig.length > 0 ? '&' : '';
46636 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46639 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46643 _getIFrameHtml : function()
46645 var sFile = 'fckeditor.html' ;
46646 /* no idea what this is about..
46649 if ( (/fcksource=true/i).test( window.top.location.search ) )
46650 sFile = 'fckeditor.original.html' ;
46655 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46656 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46659 var html = '<iframe id="' + this.getId() +
46660 '___Frame" src="' + sLink +
46661 '" width="' + this.width +
46662 '" height="' + this.height + '"' +
46663 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46664 ' frameborder="0" scrolling="no"></iframe>' ;
46669 _insertHtmlBefore : function( html, element )
46671 if ( element.insertAdjacentHTML ) {
46673 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46675 var oRange = document.createRange() ;
46676 oRange.setStartBefore( element ) ;
46677 var oFragment = oRange.createContextualFragment( html );
46678 element.parentNode.insertBefore( oFragment, element ) ;
46691 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46693 function FCKeditor_OnComplete(editorInstance){
46694 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46695 f.fckEditor = editorInstance;
46696 //console.log("loaded");
46697 f.fireEvent('editorinit', f, editorInstance);
46717 //<script type="text/javascript">
46719 * @class Roo.form.GridField
46720 * @extends Roo.form.Field
46721 * Embed a grid (or editable grid into a form)
46724 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46726 * xgrid.store = Roo.data.Store
46727 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46728 * xgrid.store.reader = Roo.data.JsonReader
46732 * Creates a new GridField
46733 * @param {Object} config Configuration options
46735 Roo.form.GridField = function(config){
46736 Roo.form.GridField.superclass.constructor.call(this, config);
46740 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46742 * @cfg {Number} width - used to restrict width of grid..
46746 * @cfg {Number} height - used to restrict height of grid..
46750 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46756 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46757 * {tag: "input", type: "checkbox", autocomplete: "off"})
46759 // defaultAutoCreate : { tag: 'div' },
46760 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46762 * @cfg {String} addTitle Text to include for adding a title.
46766 onResize : function(){
46767 Roo.form.Field.superclass.onResize.apply(this, arguments);
46770 initEvents : function(){
46771 // Roo.form.Checkbox.superclass.initEvents.call(this);
46772 // has no events...
46777 getResizeEl : function(){
46781 getPositionEl : function(){
46786 onRender : function(ct, position){
46788 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46789 var style = this.style;
46792 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46793 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46794 this.viewEl = this.wrap.createChild({ tag: 'div' });
46796 this.viewEl.applyStyles(style);
46799 this.viewEl.setWidth(this.width);
46802 this.viewEl.setHeight(this.height);
46804 //if(this.inputValue !== undefined){
46805 //this.setValue(this.value);
46808 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46811 this.grid.render();
46812 this.grid.getDataSource().on('remove', this.refreshValue, this);
46813 this.grid.getDataSource().on('update', this.refreshValue, this);
46814 this.grid.on('afteredit', this.refreshValue, this);
46820 * Sets the value of the item.
46821 * @param {String} either an object or a string..
46823 setValue : function(v){
46825 v = v || []; // empty set..
46826 // this does not seem smart - it really only affects memoryproxy grids..
46827 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46828 var ds = this.grid.getDataSource();
46829 // assumes a json reader..
46831 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46832 ds.loadData( data);
46834 // clear selection so it does not get stale.
46835 if (this.grid.sm) {
46836 this.grid.sm.clearSelections();
46839 Roo.form.GridField.superclass.setValue.call(this, v);
46840 this.refreshValue();
46841 // should load data in the grid really....
46845 refreshValue: function() {
46847 this.grid.getDataSource().each(function(r) {
46850 this.el.dom.value = Roo.encode(val);
46858 * Ext JS Library 1.1.1
46859 * Copyright(c) 2006-2007, Ext JS, LLC.
46861 * Originally Released Under LGPL - original licence link has changed is not relivant.
46864 * <script type="text/javascript">
46867 * @class Roo.form.DisplayField
46868 * @extends Roo.form.Field
46869 * A generic Field to display non-editable data.
46871 * Creates a new Display Field item.
46872 * @param {Object} config Configuration options
46874 Roo.form.DisplayField = function(config){
46875 Roo.form.DisplayField.superclass.constructor.call(this, config);
46879 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46880 inputType: 'hidden',
46886 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46888 focusClass : undefined,
46890 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46892 fieldClass: 'x-form-field',
46895 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46897 valueRenderer: undefined,
46901 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46902 * {tag: "input", type: "checkbox", autocomplete: "off"})
46905 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46907 onResize : function(){
46908 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46912 initEvents : function(){
46913 // Roo.form.Checkbox.superclass.initEvents.call(this);
46914 // has no events...
46919 getResizeEl : function(){
46923 getPositionEl : function(){
46928 onRender : function(ct, position){
46930 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46931 //if(this.inputValue !== undefined){
46932 this.wrap = this.el.wrap();
46934 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46936 if (this.bodyStyle) {
46937 this.viewEl.applyStyles(this.bodyStyle);
46939 //this.viewEl.setStyle('padding', '2px');
46941 this.setValue(this.value);
46946 initValue : Roo.emptyFn,
46951 onClick : function(){
46956 * Sets the checked state of the checkbox.
46957 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46959 setValue : function(v){
46961 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46962 // this might be called before we have a dom element..
46963 if (!this.viewEl) {
46966 this.viewEl.dom.innerHTML = html;
46967 Roo.form.DisplayField.superclass.setValue.call(this, v);
46977 * @class Roo.form.DayPicker
46978 * @extends Roo.form.Field
46979 * A Day picker show [M] [T] [W] ....
46981 * Creates a new Day Picker
46982 * @param {Object} config Configuration options
46984 Roo.form.DayPicker= function(config){
46985 Roo.form.DayPicker.superclass.constructor.call(this, config);
46989 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46991 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46993 focusClass : undefined,
46995 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46997 fieldClass: "x-form-field",
47000 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47001 * {tag: "input", type: "checkbox", autocomplete: "off"})
47003 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
47006 actionMode : 'viewEl',
47010 inputType : 'hidden',
47013 inputElement: false, // real input element?
47014 basedOn: false, // ????
47016 isFormField: true, // not sure where this is needed!!!!
47018 onResize : function(){
47019 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47020 if(!this.boxLabel){
47021 this.el.alignTo(this.wrap, 'c-c');
47025 initEvents : function(){
47026 Roo.form.Checkbox.superclass.initEvents.call(this);
47027 this.el.on("click", this.onClick, this);
47028 this.el.on("change", this.onClick, this);
47032 getResizeEl : function(){
47036 getPositionEl : function(){
47042 onRender : function(ct, position){
47043 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47045 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47047 var r1 = '<table><tr>';
47048 var r2 = '<tr class="x-form-daypick-icons">';
47049 for (var i=0; i < 7; i++) {
47050 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47051 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47054 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47055 viewEl.select('img').on('click', this.onClick, this);
47056 this.viewEl = viewEl;
47059 // this will not work on Chrome!!!
47060 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47061 this.el.on('propertychange', this.setFromHidden, this); //ie
47069 initValue : Roo.emptyFn,
47072 * Returns the checked state of the checkbox.
47073 * @return {Boolean} True if checked, else false
47075 getValue : function(){
47076 return this.el.dom.value;
47081 onClick : function(e){
47082 //this.setChecked(!this.checked);
47083 Roo.get(e.target).toggleClass('x-menu-item-checked');
47084 this.refreshValue();
47085 //if(this.el.dom.checked != this.checked){
47086 // this.setValue(this.el.dom.checked);
47091 refreshValue : function()
47094 this.viewEl.select('img',true).each(function(e,i,n) {
47095 val += e.is(".x-menu-item-checked") ? String(n) : '';
47097 this.setValue(val, true);
47101 * Sets the checked state of the checkbox.
47102 * On is always based on a string comparison between inputValue and the param.
47103 * @param {Boolean/String} value - the value to set
47104 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47106 setValue : function(v,suppressEvent){
47107 if (!this.el.dom) {
47110 var old = this.el.dom.value ;
47111 this.el.dom.value = v;
47112 if (suppressEvent) {
47116 // update display..
47117 this.viewEl.select('img',true).each(function(e,i,n) {
47119 var on = e.is(".x-menu-item-checked");
47120 var newv = v.indexOf(String(n)) > -1;
47122 e.toggleClass('x-menu-item-checked');
47128 this.fireEvent('change', this, v, old);
47133 // handle setting of hidden value by some other method!!?!?
47134 setFromHidden: function()
47139 //console.log("SET FROM HIDDEN");
47140 //alert('setFrom hidden');
47141 this.setValue(this.el.dom.value);
47144 onDestroy : function()
47147 Roo.get(this.viewEl).remove();
47150 Roo.form.DayPicker.superclass.onDestroy.call(this);
47154 * RooJS Library 1.1.1
47155 * Copyright(c) 2008-2011 Alan Knowles
47162 * @class Roo.form.ComboCheck
47163 * @extends Roo.form.ComboBox
47164 * A combobox for multiple select items.
47166 * FIXME - could do with a reset button..
47169 * Create a new ComboCheck
47170 * @param {Object} config Configuration options
47172 Roo.form.ComboCheck = function(config){
47173 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47174 // should verify some data...
47176 // hiddenName = required..
47177 // displayField = required
47178 // valudField == required
47179 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47181 Roo.each(req, function(e) {
47182 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47183 throw "Roo.form.ComboCheck : missing value for: " + e;
47190 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47195 selectedClass: 'x-menu-item-checked',
47198 onRender : function(ct, position){
47204 var cls = 'x-combo-list';
47207 this.tpl = new Roo.Template({
47208 html : '<div class="'+cls+'-item x-menu-check-item">' +
47209 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47210 '<span>{' + this.displayField + '}</span>' +
47217 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47218 this.view.singleSelect = false;
47219 this.view.multiSelect = true;
47220 this.view.toggleSelect = true;
47221 this.pageTb.add(new Roo.Toolbar.Fill(), {
47224 handler: function()
47231 onViewOver : function(e, t){
47237 onViewClick : function(doFocus,index){
47241 select: function () {
47242 //Roo.log("SELECT CALLED");
47245 selectByValue : function(xv, scrollIntoView){
47246 var ar = this.getValueArray();
47249 Roo.each(ar, function(v) {
47250 if(v === undefined || v === null){
47253 var r = this.findRecord(this.valueField, v);
47255 sels.push(this.store.indexOf(r))
47259 this.view.select(sels);
47265 onSelect : function(record, index){
47266 // Roo.log("onselect Called");
47267 // this is only called by the clear button now..
47268 this.view.clearSelections();
47269 this.setValue('[]');
47270 if (this.value != this.valueBefore) {
47271 this.fireEvent('change', this, this.value, this.valueBefore);
47272 this.valueBefore = this.value;
47275 getValueArray : function()
47280 //Roo.log(this.value);
47281 if (typeof(this.value) == 'undefined') {
47284 var ar = Roo.decode(this.value);
47285 return ar instanceof Array ? ar : []; //?? valid?
47288 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47293 expand : function ()
47296 Roo.form.ComboCheck.superclass.expand.call(this);
47297 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47298 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47303 collapse : function(){
47304 Roo.form.ComboCheck.superclass.collapse.call(this);
47305 var sl = this.view.getSelectedIndexes();
47306 var st = this.store;
47310 Roo.each(sl, function(i) {
47312 nv.push(r.get(this.valueField));
47314 this.setValue(Roo.encode(nv));
47315 if (this.value != this.valueBefore) {
47317 this.fireEvent('change', this, this.value, this.valueBefore);
47318 this.valueBefore = this.value;
47323 setValue : function(v){
47327 var vals = this.getValueArray();
47329 Roo.each(vals, function(k) {
47330 var r = this.findRecord(this.valueField, k);
47332 tv.push(r.data[this.displayField]);
47333 }else if(this.valueNotFoundText !== undefined){
47334 tv.push( this.valueNotFoundText );
47339 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47340 this.hiddenField.value = v;
47346 * Ext JS Library 1.1.1
47347 * Copyright(c) 2006-2007, Ext JS, LLC.
47349 * Originally Released Under LGPL - original licence link has changed is not relivant.
47352 * <script type="text/javascript">
47356 * @class Roo.form.Signature
47357 * @extends Roo.form.Field
47361 * @param {Object} config Configuration options
47364 Roo.form.Signature = function(config){
47365 Roo.form.Signature.superclass.constructor.call(this, config);
47367 this.addEvents({// not in used??
47370 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47371 * @param {Roo.form.Signature} combo This combo box
47376 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47377 * @param {Roo.form.ComboBox} combo This combo box
47378 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47384 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47386 * @cfg {Object} labels Label to use when rendering a form.
47390 * confirm : "Confirm"
47395 confirm : "Confirm"
47398 * @cfg {Number} width The signature panel width (defaults to 300)
47402 * @cfg {Number} height The signature panel height (defaults to 100)
47406 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47408 allowBlank : false,
47411 // {Object} signPanel The signature SVG panel element (defaults to {})
47413 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47414 isMouseDown : false,
47415 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47416 isConfirmed : false,
47417 // {String} signatureTmp SVG mapping string (defaults to empty string)
47421 defaultAutoCreate : { // modified by initCompnoent..
47427 onRender : function(ct, position){
47429 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47431 this.wrap = this.el.wrap({
47432 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47435 this.createToolbar(this);
47436 this.signPanel = this.wrap.createChild({
47438 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47442 this.svgID = Roo.id();
47443 this.svgEl = this.signPanel.createChild({
47444 xmlns : 'http://www.w3.org/2000/svg',
47446 id : this.svgID + "-svg",
47448 height: this.height,
47449 viewBox: '0 0 '+this.width+' '+this.height,
47453 id: this.svgID + "-svg-r",
47455 height: this.height,
47460 id: this.svgID + "-svg-l",
47462 y1: (this.height*0.8), // start set the line in 80% of height
47463 x2: this.width, // end
47464 y2: (this.height*0.8), // end set the line in 80% of height
47466 'stroke-width': "1",
47467 'stroke-dasharray': "3",
47468 'shape-rendering': "crispEdges",
47469 'pointer-events': "none"
47473 id: this.svgID + "-svg-p",
47475 'stroke-width': "3",
47477 'pointer-events': 'none'
47482 this.svgBox = this.svgEl.dom.getScreenCTM();
47484 createSVG : function(){
47485 var svg = this.signPanel;
47486 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47489 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47490 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47491 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47492 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47493 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47494 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47495 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47498 isTouchEvent : function(e){
47499 return e.type.match(/^touch/);
47501 getCoords : function (e) {
47502 var pt = this.svgEl.dom.createSVGPoint();
47505 if (this.isTouchEvent(e)) {
47506 pt.x = e.targetTouches[0].clientX
47507 pt.y = e.targetTouches[0].clientY;
47509 var a = this.svgEl.dom.getScreenCTM();
47510 var b = a.inverse();
47511 var mx = pt.matrixTransform(b);
47512 return mx.x + ',' + mx.y;
47514 //mouse event headler
47515 down : function (e) {
47516 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47517 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47519 this.isMouseDown = true;
47521 e.preventDefault();
47523 move : function (e) {
47524 if (this.isMouseDown) {
47525 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47526 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47529 e.preventDefault();
47531 up : function (e) {
47532 this.isMouseDown = false;
47533 var sp = this.signatureTmp.split(' ');
47536 if(!sp[sp.length-2].match(/^L/)){
47540 this.signatureTmp = sp.join(" ");
47543 if(this.getValue() != this.signatureTmp){
47544 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47545 this.isConfirmed = false;
47547 e.preventDefault();
47551 * Protected method that will not generally be called directly. It
47552 * is called when the editor creates its toolbar. Override this method if you need to
47553 * add custom toolbar buttons.
47554 * @param {HtmlEditor} editor
47556 createToolbar : function(editor){
47557 function btn(id, toggle, handler){
47558 var xid = fid + '-'+ id ;
47562 cls : 'x-btn-icon x-edit-'+id,
47563 enableToggle:toggle !== false,
47564 scope: editor, // was editor...
47565 handler:handler||editor.relayBtnCmd,
47566 clickEvent:'mousedown',
47567 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47573 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47577 cls : ' x-signature-btn x-signature-'+id,
47578 scope: editor, // was editor...
47579 handler: this.reset,
47580 clickEvent:'mousedown',
47581 text: this.labels.clear
47588 cls : ' x-signature-btn x-signature-'+id,
47589 scope: editor, // was editor...
47590 handler: this.confirmHandler,
47591 clickEvent:'mousedown',
47592 text: this.labels.confirm
47599 * when user is clicked confirm then show this image.....
47601 * @return {String} Image Data URI
47603 getImageDataURI : function(){
47604 var svg = this.svgEl.dom.parentNode.innerHTML;
47605 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47610 * @return {Boolean} this.isConfirmed
47612 getConfirmed : function(){
47613 return this.isConfirmed;
47617 * @return {Number} this.width
47619 getWidth : function(){
47624 * @return {Number} this.height
47626 getHeight : function(){
47627 return this.height;
47630 getSignature : function(){
47631 return this.signatureTmp;
47634 reset : function(){
47635 this.signatureTmp = '';
47636 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47637 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47638 this.isConfirmed = false;
47639 Roo.form.Signature.superclass.reset.call(this);
47641 setSignature : function(s){
47642 this.signatureTmp = s;
47643 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47644 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47646 this.isConfirmed = false;
47647 Roo.form.Signature.superclass.reset.call(this);
47650 // Roo.log(this.signPanel.dom.contentWindow.up())
47653 setConfirmed : function(){
47657 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47660 confirmHandler : function(){
47661 if(!this.getSignature()){
47665 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47666 this.setValue(this.getSignature());
47667 this.isConfirmed = true;
47669 this.fireEvent('confirm', this);
47672 // Subclasses should provide the validation implementation by overriding this
47673 validateValue : function(value){
47674 if(this.allowBlank){
47678 if(this.isConfirmed){
47685 * Ext JS Library 1.1.1
47686 * Copyright(c) 2006-2007, Ext JS, LLC.
47688 * Originally Released Under LGPL - original licence link has changed is not relivant.
47691 * <script type="text/javascript">
47696 * @class Roo.form.ComboBox
47697 * @extends Roo.form.TriggerField
47698 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47700 * Create a new ComboBox.
47701 * @param {Object} config Configuration options
47703 Roo.form.Select = function(config){
47704 Roo.form.Select.superclass.constructor.call(this, config);
47708 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47710 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47713 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47714 * rendering into an Roo.Editor, defaults to false)
47717 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47718 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47721 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47724 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47725 * the dropdown list (defaults to undefined, with no header element)
47729 * @cfg {String/Roo.Template} tpl The template to use to render the output
47733 defaultAutoCreate : {tag: "select" },
47735 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47737 listWidth: undefined,
47739 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47740 * mode = 'remote' or 'text' if mode = 'local')
47742 displayField: undefined,
47744 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47745 * mode = 'remote' or 'value' if mode = 'local').
47746 * Note: use of a valueField requires the user make a selection
47747 * in order for a value to be mapped.
47749 valueField: undefined,
47753 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47754 * field's data value (defaults to the underlying DOM element's name)
47756 hiddenName: undefined,
47758 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47762 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47764 selectedClass: 'x-combo-selected',
47766 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47767 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47768 * which displays a downward arrow icon).
47770 triggerClass : 'x-form-arrow-trigger',
47772 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47776 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47777 * anchor positions (defaults to 'tl-bl')
47779 listAlign: 'tl-bl?',
47781 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47785 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47786 * query specified by the allQuery config option (defaults to 'query')
47788 triggerAction: 'query',
47790 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47791 * (defaults to 4, does not apply if editable = false)
47795 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47796 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47800 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47801 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47805 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47806 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47810 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47811 * when editable = true (defaults to false)
47813 selectOnFocus:false,
47815 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47817 queryParam: 'query',
47819 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47820 * when mode = 'remote' (defaults to 'Loading...')
47822 loadingText: 'Loading...',
47824 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47828 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47832 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47833 * traditional select (defaults to true)
47837 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47841 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47845 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47846 * listWidth has a higher value)
47850 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47851 * allow the user to set arbitrary text into the field (defaults to false)
47853 forceSelection:false,
47855 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47856 * if typeAhead = true (defaults to 250)
47858 typeAheadDelay : 250,
47860 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47861 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47863 valueNotFoundText : undefined,
47866 * @cfg {String} defaultValue The value displayed after loading the store.
47871 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47873 blockFocus : false,
47876 * @cfg {Boolean} disableClear Disable showing of clear button.
47878 disableClear : false,
47880 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47882 alwaysQuery : false,
47888 // element that contains real text value.. (when hidden is used..)
47891 onRender : function(ct, position){
47892 Roo.form.Field.prototype.onRender.call(this, ct, position);
47895 this.store.on('beforeload', this.onBeforeLoad, this);
47896 this.store.on('load', this.onLoad, this);
47897 this.store.on('loadexception', this.onLoadException, this);
47898 this.store.load({});
47906 initEvents : function(){
47907 //Roo.form.ComboBox.superclass.initEvents.call(this);
47911 onDestroy : function(){
47914 this.store.un('beforeload', this.onBeforeLoad, this);
47915 this.store.un('load', this.onLoad, this);
47916 this.store.un('loadexception', this.onLoadException, this);
47918 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47922 fireKey : function(e){
47923 if(e.isNavKeyPress() && !this.list.isVisible()){
47924 this.fireEvent("specialkey", this, e);
47929 onResize: function(w, h){
47937 * Allow or prevent the user from directly editing the field text. If false is passed,
47938 * the user will only be able to select from the items defined in the dropdown list. This method
47939 * is the runtime equivalent of setting the 'editable' config option at config time.
47940 * @param {Boolean} value True to allow the user to directly edit the field text
47942 setEditable : function(value){
47947 onBeforeLoad : function(){
47949 Roo.log("Select before load");
47952 this.innerList.update(this.loadingText ?
47953 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47954 //this.restrictHeight();
47955 this.selectedIndex = -1;
47959 onLoad : function(){
47962 var dom = this.el.dom;
47963 dom.innerHTML = '';
47964 var od = dom.ownerDocument;
47966 if (this.emptyText) {
47967 var op = od.createElement('option');
47968 op.setAttribute('value', '');
47969 op.innerHTML = String.format('{0}', this.emptyText);
47970 dom.appendChild(op);
47972 if(this.store.getCount() > 0){
47974 var vf = this.valueField;
47975 var df = this.displayField;
47976 this.store.data.each(function(r) {
47977 // which colmsn to use... testing - cdoe / title..
47978 var op = od.createElement('option');
47979 op.setAttribute('value', r.data[vf]);
47980 op.innerHTML = String.format('{0}', r.data[df]);
47981 dom.appendChild(op);
47983 if (typeof(this.defaultValue != 'undefined')) {
47984 this.setValue(this.defaultValue);
47989 //this.onEmptyResults();
47994 onLoadException : function()
47996 dom.innerHTML = '';
47998 Roo.log("Select on load exception");
48002 Roo.log(this.store.reader.jsonData);
48003 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48004 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48010 onTypeAhead : function(){
48015 onSelect : function(record, index){
48016 Roo.log('on select?');
48018 if(this.fireEvent('beforeselect', this, record, index) !== false){
48019 this.setFromData(index > -1 ? record.data : false);
48021 this.fireEvent('select', this, record, index);
48026 * Returns the currently selected field value or empty string if no value is set.
48027 * @return {String} value The selected value
48029 getValue : function(){
48030 var dom = this.el.dom;
48031 this.value = dom.options[dom.selectedIndex].value;
48037 * Clears any text/value currently set in the field
48039 clearValue : function(){
48041 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48046 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48047 * will be displayed in the field. If the value does not match the data value of an existing item,
48048 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48049 * Otherwise the field will be blank (although the value will still be set).
48050 * @param {String} value The value to match
48052 setValue : function(v){
48053 var d = this.el.dom;
48054 for (var i =0; i < d.options.length;i++) {
48055 if (v == d.options[i].value) {
48056 d.selectedIndex = i;
48064 * @property {Object} the last set data for the element
48069 * Sets the value of the field based on a object which is related to the record format for the store.
48070 * @param {Object} value the value to set as. or false on reset?
48072 setFromData : function(o){
48073 Roo.log('setfrom data?');
48079 reset : function(){
48083 findRecord : function(prop, value){
48088 if(this.store.getCount() > 0){
48089 this.store.each(function(r){
48090 if(r.data[prop] == value){
48100 getName: function()
48102 // returns hidden if it's set..
48103 if (!this.rendered) {return ''};
48104 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48112 onEmptyResults : function(){
48113 Roo.log('empty results');
48118 * Returns true if the dropdown list is expanded, else false.
48120 isExpanded : function(){
48125 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48126 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48127 * @param {String} value The data value of the item to select
48128 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48129 * selected item if it is not currently in view (defaults to true)
48130 * @return {Boolean} True if the value matched an item in the list, else false
48132 selectByValue : function(v, scrollIntoView){
48133 Roo.log('select By Value');
48136 if(v !== undefined && v !== null){
48137 var r = this.findRecord(this.valueField || this.displayField, v);
48139 this.select(this.store.indexOf(r), scrollIntoView);
48147 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48148 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48149 * @param {Number} index The zero-based index of the list item to select
48150 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48151 * selected item if it is not currently in view (defaults to true)
48153 select : function(index, scrollIntoView){
48154 Roo.log('select ');
48157 this.selectedIndex = index;
48158 this.view.select(index);
48159 if(scrollIntoView !== false){
48160 var el = this.view.getNode(index);
48162 this.innerList.scrollChildIntoView(el, false);
48170 validateBlur : function(){
48177 initQuery : function(){
48178 this.doQuery(this.getRawValue());
48182 doForce : function(){
48183 if(this.el.dom.value.length > 0){
48184 this.el.dom.value =
48185 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48191 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48192 * query allowing the query action to be canceled if needed.
48193 * @param {String} query The SQL query to execute
48194 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48195 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48196 * saved in the current store (defaults to false)
48198 doQuery : function(q, forceAll){
48200 Roo.log('doQuery?');
48201 if(q === undefined || q === null){
48206 forceAll: forceAll,
48210 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48214 forceAll = qe.forceAll;
48215 if(forceAll === true || (q.length >= this.minChars)){
48216 if(this.lastQuery != q || this.alwaysQuery){
48217 this.lastQuery = q;
48218 if(this.mode == 'local'){
48219 this.selectedIndex = -1;
48221 this.store.clearFilter();
48223 this.store.filter(this.displayField, q);
48227 this.store.baseParams[this.queryParam] = q;
48229 params: this.getParams(q)
48234 this.selectedIndex = -1;
48241 getParams : function(q){
48243 //p[this.queryParam] = q;
48246 p.limit = this.pageSize;
48252 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48254 collapse : function(){
48259 collapseIf : function(e){
48264 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48266 expand : function(){
48274 * @cfg {Boolean} grow
48278 * @cfg {Number} growMin
48282 * @cfg {Number} growMax
48290 setWidth : function()
48294 getResizeEl : function(){
48297 });//<script type="text/javasscript">
48301 * @class Roo.DDView
48302 * A DnD enabled version of Roo.View.
48303 * @param {Element/String} container The Element in which to create the View.
48304 * @param {String} tpl The template string used to create the markup for each element of the View
48305 * @param {Object} config The configuration properties. These include all the config options of
48306 * {@link Roo.View} plus some specific to this class.<br>
48308 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48309 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48311 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48312 .x-view-drag-insert-above {
48313 border-top:1px dotted #3366cc;
48315 .x-view-drag-insert-below {
48316 border-bottom:1px dotted #3366cc;
48322 Roo.DDView = function(container, tpl, config) {
48323 Roo.DDView.superclass.constructor.apply(this, arguments);
48324 this.getEl().setStyle("outline", "0px none");
48325 this.getEl().unselectable();
48326 if (this.dragGroup) {
48327 this.setDraggable(this.dragGroup.split(","));
48329 if (this.dropGroup) {
48330 this.setDroppable(this.dropGroup.split(","));
48332 if (this.deletable) {
48333 this.setDeletable();
48335 this.isDirtyFlag = false;
48341 Roo.extend(Roo.DDView, Roo.View, {
48342 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48343 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48344 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48345 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48349 reset: Roo.emptyFn,
48351 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48353 validate: function() {
48357 destroy: function() {
48358 this.purgeListeners();
48359 this.getEl.removeAllListeners();
48360 this.getEl().remove();
48361 if (this.dragZone) {
48362 if (this.dragZone.destroy) {
48363 this.dragZone.destroy();
48366 if (this.dropZone) {
48367 if (this.dropZone.destroy) {
48368 this.dropZone.destroy();
48373 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48374 getName: function() {
48378 /** Loads the View from a JSON string representing the Records to put into the Store. */
48379 setValue: function(v) {
48381 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48384 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48385 this.store.proxy = new Roo.data.MemoryProxy(data);
48389 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48390 getValue: function() {
48392 this.store.each(function(rec) {
48393 result += rec.id + ',';
48395 return result.substr(0, result.length - 1) + ')';
48398 getIds: function() {
48399 var i = 0, result = new Array(this.store.getCount());
48400 this.store.each(function(rec) {
48401 result[i++] = rec.id;
48406 isDirty: function() {
48407 return this.isDirtyFlag;
48411 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48412 * whole Element becomes the target, and this causes the drop gesture to append.
48414 getTargetFromEvent : function(e) {
48415 var target = e.getTarget();
48416 while ((target !== null) && (target.parentNode != this.el.dom)) {
48417 target = target.parentNode;
48420 target = this.el.dom.lastChild || this.el.dom;
48426 * Create the drag data which consists of an object which has the property "ddel" as
48427 * the drag proxy element.
48429 getDragData : function(e) {
48430 var target = this.findItemFromChild(e.getTarget());
48432 this.handleSelection(e);
48433 var selNodes = this.getSelectedNodes();
48436 copy: this.copy || (this.allowCopy && e.ctrlKey),
48440 var selectedIndices = this.getSelectedIndexes();
48441 for (var i = 0; i < selectedIndices.length; i++) {
48442 dragData.records.push(this.store.getAt(selectedIndices[i]));
48444 if (selNodes.length == 1) {
48445 dragData.ddel = target.cloneNode(true); // the div element
48447 var div = document.createElement('div'); // create the multi element drag "ghost"
48448 div.className = 'multi-proxy';
48449 for (var i = 0, len = selNodes.length; i < len; i++) {
48450 div.appendChild(selNodes[i].cloneNode(true));
48452 dragData.ddel = div;
48454 //console.log(dragData)
48455 //console.log(dragData.ddel.innerHTML)
48458 //console.log('nodragData')
48462 /** Specify to which ddGroup items in this DDView may be dragged. */
48463 setDraggable: function(ddGroup) {
48464 if (ddGroup instanceof Array) {
48465 Roo.each(ddGroup, this.setDraggable, this);
48468 if (this.dragZone) {
48469 this.dragZone.addToGroup(ddGroup);
48471 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48472 containerScroll: true,
48476 // Draggability implies selection. DragZone's mousedown selects the element.
48477 if (!this.multiSelect) { this.singleSelect = true; }
48479 // Wire the DragZone's handlers up to methods in *this*
48480 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48484 /** Specify from which ddGroup this DDView accepts drops. */
48485 setDroppable: function(ddGroup) {
48486 if (ddGroup instanceof Array) {
48487 Roo.each(ddGroup, this.setDroppable, this);
48490 if (this.dropZone) {
48491 this.dropZone.addToGroup(ddGroup);
48493 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48494 containerScroll: true,
48498 // Wire the DropZone's handlers up to methods in *this*
48499 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48500 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48501 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48502 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48503 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48507 /** Decide whether to drop above or below a View node. */
48508 getDropPoint : function(e, n, dd){
48509 if (n == this.el.dom) { return "above"; }
48510 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48511 var c = t + (b - t) / 2;
48512 var y = Roo.lib.Event.getPageY(e);
48520 onNodeEnter : function(n, dd, e, data){
48524 onNodeOver : function(n, dd, e, data){
48525 var pt = this.getDropPoint(e, n, dd);
48526 // set the insert point style on the target node
48527 var dragElClass = this.dropNotAllowed;
48530 if (pt == "above"){
48531 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48532 targetElClass = "x-view-drag-insert-above";
48534 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48535 targetElClass = "x-view-drag-insert-below";
48537 if (this.lastInsertClass != targetElClass){
48538 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48539 this.lastInsertClass = targetElClass;
48542 return dragElClass;
48545 onNodeOut : function(n, dd, e, data){
48546 this.removeDropIndicators(n);
48549 onNodeDrop : function(n, dd, e, data){
48550 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48553 var pt = this.getDropPoint(e, n, dd);
48554 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48555 if (pt == "below") { insertAt++; }
48556 for (var i = 0; i < data.records.length; i++) {
48557 var r = data.records[i];
48558 var dup = this.store.getById(r.id);
48559 if (dup && (dd != this.dragZone)) {
48560 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48563 this.store.insert(insertAt++, r.copy());
48565 data.source.isDirtyFlag = true;
48567 this.store.insert(insertAt++, r);
48569 this.isDirtyFlag = true;
48572 this.dragZone.cachedTarget = null;
48576 removeDropIndicators : function(n){
48578 Roo.fly(n).removeClass([
48579 "x-view-drag-insert-above",
48580 "x-view-drag-insert-below"]);
48581 this.lastInsertClass = "_noclass";
48586 * Utility method. Add a delete option to the DDView's context menu.
48587 * @param {String} imageUrl The URL of the "delete" icon image.
48589 setDeletable: function(imageUrl) {
48590 if (!this.singleSelect && !this.multiSelect) {
48591 this.singleSelect = true;
48593 var c = this.getContextMenu();
48594 this.contextMenu.on("itemclick", function(item) {
48597 this.remove(this.getSelectedIndexes());
48601 this.contextMenu.add({
48608 /** Return the context menu for this DDView. */
48609 getContextMenu: function() {
48610 if (!this.contextMenu) {
48611 // Create the View's context menu
48612 this.contextMenu = new Roo.menu.Menu({
48613 id: this.id + "-contextmenu"
48615 this.el.on("contextmenu", this.showContextMenu, this);
48617 return this.contextMenu;
48620 disableContextMenu: function() {
48621 if (this.contextMenu) {
48622 this.el.un("contextmenu", this.showContextMenu, this);
48626 showContextMenu: function(e, item) {
48627 item = this.findItemFromChild(e.getTarget());
48630 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48631 this.contextMenu.showAt(e.getXY());
48636 * Remove {@link Roo.data.Record}s at the specified indices.
48637 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48639 remove: function(selectedIndices) {
48640 selectedIndices = [].concat(selectedIndices);
48641 for (var i = 0; i < selectedIndices.length; i++) {
48642 var rec = this.store.getAt(selectedIndices[i]);
48643 this.store.remove(rec);
48648 * Double click fires the event, but also, if this is draggable, and there is only one other
48649 * related DropZone, it transfers the selected node.
48651 onDblClick : function(e){
48652 var item = this.findItemFromChild(e.getTarget());
48654 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48657 if (this.dragGroup) {
48658 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48659 while (targets.indexOf(this.dropZone) > -1) {
48660 targets.remove(this.dropZone);
48662 if (targets.length == 1) {
48663 this.dragZone.cachedTarget = null;
48664 var el = Roo.get(targets[0].getEl());
48665 var box = el.getBox(true);
48666 targets[0].onNodeDrop(el.dom, {
48668 xy: [box.x, box.y + box.height - 1]
48669 }, null, this.getDragData(e));
48675 handleSelection: function(e) {
48676 this.dragZone.cachedTarget = null;
48677 var item = this.findItemFromChild(e.getTarget());
48679 this.clearSelections(true);
48682 if (item && (this.multiSelect || this.singleSelect)){
48683 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48684 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48685 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48686 this.unselect(item);
48688 this.select(item, this.multiSelect && e.ctrlKey);
48689 this.lastSelection = item;
48694 onItemClick : function(item, index, e){
48695 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48701 unselect : function(nodeInfo, suppressEvent){
48702 var node = this.getNode(nodeInfo);
48703 if(node && this.isSelected(node)){
48704 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48705 Roo.fly(node).removeClass(this.selectedClass);
48706 this.selections.remove(node);
48707 if(!suppressEvent){
48708 this.fireEvent("selectionchange", this, this.selections);
48716 * Ext JS Library 1.1.1
48717 * Copyright(c) 2006-2007, Ext JS, LLC.
48719 * Originally Released Under LGPL - original licence link has changed is not relivant.
48722 * <script type="text/javascript">
48726 * @class Roo.LayoutManager
48727 * @extends Roo.util.Observable
48728 * Base class for layout managers.
48730 Roo.LayoutManager = function(container, config){
48731 Roo.LayoutManager.superclass.constructor.call(this);
48732 this.el = Roo.get(container);
48733 // ie scrollbar fix
48734 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48735 document.body.scroll = "no";
48736 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48737 this.el.position('relative');
48739 this.id = this.el.id;
48740 this.el.addClass("x-layout-container");
48741 /** false to disable window resize monitoring @type Boolean */
48742 this.monitorWindowResize = true;
48747 * Fires when a layout is performed.
48748 * @param {Roo.LayoutManager} this
48752 * @event regionresized
48753 * Fires when the user resizes a region.
48754 * @param {Roo.LayoutRegion} region The resized region
48755 * @param {Number} newSize The new size (width for east/west, height for north/south)
48757 "regionresized" : true,
48759 * @event regioncollapsed
48760 * Fires when a region is collapsed.
48761 * @param {Roo.LayoutRegion} region The collapsed region
48763 "regioncollapsed" : true,
48765 * @event regionexpanded
48766 * Fires when a region is expanded.
48767 * @param {Roo.LayoutRegion} region The expanded region
48769 "regionexpanded" : true
48771 this.updating = false;
48772 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48775 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48777 * Returns true if this layout is currently being updated
48778 * @return {Boolean}
48780 isUpdating : function(){
48781 return this.updating;
48785 * Suspend the LayoutManager from doing auto-layouts while
48786 * making multiple add or remove calls
48788 beginUpdate : function(){
48789 this.updating = true;
48793 * Restore auto-layouts and optionally disable the manager from performing a layout
48794 * @param {Boolean} noLayout true to disable a layout update
48796 endUpdate : function(noLayout){
48797 this.updating = false;
48803 layout: function(){
48807 onRegionResized : function(region, newSize){
48808 this.fireEvent("regionresized", region, newSize);
48812 onRegionCollapsed : function(region){
48813 this.fireEvent("regioncollapsed", region);
48816 onRegionExpanded : function(region){
48817 this.fireEvent("regionexpanded", region);
48821 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48822 * performs box-model adjustments.
48823 * @return {Object} The size as an object {width: (the width), height: (the height)}
48825 getViewSize : function(){
48827 if(this.el.dom != document.body){
48828 size = this.el.getSize();
48830 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48832 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48833 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48838 * Returns the Element this layout is bound to.
48839 * @return {Roo.Element}
48841 getEl : function(){
48846 * Returns the specified region.
48847 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48848 * @return {Roo.LayoutRegion}
48850 getRegion : function(target){
48851 return this.regions[target.toLowerCase()];
48854 onWindowResize : function(){
48855 if(this.monitorWindowResize){
48861 * Ext JS Library 1.1.1
48862 * Copyright(c) 2006-2007, Ext JS, LLC.
48864 * Originally Released Under LGPL - original licence link has changed is not relivant.
48867 * <script type="text/javascript">
48870 * @class Roo.BorderLayout
48871 * @extends Roo.LayoutManager
48872 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48873 * please see: <br><br>
48874 * <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>
48875 * <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>
48878 var layout = new Roo.BorderLayout(document.body, {
48912 preferredTabWidth: 150
48917 var CP = Roo.ContentPanel;
48919 layout.beginUpdate();
48920 layout.add("north", new CP("north", "North"));
48921 layout.add("south", new CP("south", {title: "South", closable: true}));
48922 layout.add("west", new CP("west", {title: "West"}));
48923 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48924 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48925 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48926 layout.getRegion("center").showPanel("center1");
48927 layout.endUpdate();
48930 <b>The container the layout is rendered into can be either the body element or any other element.
48931 If it is not the body element, the container needs to either be an absolute positioned element,
48932 or you will need to add "position:relative" to the css of the container. You will also need to specify
48933 the container size if it is not the body element.</b>
48936 * Create a new BorderLayout
48937 * @param {String/HTMLElement/Element} container The container this layout is bound to
48938 * @param {Object} config Configuration options
48940 Roo.BorderLayout = function(container, config){
48941 config = config || {};
48942 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48943 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48944 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48945 var target = this.factory.validRegions[i];
48946 if(config[target]){
48947 this.addRegion(target, config[target]);
48952 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48954 * Creates and adds a new region if it doesn't already exist.
48955 * @param {String} target The target region key (north, south, east, west or center).
48956 * @param {Object} config The regions config object
48957 * @return {BorderLayoutRegion} The new region
48959 addRegion : function(target, config){
48960 if(!this.regions[target]){
48961 var r = this.factory.create(target, this, config);
48962 this.bindRegion(target, r);
48964 return this.regions[target];
48968 bindRegion : function(name, r){
48969 this.regions[name] = r;
48970 r.on("visibilitychange", this.layout, this);
48971 r.on("paneladded", this.layout, this);
48972 r.on("panelremoved", this.layout, this);
48973 r.on("invalidated", this.layout, this);
48974 r.on("resized", this.onRegionResized, this);
48975 r.on("collapsed", this.onRegionCollapsed, this);
48976 r.on("expanded", this.onRegionExpanded, this);
48980 * Performs a layout update.
48982 layout : function(){
48983 if(this.updating) return;
48984 var size = this.getViewSize();
48985 var w = size.width;
48986 var h = size.height;
48991 //var x = 0, y = 0;
48993 var rs = this.regions;
48994 var north = rs["north"];
48995 var south = rs["south"];
48996 var west = rs["west"];
48997 var east = rs["east"];
48998 var center = rs["center"];
48999 //if(this.hideOnLayout){ // not supported anymore
49000 //c.el.setStyle("display", "none");
49002 if(north && north.isVisible()){
49003 var b = north.getBox();
49004 var m = north.getMargins();
49005 b.width = w - (m.left+m.right);
49008 centerY = b.height + b.y + m.bottom;
49009 centerH -= centerY;
49010 north.updateBox(this.safeBox(b));
49012 if(south && south.isVisible()){
49013 var b = south.getBox();
49014 var m = south.getMargins();
49015 b.width = w - (m.left+m.right);
49017 var totalHeight = (b.height + m.top + m.bottom);
49018 b.y = h - totalHeight + m.top;
49019 centerH -= totalHeight;
49020 south.updateBox(this.safeBox(b));
49022 if(west && west.isVisible()){
49023 var b = west.getBox();
49024 var m = west.getMargins();
49025 b.height = centerH - (m.top+m.bottom);
49027 b.y = centerY + m.top;
49028 var totalWidth = (b.width + m.left + m.right);
49029 centerX += totalWidth;
49030 centerW -= totalWidth;
49031 west.updateBox(this.safeBox(b));
49033 if(east && east.isVisible()){
49034 var b = east.getBox();
49035 var m = east.getMargins();
49036 b.height = centerH - (m.top+m.bottom);
49037 var totalWidth = (b.width + m.left + m.right);
49038 b.x = w - totalWidth + m.left;
49039 b.y = centerY + m.top;
49040 centerW -= totalWidth;
49041 east.updateBox(this.safeBox(b));
49044 var m = center.getMargins();
49046 x: centerX + m.left,
49047 y: centerY + m.top,
49048 width: centerW - (m.left+m.right),
49049 height: centerH - (m.top+m.bottom)
49051 //if(this.hideOnLayout){
49052 //center.el.setStyle("display", "block");
49054 center.updateBox(this.safeBox(centerBox));
49057 this.fireEvent("layout", this);
49061 safeBox : function(box){
49062 box.width = Math.max(0, box.width);
49063 box.height = Math.max(0, box.height);
49068 * Adds a ContentPanel (or subclass) to this layout.
49069 * @param {String} target The target region key (north, south, east, west or center).
49070 * @param {Roo.ContentPanel} panel The panel to add
49071 * @return {Roo.ContentPanel} The added panel
49073 add : function(target, panel){
49075 target = target.toLowerCase();
49076 return this.regions[target].add(panel);
49080 * Remove a ContentPanel (or subclass) to this layout.
49081 * @param {String} target The target region key (north, south, east, west or center).
49082 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49083 * @return {Roo.ContentPanel} The removed panel
49085 remove : function(target, panel){
49086 target = target.toLowerCase();
49087 return this.regions[target].remove(panel);
49091 * Searches all regions for a panel with the specified id
49092 * @param {String} panelId
49093 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49095 findPanel : function(panelId){
49096 var rs = this.regions;
49097 for(var target in rs){
49098 if(typeof rs[target] != "function"){
49099 var p = rs[target].getPanel(panelId);
49109 * Searches all regions for a panel with the specified id and activates (shows) it.
49110 * @param {String/ContentPanel} panelId The panels id or the panel itself
49111 * @return {Roo.ContentPanel} The shown panel or null
49113 showPanel : function(panelId) {
49114 var rs = this.regions;
49115 for(var target in rs){
49116 var r = rs[target];
49117 if(typeof r != "function"){
49118 if(r.hasPanel(panelId)){
49119 return r.showPanel(panelId);
49127 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49128 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49130 restoreState : function(provider){
49132 provider = Roo.state.Manager;
49134 var sm = new Roo.LayoutStateManager();
49135 sm.init(this, provider);
49139 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49140 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49141 * a valid ContentPanel config object. Example:
49143 // Create the main layout
49144 var layout = new Roo.BorderLayout('main-ct', {
49155 // Create and add multiple ContentPanels at once via configs
49158 id: 'source-files',
49160 title:'Ext Source Files',
49173 * @param {Object} regions An object containing ContentPanel configs by region name
49175 batchAdd : function(regions){
49176 this.beginUpdate();
49177 for(var rname in regions){
49178 var lr = this.regions[rname];
49180 this.addTypedPanels(lr, regions[rname]);
49187 addTypedPanels : function(lr, ps){
49188 if(typeof ps == 'string'){
49189 lr.add(new Roo.ContentPanel(ps));
49191 else if(ps instanceof Array){
49192 for(var i =0, len = ps.length; i < len; i++){
49193 this.addTypedPanels(lr, ps[i]);
49196 else if(!ps.events){ // raw config?
49198 delete ps.el; // prevent conflict
49199 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49201 else { // panel object assumed!
49206 * Adds a xtype elements to the layout.
49210 xtype : 'ContentPanel',
49217 xtype : 'NestedLayoutPanel',
49223 items : [ ... list of content panels or nested layout panels.. ]
49227 * @param {Object} cfg Xtype definition of item to add.
49229 addxtype : function(cfg)
49231 // basically accepts a pannel...
49232 // can accept a layout region..!?!?
49233 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49235 if (!cfg.xtype.match(/Panel$/)) {
49240 if (typeof(cfg.region) == 'undefined') {
49241 Roo.log("Failed to add Panel, region was not set");
49245 var region = cfg.region;
49251 xitems = cfg.items;
49258 case 'ContentPanel': // ContentPanel (el, cfg)
49259 case 'ScrollPanel': // ContentPanel (el, cfg)
49261 if(cfg.autoCreate) {
49262 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49264 var el = this.el.createChild();
49265 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49268 this.add(region, ret);
49272 case 'TreePanel': // our new panel!
49273 cfg.el = this.el.createChild();
49274 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49275 this.add(region, ret);
49278 case 'NestedLayoutPanel':
49279 // create a new Layout (which is a Border Layout...
49280 var el = this.el.createChild();
49281 var clayout = cfg.layout;
49283 clayout.items = clayout.items || [];
49284 // replace this exitems with the clayout ones..
49285 xitems = clayout.items;
49288 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49289 cfg.background = false;
49291 var layout = new Roo.BorderLayout(el, clayout);
49293 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49294 //console.log('adding nested layout panel ' + cfg.toSource());
49295 this.add(region, ret);
49296 nb = {}; /// find first...
49301 // needs grid and region
49303 //var el = this.getRegion(region).el.createChild();
49304 var el = this.el.createChild();
49305 // create the grid first...
49307 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49309 if (region == 'center' && this.active ) {
49310 cfg.background = false;
49312 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49314 this.add(region, ret);
49315 if (cfg.background) {
49316 ret.on('activate', function(gp) {
49317 if (!gp.grid.rendered) {
49332 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49334 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49335 this.add(region, ret);
49338 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49342 // GridPanel (grid, cfg)
49345 this.beginUpdate();
49349 Roo.each(xitems, function(i) {
49350 region = nb && i.region ? i.region : false;
49352 var add = ret.addxtype(i);
49355 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49356 if (!i.background) {
49357 abn[region] = nb[region] ;
49364 // make the last non-background panel active..
49365 //if (nb) { Roo.log(abn); }
49368 for(var r in abn) {
49369 region = this.getRegion(r);
49371 // tried using nb[r], but it does not work..
49373 region.showPanel(abn[r]);
49384 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49385 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49386 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49387 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49390 var CP = Roo.ContentPanel;
49392 var layout = Roo.BorderLayout.create({
49396 panels: [new CP("north", "North")]
49405 panels: [new CP("west", {title: "West"})]
49414 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49423 panels: [new CP("south", {title: "South", closable: true})]
49430 preferredTabWidth: 150,
49432 new CP("center1", {title: "Close Me", closable: true}),
49433 new CP("center2", {title: "Center Panel", closable: false})
49438 layout.getRegion("center").showPanel("center1");
49443 Roo.BorderLayout.create = function(config, targetEl){
49444 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49445 layout.beginUpdate();
49446 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49447 for(var j = 0, jlen = regions.length; j < jlen; j++){
49448 var lr = regions[j];
49449 if(layout.regions[lr] && config[lr].panels){
49450 var r = layout.regions[lr];
49451 var ps = config[lr].panels;
49452 layout.addTypedPanels(r, ps);
49455 layout.endUpdate();
49460 Roo.BorderLayout.RegionFactory = {
49462 validRegions : ["north","south","east","west","center"],
49465 create : function(target, mgr, config){
49466 target = target.toLowerCase();
49467 if(config.lightweight || config.basic){
49468 return new Roo.BasicLayoutRegion(mgr, config, target);
49472 return new Roo.NorthLayoutRegion(mgr, config);
49474 return new Roo.SouthLayoutRegion(mgr, config);
49476 return new Roo.EastLayoutRegion(mgr, config);
49478 return new Roo.WestLayoutRegion(mgr, config);
49480 return new Roo.CenterLayoutRegion(mgr, config);
49482 throw 'Layout region "'+target+'" not supported.';
49486 * Ext JS Library 1.1.1
49487 * Copyright(c) 2006-2007, Ext JS, LLC.
49489 * Originally Released Under LGPL - original licence link has changed is not relivant.
49492 * <script type="text/javascript">
49496 * @class Roo.BasicLayoutRegion
49497 * @extends Roo.util.Observable
49498 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49499 * and does not have a titlebar, tabs or any other features. All it does is size and position
49500 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49502 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49504 this.position = pos;
49507 * @scope Roo.BasicLayoutRegion
49511 * @event beforeremove
49512 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49513 * @param {Roo.LayoutRegion} this
49514 * @param {Roo.ContentPanel} panel The panel
49515 * @param {Object} e The cancel event object
49517 "beforeremove" : true,
49519 * @event invalidated
49520 * Fires when the layout for this region is changed.
49521 * @param {Roo.LayoutRegion} this
49523 "invalidated" : true,
49525 * @event visibilitychange
49526 * Fires when this region is shown or hidden
49527 * @param {Roo.LayoutRegion} this
49528 * @param {Boolean} visibility true or false
49530 "visibilitychange" : true,
49532 * @event paneladded
49533 * Fires when a panel is added.
49534 * @param {Roo.LayoutRegion} this
49535 * @param {Roo.ContentPanel} panel The panel
49537 "paneladded" : true,
49539 * @event panelremoved
49540 * Fires when a panel is removed.
49541 * @param {Roo.LayoutRegion} this
49542 * @param {Roo.ContentPanel} panel The panel
49544 "panelremoved" : true,
49547 * Fires when this region is collapsed.
49548 * @param {Roo.LayoutRegion} this
49550 "collapsed" : true,
49553 * Fires when this region is expanded.
49554 * @param {Roo.LayoutRegion} this
49559 * Fires when this region is slid into view.
49560 * @param {Roo.LayoutRegion} this
49562 "slideshow" : true,
49565 * Fires when this region slides out of view.
49566 * @param {Roo.LayoutRegion} this
49568 "slidehide" : true,
49570 * @event panelactivated
49571 * Fires when a panel is activated.
49572 * @param {Roo.LayoutRegion} this
49573 * @param {Roo.ContentPanel} panel The activated panel
49575 "panelactivated" : true,
49578 * Fires when the user resizes this region.
49579 * @param {Roo.LayoutRegion} this
49580 * @param {Number} newSize The new size (width for east/west, height for north/south)
49584 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49585 this.panels = new Roo.util.MixedCollection();
49586 this.panels.getKey = this.getPanelId.createDelegate(this);
49588 this.activePanel = null;
49589 // ensure listeners are added...
49591 if (config.listeners || config.events) {
49592 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49593 listeners : config.listeners || {},
49594 events : config.events || {}
49598 if(skipConfig !== true){
49599 this.applyConfig(config);
49603 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49604 getPanelId : function(p){
49608 applyConfig : function(config){
49609 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49610 this.config = config;
49615 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49616 * the width, for horizontal (north, south) the height.
49617 * @param {Number} newSize The new width or height
49619 resizeTo : function(newSize){
49620 var el = this.el ? this.el :
49621 (this.activePanel ? this.activePanel.getEl() : null);
49623 switch(this.position){
49626 el.setWidth(newSize);
49627 this.fireEvent("resized", this, newSize);
49631 el.setHeight(newSize);
49632 this.fireEvent("resized", this, newSize);
49638 getBox : function(){
49639 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49642 getMargins : function(){
49643 return this.margins;
49646 updateBox : function(box){
49648 var el = this.activePanel.getEl();
49649 el.dom.style.left = box.x + "px";
49650 el.dom.style.top = box.y + "px";
49651 this.activePanel.setSize(box.width, box.height);
49655 * Returns the container element for this region.
49656 * @return {Roo.Element}
49658 getEl : function(){
49659 return this.activePanel;
49663 * Returns true if this region is currently visible.
49664 * @return {Boolean}
49666 isVisible : function(){
49667 return this.activePanel ? true : false;
49670 setActivePanel : function(panel){
49671 panel = this.getPanel(panel);
49672 if(this.activePanel && this.activePanel != panel){
49673 this.activePanel.setActiveState(false);
49674 this.activePanel.getEl().setLeftTop(-10000,-10000);
49676 this.activePanel = panel;
49677 panel.setActiveState(true);
49679 panel.setSize(this.box.width, this.box.height);
49681 this.fireEvent("panelactivated", this, panel);
49682 this.fireEvent("invalidated");
49686 * Show the specified panel.
49687 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49688 * @return {Roo.ContentPanel} The shown panel or null
49690 showPanel : function(panel){
49691 if(panel = this.getPanel(panel)){
49692 this.setActivePanel(panel);
49698 * Get the active panel for this region.
49699 * @return {Roo.ContentPanel} The active panel or null
49701 getActivePanel : function(){
49702 return this.activePanel;
49706 * Add the passed ContentPanel(s)
49707 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49708 * @return {Roo.ContentPanel} The panel added (if only one was added)
49710 add : function(panel){
49711 if(arguments.length > 1){
49712 for(var i = 0, len = arguments.length; i < len; i++) {
49713 this.add(arguments[i]);
49717 if(this.hasPanel(panel)){
49718 this.showPanel(panel);
49721 var el = panel.getEl();
49722 if(el.dom.parentNode != this.mgr.el.dom){
49723 this.mgr.el.dom.appendChild(el.dom);
49725 if(panel.setRegion){
49726 panel.setRegion(this);
49728 this.panels.add(panel);
49729 el.setStyle("position", "absolute");
49730 if(!panel.background){
49731 this.setActivePanel(panel);
49732 if(this.config.initialSize && this.panels.getCount()==1){
49733 this.resizeTo(this.config.initialSize);
49736 this.fireEvent("paneladded", this, panel);
49741 * Returns true if the panel is in this region.
49742 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49743 * @return {Boolean}
49745 hasPanel : function(panel){
49746 if(typeof panel == "object"){ // must be panel obj
49747 panel = panel.getId();
49749 return this.getPanel(panel) ? true : false;
49753 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49754 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49755 * @param {Boolean} preservePanel Overrides the config preservePanel option
49756 * @return {Roo.ContentPanel} The panel that was removed
49758 remove : function(panel, preservePanel){
49759 panel = this.getPanel(panel);
49764 this.fireEvent("beforeremove", this, panel, e);
49765 if(e.cancel === true){
49768 var panelId = panel.getId();
49769 this.panels.removeKey(panelId);
49774 * Returns the panel specified or null if it's not in this region.
49775 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49776 * @return {Roo.ContentPanel}
49778 getPanel : function(id){
49779 if(typeof id == "object"){ // must be panel obj
49782 return this.panels.get(id);
49786 * Returns this regions position (north/south/east/west/center).
49789 getPosition: function(){
49790 return this.position;
49794 * Ext JS Library 1.1.1
49795 * Copyright(c) 2006-2007, Ext JS, LLC.
49797 * Originally Released Under LGPL - original licence link has changed is not relivant.
49800 * <script type="text/javascript">
49804 * @class Roo.LayoutRegion
49805 * @extends Roo.BasicLayoutRegion
49806 * This class represents a region in a layout manager.
49807 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49808 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49809 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49810 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49811 * @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})
49812 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49813 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49814 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49815 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49816 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49817 * @cfg {String} title The title for the region (overrides panel titles)
49818 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49819 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49820 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49821 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49822 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49823 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49824 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49825 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49826 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49827 * @cfg {Boolean} showPin True to show a pin button
49828 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49829 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49830 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49831 * @cfg {Number} width For East/West panels
49832 * @cfg {Number} height For North/South panels
49833 * @cfg {Boolean} split To show the splitter
49834 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49836 Roo.LayoutRegion = function(mgr, config, pos){
49837 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49838 var dh = Roo.DomHelper;
49839 /** This region's container element
49840 * @type Roo.Element */
49841 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49842 /** This region's title element
49843 * @type Roo.Element */
49845 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49846 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49847 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49849 this.titleEl.enableDisplayMode();
49850 /** This region's title text element
49851 * @type HTMLElement */
49852 this.titleTextEl = this.titleEl.dom.firstChild;
49853 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49854 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49855 this.closeBtn.enableDisplayMode();
49856 this.closeBtn.on("click", this.closeClicked, this);
49857 this.closeBtn.hide();
49859 this.createBody(config);
49860 this.visible = true;
49861 this.collapsed = false;
49863 if(config.hideWhenEmpty){
49865 this.on("paneladded", this.validateVisibility, this);
49866 this.on("panelremoved", this.validateVisibility, this);
49868 this.applyConfig(config);
49871 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49873 createBody : function(){
49874 /** This region's body element
49875 * @type Roo.Element */
49876 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49879 applyConfig : function(c){
49880 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49881 var dh = Roo.DomHelper;
49882 if(c.titlebar !== false){
49883 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49884 this.collapseBtn.on("click", this.collapse, this);
49885 this.collapseBtn.enableDisplayMode();
49887 if(c.showPin === true || this.showPin){
49888 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49889 this.stickBtn.enableDisplayMode();
49890 this.stickBtn.on("click", this.expand, this);
49891 this.stickBtn.hide();
49894 /** This region's collapsed element
49895 * @type Roo.Element */
49896 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49897 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49899 if(c.floatable !== false){
49900 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49901 this.collapsedEl.on("click", this.collapseClick, this);
49904 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49905 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49906 id: "message", unselectable: "on", style:{"float":"left"}});
49907 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49909 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49910 this.expandBtn.on("click", this.expand, this);
49912 if(this.collapseBtn){
49913 this.collapseBtn.setVisible(c.collapsible == true);
49915 this.cmargins = c.cmargins || this.cmargins ||
49916 (this.position == "west" || this.position == "east" ?
49917 {top: 0, left: 2, right:2, bottom: 0} :
49918 {top: 2, left: 0, right:0, bottom: 2});
49919 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49920 this.bottomTabs = c.tabPosition != "top";
49921 this.autoScroll = c.autoScroll || false;
49922 if(this.autoScroll){
49923 this.bodyEl.setStyle("overflow", "auto");
49925 this.bodyEl.setStyle("overflow", "hidden");
49927 //if(c.titlebar !== false){
49928 if((!c.titlebar && !c.title) || c.titlebar === false){
49929 this.titleEl.hide();
49931 this.titleEl.show();
49933 this.titleTextEl.innerHTML = c.title;
49937 this.duration = c.duration || .30;
49938 this.slideDuration = c.slideDuration || .45;
49941 this.collapse(true);
49948 * Returns true if this region is currently visible.
49949 * @return {Boolean}
49951 isVisible : function(){
49952 return this.visible;
49956 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49957 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49959 setCollapsedTitle : function(title){
49960 title = title || " ";
49961 if(this.collapsedTitleTextEl){
49962 this.collapsedTitleTextEl.innerHTML = title;
49966 getBox : function(){
49968 if(!this.collapsed){
49969 b = this.el.getBox(false, true);
49971 b = this.collapsedEl.getBox(false, true);
49976 getMargins : function(){
49977 return this.collapsed ? this.cmargins : this.margins;
49980 highlight : function(){
49981 this.el.addClass("x-layout-panel-dragover");
49984 unhighlight : function(){
49985 this.el.removeClass("x-layout-panel-dragover");
49988 updateBox : function(box){
49990 if(!this.collapsed){
49991 this.el.dom.style.left = box.x + "px";
49992 this.el.dom.style.top = box.y + "px";
49993 this.updateBody(box.width, box.height);
49995 this.collapsedEl.dom.style.left = box.x + "px";
49996 this.collapsedEl.dom.style.top = box.y + "px";
49997 this.collapsedEl.setSize(box.width, box.height);
50000 this.tabs.autoSizeTabs();
50004 updateBody : function(w, h){
50006 this.el.setWidth(w);
50007 w -= this.el.getBorderWidth("rl");
50008 if(this.config.adjustments){
50009 w += this.config.adjustments[0];
50013 this.el.setHeight(h);
50014 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50015 h -= this.el.getBorderWidth("tb");
50016 if(this.config.adjustments){
50017 h += this.config.adjustments[1];
50019 this.bodyEl.setHeight(h);
50021 h = this.tabs.syncHeight(h);
50024 if(this.panelSize){
50025 w = w !== null ? w : this.panelSize.width;
50026 h = h !== null ? h : this.panelSize.height;
50028 if(this.activePanel){
50029 var el = this.activePanel.getEl();
50030 w = w !== null ? w : el.getWidth();
50031 h = h !== null ? h : el.getHeight();
50032 this.panelSize = {width: w, height: h};
50033 this.activePanel.setSize(w, h);
50035 if(Roo.isIE && this.tabs){
50036 this.tabs.el.repaint();
50041 * Returns the container element for this region.
50042 * @return {Roo.Element}
50044 getEl : function(){
50049 * Hides this region.
50052 if(!this.collapsed){
50053 this.el.dom.style.left = "-2000px";
50056 this.collapsedEl.dom.style.left = "-2000px";
50057 this.collapsedEl.hide();
50059 this.visible = false;
50060 this.fireEvent("visibilitychange", this, false);
50064 * Shows this region if it was previously hidden.
50067 if(!this.collapsed){
50070 this.collapsedEl.show();
50072 this.visible = true;
50073 this.fireEvent("visibilitychange", this, true);
50076 closeClicked : function(){
50077 if(this.activePanel){
50078 this.remove(this.activePanel);
50082 collapseClick : function(e){
50084 e.stopPropagation();
50087 e.stopPropagation();
50093 * Collapses this region.
50094 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50096 collapse : function(skipAnim){
50097 if(this.collapsed) return;
50098 this.collapsed = true;
50100 this.split.el.hide();
50102 if(this.config.animate && skipAnim !== true){
50103 this.fireEvent("invalidated", this);
50104 this.animateCollapse();
50106 this.el.setLocation(-20000,-20000);
50108 this.collapsedEl.show();
50109 this.fireEvent("collapsed", this);
50110 this.fireEvent("invalidated", this);
50114 animateCollapse : function(){
50119 * Expands this region if it was previously collapsed.
50120 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50121 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50123 expand : function(e, skipAnim){
50124 if(e) e.stopPropagation();
50125 if(!this.collapsed || this.el.hasActiveFx()) return;
50127 this.afterSlideIn();
50130 this.collapsed = false;
50131 if(this.config.animate && skipAnim !== true){
50132 this.animateExpand();
50136 this.split.el.show();
50138 this.collapsedEl.setLocation(-2000,-2000);
50139 this.collapsedEl.hide();
50140 this.fireEvent("invalidated", this);
50141 this.fireEvent("expanded", this);
50145 animateExpand : function(){
50149 initTabs : function()
50151 this.bodyEl.setStyle("overflow", "hidden");
50152 var ts = new Roo.TabPanel(
50155 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50156 disableTooltips: this.config.disableTabTips,
50157 toolbar : this.config.toolbar
50160 if(this.config.hideTabs){
50161 ts.stripWrap.setDisplayed(false);
50164 ts.resizeTabs = this.config.resizeTabs === true;
50165 ts.minTabWidth = this.config.minTabWidth || 40;
50166 ts.maxTabWidth = this.config.maxTabWidth || 250;
50167 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50168 ts.monitorResize = false;
50169 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50170 ts.bodyEl.addClass('x-layout-tabs-body');
50171 this.panels.each(this.initPanelAsTab, this);
50174 initPanelAsTab : function(panel){
50175 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50176 this.config.closeOnTab && panel.isClosable());
50177 if(panel.tabTip !== undefined){
50178 ti.setTooltip(panel.tabTip);
50180 ti.on("activate", function(){
50181 this.setActivePanel(panel);
50183 if(this.config.closeOnTab){
50184 ti.on("beforeclose", function(t, e){
50186 this.remove(panel);
50192 updatePanelTitle : function(panel, title){
50193 if(this.activePanel == panel){
50194 this.updateTitle(title);
50197 var ti = this.tabs.getTab(panel.getEl().id);
50199 if(panel.tabTip !== undefined){
50200 ti.setTooltip(panel.tabTip);
50205 updateTitle : function(title){
50206 if(this.titleTextEl && !this.config.title){
50207 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50211 setActivePanel : function(panel){
50212 panel = this.getPanel(panel);
50213 if(this.activePanel && this.activePanel != panel){
50214 this.activePanel.setActiveState(false);
50216 this.activePanel = panel;
50217 panel.setActiveState(true);
50218 if(this.panelSize){
50219 panel.setSize(this.panelSize.width, this.panelSize.height);
50222 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50224 this.updateTitle(panel.getTitle());
50226 this.fireEvent("invalidated", this);
50228 this.fireEvent("panelactivated", this, panel);
50232 * Shows the specified panel.
50233 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50234 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50236 showPanel : function(panel){
50237 if(panel = this.getPanel(panel)){
50239 var tab = this.tabs.getTab(panel.getEl().id);
50240 if(tab.isHidden()){
50241 this.tabs.unhideTab(tab.id);
50245 this.setActivePanel(panel);
50252 * Get the active panel for this region.
50253 * @return {Roo.ContentPanel} The active panel or null
50255 getActivePanel : function(){
50256 return this.activePanel;
50259 validateVisibility : function(){
50260 if(this.panels.getCount() < 1){
50261 this.updateTitle(" ");
50262 this.closeBtn.hide();
50265 if(!this.isVisible()){
50272 * Adds the passed ContentPanel(s) to this region.
50273 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50274 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50276 add : function(panel){
50277 if(arguments.length > 1){
50278 for(var i = 0, len = arguments.length; i < len; i++) {
50279 this.add(arguments[i]);
50283 if(this.hasPanel(panel)){
50284 this.showPanel(panel);
50287 panel.setRegion(this);
50288 this.panels.add(panel);
50289 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50290 this.bodyEl.dom.appendChild(panel.getEl().dom);
50291 if(panel.background !== true){
50292 this.setActivePanel(panel);
50294 this.fireEvent("paneladded", this, panel);
50300 this.initPanelAsTab(panel);
50302 if(panel.background !== true){
50303 this.tabs.activate(panel.getEl().id);
50305 this.fireEvent("paneladded", this, panel);
50310 * Hides the tab for the specified panel.
50311 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50313 hidePanel : function(panel){
50314 if(this.tabs && (panel = this.getPanel(panel))){
50315 this.tabs.hideTab(panel.getEl().id);
50320 * Unhides the tab for a previously hidden panel.
50321 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50323 unhidePanel : function(panel){
50324 if(this.tabs && (panel = this.getPanel(panel))){
50325 this.tabs.unhideTab(panel.getEl().id);
50329 clearPanels : function(){
50330 while(this.panels.getCount() > 0){
50331 this.remove(this.panels.first());
50336 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50337 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50338 * @param {Boolean} preservePanel Overrides the config preservePanel option
50339 * @return {Roo.ContentPanel} The panel that was removed
50341 remove : function(panel, preservePanel){
50342 panel = this.getPanel(panel);
50347 this.fireEvent("beforeremove", this, panel, e);
50348 if(e.cancel === true){
50351 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50352 var panelId = panel.getId();
50353 this.panels.removeKey(panelId);
50355 document.body.appendChild(panel.getEl().dom);
50358 this.tabs.removeTab(panel.getEl().id);
50359 }else if (!preservePanel){
50360 this.bodyEl.dom.removeChild(panel.getEl().dom);
50362 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50363 var p = this.panels.first();
50364 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50365 tempEl.appendChild(p.getEl().dom);
50366 this.bodyEl.update("");
50367 this.bodyEl.dom.appendChild(p.getEl().dom);
50369 this.updateTitle(p.getTitle());
50371 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50372 this.setActivePanel(p);
50374 panel.setRegion(null);
50375 if(this.activePanel == panel){
50376 this.activePanel = null;
50378 if(this.config.autoDestroy !== false && preservePanel !== true){
50379 try{panel.destroy();}catch(e){}
50381 this.fireEvent("panelremoved", this, panel);
50386 * Returns the TabPanel component used by this region
50387 * @return {Roo.TabPanel}
50389 getTabs : function(){
50393 createTool : function(parentEl, className){
50394 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50395 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50396 btn.addClassOnOver("x-layout-tools-button-over");
50401 * Ext JS Library 1.1.1
50402 * Copyright(c) 2006-2007, Ext JS, LLC.
50404 * Originally Released Under LGPL - original licence link has changed is not relivant.
50407 * <script type="text/javascript">
50413 * @class Roo.SplitLayoutRegion
50414 * @extends Roo.LayoutRegion
50415 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50417 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50418 this.cursor = cursor;
50419 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50422 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50423 splitTip : "Drag to resize.",
50424 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50425 useSplitTips : false,
50427 applyConfig : function(config){
50428 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50431 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50432 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50433 /** The SplitBar for this region
50434 * @type Roo.SplitBar */
50435 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50436 this.split.on("moved", this.onSplitMove, this);
50437 this.split.useShim = config.useShim === true;
50438 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50439 if(this.useSplitTips){
50440 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50442 if(config.collapsible){
50443 this.split.el.on("dblclick", this.collapse, this);
50446 if(typeof config.minSize != "undefined"){
50447 this.split.minSize = config.minSize;
50449 if(typeof config.maxSize != "undefined"){
50450 this.split.maxSize = config.maxSize;
50452 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50453 this.hideSplitter();
50458 getHMaxSize : function(){
50459 var cmax = this.config.maxSize || 10000;
50460 var center = this.mgr.getRegion("center");
50461 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50464 getVMaxSize : function(){
50465 var cmax = this.config.maxSize || 10000;
50466 var center = this.mgr.getRegion("center");
50467 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50470 onSplitMove : function(split, newSize){
50471 this.fireEvent("resized", this, newSize);
50475 * Returns the {@link Roo.SplitBar} for this region.
50476 * @return {Roo.SplitBar}
50478 getSplitBar : function(){
50483 this.hideSplitter();
50484 Roo.SplitLayoutRegion.superclass.hide.call(this);
50487 hideSplitter : function(){
50489 this.split.el.setLocation(-2000,-2000);
50490 this.split.el.hide();
50496 this.split.el.show();
50498 Roo.SplitLayoutRegion.superclass.show.call(this);
50501 beforeSlide: function(){
50502 if(Roo.isGecko){// firefox overflow auto bug workaround
50503 this.bodyEl.clip();
50504 if(this.tabs) this.tabs.bodyEl.clip();
50505 if(this.activePanel){
50506 this.activePanel.getEl().clip();
50508 if(this.activePanel.beforeSlide){
50509 this.activePanel.beforeSlide();
50515 afterSlide : function(){
50516 if(Roo.isGecko){// firefox overflow auto bug workaround
50517 this.bodyEl.unclip();
50518 if(this.tabs) this.tabs.bodyEl.unclip();
50519 if(this.activePanel){
50520 this.activePanel.getEl().unclip();
50521 if(this.activePanel.afterSlide){
50522 this.activePanel.afterSlide();
50528 initAutoHide : function(){
50529 if(this.autoHide !== false){
50530 if(!this.autoHideHd){
50531 var st = new Roo.util.DelayedTask(this.slideIn, this);
50532 this.autoHideHd = {
50533 "mouseout": function(e){
50534 if(!e.within(this.el, true)){
50538 "mouseover" : function(e){
50544 this.el.on(this.autoHideHd);
50548 clearAutoHide : function(){
50549 if(this.autoHide !== false){
50550 this.el.un("mouseout", this.autoHideHd.mouseout);
50551 this.el.un("mouseover", this.autoHideHd.mouseover);
50555 clearMonitor : function(){
50556 Roo.get(document).un("click", this.slideInIf, this);
50559 // these names are backwards but not changed for compat
50560 slideOut : function(){
50561 if(this.isSlid || this.el.hasActiveFx()){
50564 this.isSlid = true;
50565 if(this.collapseBtn){
50566 this.collapseBtn.hide();
50568 this.closeBtnState = this.closeBtn.getStyle('display');
50569 this.closeBtn.hide();
50571 this.stickBtn.show();
50574 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50575 this.beforeSlide();
50576 this.el.setStyle("z-index", 10001);
50577 this.el.slideIn(this.getSlideAnchor(), {
50578 callback: function(){
50580 this.initAutoHide();
50581 Roo.get(document).on("click", this.slideInIf, this);
50582 this.fireEvent("slideshow", this);
50589 afterSlideIn : function(){
50590 this.clearAutoHide();
50591 this.isSlid = false;
50592 this.clearMonitor();
50593 this.el.setStyle("z-index", "");
50594 if(this.collapseBtn){
50595 this.collapseBtn.show();
50597 this.closeBtn.setStyle('display', this.closeBtnState);
50599 this.stickBtn.hide();
50601 this.fireEvent("slidehide", this);
50604 slideIn : function(cb){
50605 if(!this.isSlid || this.el.hasActiveFx()){
50609 this.isSlid = false;
50610 this.beforeSlide();
50611 this.el.slideOut(this.getSlideAnchor(), {
50612 callback: function(){
50613 this.el.setLeftTop(-10000, -10000);
50615 this.afterSlideIn();
50623 slideInIf : function(e){
50624 if(!e.within(this.el)){
50629 animateCollapse : function(){
50630 this.beforeSlide();
50631 this.el.setStyle("z-index", 20000);
50632 var anchor = this.getSlideAnchor();
50633 this.el.slideOut(anchor, {
50634 callback : function(){
50635 this.el.setStyle("z-index", "");
50636 this.collapsedEl.slideIn(anchor, {duration:.3});
50638 this.el.setLocation(-10000,-10000);
50640 this.fireEvent("collapsed", this);
50647 animateExpand : function(){
50648 this.beforeSlide();
50649 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50650 this.el.setStyle("z-index", 20000);
50651 this.collapsedEl.hide({
50654 this.el.slideIn(this.getSlideAnchor(), {
50655 callback : function(){
50656 this.el.setStyle("z-index", "");
50659 this.split.el.show();
50661 this.fireEvent("invalidated", this);
50662 this.fireEvent("expanded", this);
50690 getAnchor : function(){
50691 return this.anchors[this.position];
50694 getCollapseAnchor : function(){
50695 return this.canchors[this.position];
50698 getSlideAnchor : function(){
50699 return this.sanchors[this.position];
50702 getAlignAdj : function(){
50703 var cm = this.cmargins;
50704 switch(this.position){
50720 getExpandAdj : function(){
50721 var c = this.collapsedEl, cm = this.cmargins;
50722 switch(this.position){
50724 return [-(cm.right+c.getWidth()+cm.left), 0];
50727 return [cm.right+c.getWidth()+cm.left, 0];
50730 return [0, -(cm.top+cm.bottom+c.getHeight())];
50733 return [0, cm.top+cm.bottom+c.getHeight()];
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 * These classes are private internal classes
50750 Roo.CenterLayoutRegion = function(mgr, config){
50751 Roo.LayoutRegion.call(this, mgr, config, "center");
50752 this.visible = true;
50753 this.minWidth = config.minWidth || 20;
50754 this.minHeight = config.minHeight || 20;
50757 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50759 // center panel can't be hidden
50763 // center panel can't be hidden
50766 getMinWidth: function(){
50767 return this.minWidth;
50770 getMinHeight: function(){
50771 return this.minHeight;
50776 Roo.NorthLayoutRegion = function(mgr, config){
50777 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50779 this.split.placement = Roo.SplitBar.TOP;
50780 this.split.orientation = Roo.SplitBar.VERTICAL;
50781 this.split.el.addClass("x-layout-split-v");
50783 var size = config.initialSize || config.height;
50784 if(typeof size != "undefined"){
50785 this.el.setHeight(size);
50788 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50789 orientation: Roo.SplitBar.VERTICAL,
50790 getBox : function(){
50791 if(this.collapsed){
50792 return this.collapsedEl.getBox();
50794 var box = this.el.getBox();
50796 box.height += this.split.el.getHeight();
50801 updateBox : function(box){
50802 if(this.split && !this.collapsed){
50803 box.height -= this.split.el.getHeight();
50804 this.split.el.setLeft(box.x);
50805 this.split.el.setTop(box.y+box.height);
50806 this.split.el.setWidth(box.width);
50808 if(this.collapsed){
50809 this.updateBody(box.width, null);
50811 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50815 Roo.SouthLayoutRegion = function(mgr, config){
50816 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50818 this.split.placement = Roo.SplitBar.BOTTOM;
50819 this.split.orientation = Roo.SplitBar.VERTICAL;
50820 this.split.el.addClass("x-layout-split-v");
50822 var size = config.initialSize || config.height;
50823 if(typeof size != "undefined"){
50824 this.el.setHeight(size);
50827 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50828 orientation: Roo.SplitBar.VERTICAL,
50829 getBox : function(){
50830 if(this.collapsed){
50831 return this.collapsedEl.getBox();
50833 var box = this.el.getBox();
50835 var sh = this.split.el.getHeight();
50842 updateBox : function(box){
50843 if(this.split && !this.collapsed){
50844 var sh = this.split.el.getHeight();
50847 this.split.el.setLeft(box.x);
50848 this.split.el.setTop(box.y-sh);
50849 this.split.el.setWidth(box.width);
50851 if(this.collapsed){
50852 this.updateBody(box.width, null);
50854 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50858 Roo.EastLayoutRegion = function(mgr, config){
50859 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50861 this.split.placement = Roo.SplitBar.RIGHT;
50862 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50863 this.split.el.addClass("x-layout-split-h");
50865 var size = config.initialSize || config.width;
50866 if(typeof size != "undefined"){
50867 this.el.setWidth(size);
50870 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50871 orientation: Roo.SplitBar.HORIZONTAL,
50872 getBox : function(){
50873 if(this.collapsed){
50874 return this.collapsedEl.getBox();
50876 var box = this.el.getBox();
50878 var sw = this.split.el.getWidth();
50885 updateBox : function(box){
50886 if(this.split && !this.collapsed){
50887 var sw = this.split.el.getWidth();
50889 this.split.el.setLeft(box.x);
50890 this.split.el.setTop(box.y);
50891 this.split.el.setHeight(box.height);
50894 if(this.collapsed){
50895 this.updateBody(null, box.height);
50897 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50901 Roo.WestLayoutRegion = function(mgr, config){
50902 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50904 this.split.placement = Roo.SplitBar.LEFT;
50905 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50906 this.split.el.addClass("x-layout-split-h");
50908 var size = config.initialSize || config.width;
50909 if(typeof size != "undefined"){
50910 this.el.setWidth(size);
50913 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50914 orientation: Roo.SplitBar.HORIZONTAL,
50915 getBox : function(){
50916 if(this.collapsed){
50917 return this.collapsedEl.getBox();
50919 var box = this.el.getBox();
50921 box.width += this.split.el.getWidth();
50926 updateBox : function(box){
50927 if(this.split && !this.collapsed){
50928 var sw = this.split.el.getWidth();
50930 this.split.el.setLeft(box.x+box.width);
50931 this.split.el.setTop(box.y);
50932 this.split.el.setHeight(box.height);
50934 if(this.collapsed){
50935 this.updateBody(null, box.height);
50937 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50942 * Ext JS Library 1.1.1
50943 * Copyright(c) 2006-2007, Ext JS, LLC.
50945 * Originally Released Under LGPL - original licence link has changed is not relivant.
50948 * <script type="text/javascript">
50953 * Private internal class for reading and applying state
50955 Roo.LayoutStateManager = function(layout){
50956 // default empty state
50965 Roo.LayoutStateManager.prototype = {
50966 init : function(layout, provider){
50967 this.provider = provider;
50968 var state = provider.get(layout.id+"-layout-state");
50970 var wasUpdating = layout.isUpdating();
50972 layout.beginUpdate();
50974 for(var key in state){
50975 if(typeof state[key] != "function"){
50976 var rstate = state[key];
50977 var r = layout.getRegion(key);
50980 r.resizeTo(rstate.size);
50982 if(rstate.collapsed == true){
50985 r.expand(null, true);
50991 layout.endUpdate();
50993 this.state = state;
50995 this.layout = layout;
50996 layout.on("regionresized", this.onRegionResized, this);
50997 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50998 layout.on("regionexpanded", this.onRegionExpanded, this);
51001 storeState : function(){
51002 this.provider.set(this.layout.id+"-layout-state", this.state);
51005 onRegionResized : function(region, newSize){
51006 this.state[region.getPosition()].size = newSize;
51010 onRegionCollapsed : function(region){
51011 this.state[region.getPosition()].collapsed = true;
51015 onRegionExpanded : function(region){
51016 this.state[region.getPosition()].collapsed = false;
51021 * Ext JS Library 1.1.1
51022 * Copyright(c) 2006-2007, Ext JS, LLC.
51024 * Originally Released Under LGPL - original licence link has changed is not relivant.
51027 * <script type="text/javascript">
51030 * @class Roo.ContentPanel
51031 * @extends Roo.util.Observable
51032 * A basic ContentPanel element.
51033 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51034 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51035 * @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
51036 * @cfg {Boolean} closable True if the panel can be closed/removed
51037 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51038 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51039 * @cfg {Toolbar} toolbar A toolbar for this panel
51040 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51041 * @cfg {String} title The title for this panel
51042 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51043 * @cfg {String} url Calls {@link #setUrl} with this value
51044 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51045 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51046 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51047 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51050 * Create a new ContentPanel.
51051 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51052 * @param {String/Object} config A string to set only the title or a config object
51053 * @param {String} content (optional) Set the HTML content for this panel
51054 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51056 Roo.ContentPanel = function(el, config, content){
51060 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51064 if (config && config.parentLayout) {
51065 el = config.parentLayout.el.createChild();
51068 if(el.autoCreate){ // xtype is available if this is called from factory
51072 this.el = Roo.get(el);
51073 if(!this.el && config && config.autoCreate){
51074 if(typeof config.autoCreate == "object"){
51075 if(!config.autoCreate.id){
51076 config.autoCreate.id = config.id||el;
51078 this.el = Roo.DomHelper.append(document.body,
51079 config.autoCreate, true);
51081 this.el = Roo.DomHelper.append(document.body,
51082 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51085 this.closable = false;
51086 this.loaded = false;
51087 this.active = false;
51088 if(typeof config == "string"){
51089 this.title = config;
51091 Roo.apply(this, config);
51094 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51095 this.wrapEl = this.el.wrap();
51096 this.toolbar.container = this.el.insertSibling(false, 'before');
51097 this.toolbar = new Roo.Toolbar(this.toolbar);
51100 // xtype created footer. - not sure if will work as we normally have to render first..
51101 if (this.footer && !this.footer.el && this.footer.xtype) {
51102 if (!this.wrapEl) {
51103 this.wrapEl = this.el.wrap();
51106 this.footer.container = this.wrapEl.createChild();
51108 this.footer = Roo.factory(this.footer, Roo);
51113 this.resizeEl = Roo.get(this.resizeEl, true);
51115 this.resizeEl = this.el;
51117 // handle view.xtype
51125 * Fires when this panel is activated.
51126 * @param {Roo.ContentPanel} this
51130 * @event deactivate
51131 * Fires when this panel is activated.
51132 * @param {Roo.ContentPanel} this
51134 "deactivate" : true,
51138 * Fires when this panel is resized if fitToFrame is true.
51139 * @param {Roo.ContentPanel} this
51140 * @param {Number} width The width after any component adjustments
51141 * @param {Number} height The height after any component adjustments
51147 * Fires when this tab is created
51148 * @param {Roo.ContentPanel} this
51159 if(this.autoScroll){
51160 this.resizeEl.setStyle("overflow", "auto");
51162 // fix randome scrolling
51163 this.el.on('scroll', function() {
51164 Roo.log('fix random scolling');
51165 this.scrollTo('top',0);
51168 content = content || this.content;
51170 this.setContent(content);
51172 if(config && config.url){
51173 this.setUrl(this.url, this.params, this.loadOnce);
51178 Roo.ContentPanel.superclass.constructor.call(this);
51180 if (this.view && typeof(this.view.xtype) != 'undefined') {
51181 this.view.el = this.el.appendChild(document.createElement("div"));
51182 this.view = Roo.factory(this.view);
51183 this.view.render && this.view.render(false, '');
51187 this.fireEvent('render', this);
51190 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51192 setRegion : function(region){
51193 this.region = region;
51195 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51197 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51202 * Returns the toolbar for this Panel if one was configured.
51203 * @return {Roo.Toolbar}
51205 getToolbar : function(){
51206 return this.toolbar;
51209 setActiveState : function(active){
51210 this.active = active;
51212 this.fireEvent("deactivate", this);
51214 this.fireEvent("activate", this);
51218 * Updates this panel's element
51219 * @param {String} content The new content
51220 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51222 setContent : function(content, loadScripts){
51223 this.el.update(content, loadScripts);
51226 ignoreResize : function(w, h){
51227 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51230 this.lastSize = {width: w, height: h};
51235 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51236 * @return {Roo.UpdateManager} The UpdateManager
51238 getUpdateManager : function(){
51239 return this.el.getUpdateManager();
51242 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51243 * @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:
51246 url: "your-url.php",
51247 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51248 callback: yourFunction,
51249 scope: yourObject, //(optional scope)
51252 text: "Loading...",
51257 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51258 * 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.
51259 * @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}
51260 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51261 * @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.
51262 * @return {Roo.ContentPanel} this
51265 var um = this.el.getUpdateManager();
51266 um.update.apply(um, arguments);
51272 * 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.
51273 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51274 * @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)
51275 * @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)
51276 * @return {Roo.UpdateManager} The UpdateManager
51278 setUrl : function(url, params, loadOnce){
51279 if(this.refreshDelegate){
51280 this.removeListener("activate", this.refreshDelegate);
51282 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51283 this.on("activate", this.refreshDelegate);
51284 return this.el.getUpdateManager();
51287 _handleRefresh : function(url, params, loadOnce){
51288 if(!loadOnce || !this.loaded){
51289 var updater = this.el.getUpdateManager();
51290 updater.update(url, params, this._setLoaded.createDelegate(this));
51294 _setLoaded : function(){
51295 this.loaded = true;
51299 * Returns this panel's id
51302 getId : function(){
51307 * Returns this panel's element - used by regiosn to add.
51308 * @return {Roo.Element}
51310 getEl : function(){
51311 return this.wrapEl || this.el;
51314 adjustForComponents : function(width, height)
51316 //Roo.log('adjustForComponents ');
51317 if(this.resizeEl != this.el){
51318 width -= this.el.getFrameWidth('lr');
51319 height -= this.el.getFrameWidth('tb');
51322 var te = this.toolbar.getEl();
51323 height -= te.getHeight();
51324 te.setWidth(width);
51327 var te = this.footer.getEl();
51328 Roo.log("footer:" + te.getHeight());
51330 height -= te.getHeight();
51331 te.setWidth(width);
51335 if(this.adjustments){
51336 width += this.adjustments[0];
51337 height += this.adjustments[1];
51339 return {"width": width, "height": height};
51342 setSize : function(width, height){
51343 if(this.fitToFrame && !this.ignoreResize(width, height)){
51344 if(this.fitContainer && this.resizeEl != this.el){
51345 this.el.setSize(width, height);
51347 var size = this.adjustForComponents(width, height);
51348 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51349 this.fireEvent('resize', this, size.width, size.height);
51354 * Returns this panel's title
51357 getTitle : function(){
51362 * Set this panel's title
51363 * @param {String} title
51365 setTitle : function(title){
51366 this.title = title;
51368 this.region.updatePanelTitle(this, title);
51373 * Returns true is this panel was configured to be closable
51374 * @return {Boolean}
51376 isClosable : function(){
51377 return this.closable;
51380 beforeSlide : function(){
51382 this.resizeEl.clip();
51385 afterSlide : function(){
51387 this.resizeEl.unclip();
51391 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51392 * Will fail silently if the {@link #setUrl} method has not been called.
51393 * This does not activate the panel, just updates its content.
51395 refresh : function(){
51396 if(this.refreshDelegate){
51397 this.loaded = false;
51398 this.refreshDelegate();
51403 * Destroys this panel
51405 destroy : function(){
51406 this.el.removeAllListeners();
51407 var tempEl = document.createElement("span");
51408 tempEl.appendChild(this.el.dom);
51409 tempEl.innerHTML = "";
51415 * form - if the content panel contains a form - this is a reference to it.
51416 * @type {Roo.form.Form}
51420 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51421 * This contains a reference to it.
51427 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51437 * @param {Object} cfg Xtype definition of item to add.
51440 addxtype : function(cfg) {
51442 if (cfg.xtype.match(/^Form$/)) {
51445 //if (this.footer) {
51446 // el = this.footer.container.insertSibling(false, 'before');
51448 el = this.el.createChild();
51451 this.form = new Roo.form.Form(cfg);
51454 if ( this.form.allItems.length) this.form.render(el.dom);
51457 // should only have one of theses..
51458 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51459 // views.. should not be just added - used named prop 'view''
51461 cfg.el = this.el.appendChild(document.createElement("div"));
51464 var ret = new Roo.factory(cfg);
51466 ret.render && ret.render(false, ''); // render blank..
51475 * @class Roo.GridPanel
51476 * @extends Roo.ContentPanel
51478 * Create a new GridPanel.
51479 * @param {Roo.grid.Grid} grid The grid for this panel
51480 * @param {String/Object} config A string to set only the panel's title, or a config object
51482 Roo.GridPanel = function(grid, config){
51485 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51486 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51488 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51490 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51493 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51495 // xtype created footer. - not sure if will work as we normally have to render first..
51496 if (this.footer && !this.footer.el && this.footer.xtype) {
51498 this.footer.container = this.grid.getView().getFooterPanel(true);
51499 this.footer.dataSource = this.grid.dataSource;
51500 this.footer = Roo.factory(this.footer, Roo);
51504 grid.monitorWindowResize = false; // turn off autosizing
51505 grid.autoHeight = false;
51506 grid.autoWidth = false;
51508 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51511 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51512 getId : function(){
51513 return this.grid.id;
51517 * Returns the grid for this panel
51518 * @return {Roo.grid.Grid}
51520 getGrid : function(){
51524 setSize : function(width, height){
51525 if(!this.ignoreResize(width, height)){
51526 var grid = this.grid;
51527 var size = this.adjustForComponents(width, height);
51528 grid.getGridEl().setSize(size.width, size.height);
51533 beforeSlide : function(){
51534 this.grid.getView().scroller.clip();
51537 afterSlide : function(){
51538 this.grid.getView().scroller.unclip();
51541 destroy : function(){
51542 this.grid.destroy();
51544 Roo.GridPanel.superclass.destroy.call(this);
51550 * @class Roo.NestedLayoutPanel
51551 * @extends Roo.ContentPanel
51553 * Create a new NestedLayoutPanel.
51556 * @param {Roo.BorderLayout} layout The layout for this panel
51557 * @param {String/Object} config A string to set only the title or a config object
51559 Roo.NestedLayoutPanel = function(layout, config)
51561 // construct with only one argument..
51562 /* FIXME - implement nicer consturctors
51563 if (layout.layout) {
51565 layout = config.layout;
51566 delete config.layout;
51568 if (layout.xtype && !layout.getEl) {
51569 // then layout needs constructing..
51570 layout = Roo.factory(layout, Roo);
51575 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51577 layout.monitorWindowResize = false; // turn off autosizing
51578 this.layout = layout;
51579 this.layout.getEl().addClass("x-layout-nested-layout");
51586 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51588 setSize : function(width, height){
51589 if(!this.ignoreResize(width, height)){
51590 var size = this.adjustForComponents(width, height);
51591 var el = this.layout.getEl();
51592 el.setSize(size.width, size.height);
51593 var touch = el.dom.offsetWidth;
51594 this.layout.layout();
51595 // ie requires a double layout on the first pass
51596 if(Roo.isIE && !this.initialized){
51597 this.initialized = true;
51598 this.layout.layout();
51603 // activate all subpanels if not currently active..
51605 setActiveState : function(active){
51606 this.active = active;
51608 this.fireEvent("deactivate", this);
51612 this.fireEvent("activate", this);
51613 // not sure if this should happen before or after..
51614 if (!this.layout) {
51615 return; // should not happen..
51618 for (var r in this.layout.regions) {
51619 reg = this.layout.getRegion(r);
51620 if (reg.getActivePanel()) {
51621 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51622 reg.setActivePanel(reg.getActivePanel());
51625 if (!reg.panels.length) {
51628 reg.showPanel(reg.getPanel(0));
51637 * Returns the nested BorderLayout for this panel
51638 * @return {Roo.BorderLayout}
51640 getLayout : function(){
51641 return this.layout;
51645 * Adds a xtype elements to the layout of the nested panel
51649 xtype : 'ContentPanel',
51656 xtype : 'NestedLayoutPanel',
51662 items : [ ... list of content panels or nested layout panels.. ]
51666 * @param {Object} cfg Xtype definition of item to add.
51668 addxtype : function(cfg) {
51669 return this.layout.addxtype(cfg);
51674 Roo.ScrollPanel = function(el, config, content){
51675 config = config || {};
51676 config.fitToFrame = true;
51677 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51679 this.el.dom.style.overflow = "hidden";
51680 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51681 this.el.removeClass("x-layout-inactive-content");
51682 this.el.on("mousewheel", this.onWheel, this);
51684 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51685 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51686 up.unselectable(); down.unselectable();
51687 up.on("click", this.scrollUp, this);
51688 down.on("click", this.scrollDown, this);
51689 up.addClassOnOver("x-scroller-btn-over");
51690 down.addClassOnOver("x-scroller-btn-over");
51691 up.addClassOnClick("x-scroller-btn-click");
51692 down.addClassOnClick("x-scroller-btn-click");
51693 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51695 this.resizeEl = this.el;
51696 this.el = wrap; this.up = up; this.down = down;
51699 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51701 wheelIncrement : 5,
51702 scrollUp : function(){
51703 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51706 scrollDown : function(){
51707 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51710 afterScroll : function(){
51711 var el = this.resizeEl;
51712 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51713 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51714 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51717 setSize : function(){
51718 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51719 this.afterScroll();
51722 onWheel : function(e){
51723 var d = e.getWheelDelta();
51724 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51725 this.afterScroll();
51729 setContent : function(content, loadScripts){
51730 this.resizeEl.update(content, loadScripts);
51744 * @class Roo.TreePanel
51745 * @extends Roo.ContentPanel
51747 * Create a new TreePanel. - defaults to fit/scoll contents.
51748 * @param {String/Object} config A string to set only the panel's title, or a config object
51749 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51751 Roo.TreePanel = function(config){
51752 var el = config.el;
51753 var tree = config.tree;
51754 delete config.tree;
51755 delete config.el; // hopefull!
51757 // wrapper for IE7 strict & safari scroll issue
51759 var treeEl = el.createChild();
51760 config.resizeEl = treeEl;
51764 Roo.TreePanel.superclass.constructor.call(this, el, config);
51767 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51768 //console.log(tree);
51769 this.on('activate', function()
51771 if (this.tree.rendered) {
51774 //console.log('render tree');
51775 this.tree.render();
51777 // this should not be needed.. - it's actually the 'el' that resizes?
51778 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51780 //this.on('resize', function (cp, w, h) {
51781 // this.tree.innerCt.setWidth(w);
51782 // this.tree.innerCt.setHeight(h);
51783 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51790 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51807 * Ext JS Library 1.1.1
51808 * Copyright(c) 2006-2007, Ext JS, LLC.
51810 * Originally Released Under LGPL - original licence link has changed is not relivant.
51813 * <script type="text/javascript">
51818 * @class Roo.ReaderLayout
51819 * @extends Roo.BorderLayout
51820 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51821 * center region containing two nested regions (a top one for a list view and one for item preview below),
51822 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51823 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51824 * expedites the setup of the overall layout and regions for this common application style.
51827 var reader = new Roo.ReaderLayout();
51828 var CP = Roo.ContentPanel; // shortcut for adding
51830 reader.beginUpdate();
51831 reader.add("north", new CP("north", "North"));
51832 reader.add("west", new CP("west", {title: "West"}));
51833 reader.add("east", new CP("east", {title: "East"}));
51835 reader.regions.listView.add(new CP("listView", "List"));
51836 reader.regions.preview.add(new CP("preview", "Preview"));
51837 reader.endUpdate();
51840 * Create a new ReaderLayout
51841 * @param {Object} config Configuration options
51842 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51843 * document.body if omitted)
51845 Roo.ReaderLayout = function(config, renderTo){
51846 var c = config || {size:{}};
51847 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51848 north: c.north !== false ? Roo.apply({
51852 }, c.north) : false,
51853 west: c.west !== false ? Roo.apply({
51861 margins:{left:5,right:0,bottom:5,top:5},
51862 cmargins:{left:5,right:5,bottom:5,top:5}
51863 }, c.west) : false,
51864 east: c.east !== false ? Roo.apply({
51872 margins:{left:0,right:5,bottom:5,top:5},
51873 cmargins:{left:5,right:5,bottom:5,top:5}
51874 }, c.east) : false,
51875 center: Roo.apply({
51876 tabPosition: 'top',
51880 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51884 this.el.addClass('x-reader');
51886 this.beginUpdate();
51888 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51889 south: c.preview !== false ? Roo.apply({
51896 cmargins:{top:5,left:0, right:0, bottom:0}
51897 }, c.preview) : false,
51898 center: Roo.apply({
51904 this.add('center', new Roo.NestedLayoutPanel(inner,
51905 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51909 this.regions.preview = inner.getRegion('south');
51910 this.regions.listView = inner.getRegion('center');
51913 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51915 * Ext JS Library 1.1.1
51916 * Copyright(c) 2006-2007, Ext JS, LLC.
51918 * Originally Released Under LGPL - original licence link has changed is not relivant.
51921 * <script type="text/javascript">
51925 * @class Roo.grid.Grid
51926 * @extends Roo.util.Observable
51927 * This class represents the primary interface of a component based grid control.
51928 * <br><br>Usage:<pre><code>
51929 var grid = new Roo.grid.Grid("my-container-id", {
51932 selModel: mySelectionModel,
51933 autoSizeColumns: true,
51934 monitorWindowResize: false,
51935 trackMouseOver: true
51940 * <b>Common Problems:</b><br/>
51941 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51942 * element will correct this<br/>
51943 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51944 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51945 * are unpredictable.<br/>
51946 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51947 * grid to calculate dimensions/offsets.<br/>
51949 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51950 * The container MUST have some type of size defined for the grid to fill. The container will be
51951 * automatically set to position relative if it isn't already.
51952 * @param {Object} config A config object that sets properties on this grid.
51954 Roo.grid.Grid = function(container, config){
51955 // initialize the container
51956 this.container = Roo.get(container);
51957 this.container.update("");
51958 this.container.setStyle("overflow", "hidden");
51959 this.container.addClass('x-grid-container');
51961 this.id = this.container.id;
51963 Roo.apply(this, config);
51964 // check and correct shorthanded configs
51966 this.dataSource = this.ds;
51970 this.colModel = this.cm;
51974 this.selModel = this.sm;
51978 if (this.selModel) {
51979 this.selModel = Roo.factory(this.selModel, Roo.grid);
51980 this.sm = this.selModel;
51981 this.sm.xmodule = this.xmodule || false;
51983 if (typeof(this.colModel.config) == 'undefined') {
51984 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51985 this.cm = this.colModel;
51986 this.cm.xmodule = this.xmodule || false;
51988 if (this.dataSource) {
51989 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51990 this.ds = this.dataSource;
51991 this.ds.xmodule = this.xmodule || false;
51998 this.container.setWidth(this.width);
52002 this.container.setHeight(this.height);
52009 * The raw click event for the entire grid.
52010 * @param {Roo.EventObject} e
52015 * The raw dblclick event for the entire grid.
52016 * @param {Roo.EventObject} e
52020 * @event contextmenu
52021 * The raw contextmenu event for the entire grid.
52022 * @param {Roo.EventObject} e
52024 "contextmenu" : true,
52027 * The raw mousedown event for the entire grid.
52028 * @param {Roo.EventObject} e
52030 "mousedown" : true,
52033 * The raw mouseup event for the entire grid.
52034 * @param {Roo.EventObject} e
52039 * The raw mouseover event for the entire grid.
52040 * @param {Roo.EventObject} e
52042 "mouseover" : true,
52045 * The raw mouseout event for the entire grid.
52046 * @param {Roo.EventObject} e
52051 * The raw keypress event for the entire grid.
52052 * @param {Roo.EventObject} e
52057 * The raw keydown event for the entire grid.
52058 * @param {Roo.EventObject} e
52066 * Fires when a cell is clicked
52067 * @param {Grid} this
52068 * @param {Number} rowIndex
52069 * @param {Number} columnIndex
52070 * @param {Roo.EventObject} e
52072 "cellclick" : true,
52074 * @event celldblclick
52075 * Fires when a cell is double clicked
52076 * @param {Grid} this
52077 * @param {Number} rowIndex
52078 * @param {Number} columnIndex
52079 * @param {Roo.EventObject} e
52081 "celldblclick" : true,
52084 * Fires when a row is clicked
52085 * @param {Grid} this
52086 * @param {Number} rowIndex
52087 * @param {Roo.EventObject} e
52091 * @event rowdblclick
52092 * Fires when a row is double clicked
52093 * @param {Grid} this
52094 * @param {Number} rowIndex
52095 * @param {Roo.EventObject} e
52097 "rowdblclick" : true,
52099 * @event headerclick
52100 * Fires when a header is clicked
52101 * @param {Grid} this
52102 * @param {Number} columnIndex
52103 * @param {Roo.EventObject} e
52105 "headerclick" : true,
52107 * @event headerdblclick
52108 * Fires when a header cell is double clicked
52109 * @param {Grid} this
52110 * @param {Number} columnIndex
52111 * @param {Roo.EventObject} e
52113 "headerdblclick" : true,
52115 * @event rowcontextmenu
52116 * Fires when a row is right clicked
52117 * @param {Grid} this
52118 * @param {Number} rowIndex
52119 * @param {Roo.EventObject} e
52121 "rowcontextmenu" : true,
52123 * @event cellcontextmenu
52124 * Fires when a cell is right clicked
52125 * @param {Grid} this
52126 * @param {Number} rowIndex
52127 * @param {Number} cellIndex
52128 * @param {Roo.EventObject} e
52130 "cellcontextmenu" : true,
52132 * @event headercontextmenu
52133 * Fires when a header is right clicked
52134 * @param {Grid} this
52135 * @param {Number} columnIndex
52136 * @param {Roo.EventObject} e
52138 "headercontextmenu" : true,
52140 * @event bodyscroll
52141 * Fires when the body element is scrolled
52142 * @param {Number} scrollLeft
52143 * @param {Number} scrollTop
52145 "bodyscroll" : true,
52147 * @event columnresize
52148 * Fires when the user resizes a column
52149 * @param {Number} columnIndex
52150 * @param {Number} newSize
52152 "columnresize" : true,
52154 * @event columnmove
52155 * Fires when the user moves a column
52156 * @param {Number} oldIndex
52157 * @param {Number} newIndex
52159 "columnmove" : true,
52162 * Fires when row(s) start being dragged
52163 * @param {Grid} this
52164 * @param {Roo.GridDD} dd The drag drop object
52165 * @param {event} e The raw browser event
52167 "startdrag" : true,
52170 * Fires when a drag operation is complete
52171 * @param {Grid} this
52172 * @param {Roo.GridDD} dd The drag drop object
52173 * @param {event} e The raw browser event
52178 * Fires when dragged row(s) are dropped on a valid DD target
52179 * @param {Grid} this
52180 * @param {Roo.GridDD} dd The drag drop object
52181 * @param {String} targetId The target drag drop object
52182 * @param {event} e The raw browser event
52187 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52188 * @param {Grid} this
52189 * @param {Roo.GridDD} dd The drag drop object
52190 * @param {String} targetId The target drag drop object
52191 * @param {event} e The raw browser event
52196 * Fires when the dragged row(s) first cross another DD target while being dragged
52197 * @param {Grid} this
52198 * @param {Roo.GridDD} dd The drag drop object
52199 * @param {String} targetId The target drag drop object
52200 * @param {event} e The raw browser event
52202 "dragenter" : true,
52205 * Fires when the dragged row(s) leave another DD target while being dragged
52206 * @param {Grid} this
52207 * @param {Roo.GridDD} dd The drag drop object
52208 * @param {String} targetId The target drag drop object
52209 * @param {event} e The raw browser event
52214 * Fires when a row is rendered, so you can change add a style to it.
52215 * @param {GridView} gridview The grid view
52216 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52222 * Fires when the grid is rendered
52223 * @param {Grid} grid
52228 Roo.grid.Grid.superclass.constructor.call(this);
52230 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52233 * @cfg {String} ddGroup - drag drop group.
52237 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52239 minColumnWidth : 25,
52242 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52243 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52244 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52246 autoSizeColumns : false,
52249 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52251 autoSizeHeaders : true,
52254 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52256 monitorWindowResize : true,
52259 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52260 * rows measured to get a columns size. Default is 0 (all rows).
52262 maxRowsToMeasure : 0,
52265 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52267 trackMouseOver : true,
52270 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52274 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52276 enableDragDrop : false,
52279 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52281 enableColumnMove : true,
52284 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52286 enableColumnHide : true,
52289 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52291 enableRowHeightSync : false,
52294 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52299 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52301 autoHeight : false,
52304 * @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.
52306 autoExpandColumn : false,
52309 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52312 autoExpandMin : 50,
52315 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52317 autoExpandMax : 1000,
52320 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52325 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52329 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52339 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52340 * of a fixed width. Default is false.
52343 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52346 * Called once after all setup has been completed and the grid is ready to be rendered.
52347 * @return {Roo.grid.Grid} this
52349 render : function()
52351 var c = this.container;
52352 // try to detect autoHeight/width mode
52353 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52354 this.autoHeight = true;
52356 var view = this.getView();
52359 c.on("click", this.onClick, this);
52360 c.on("dblclick", this.onDblClick, this);
52361 c.on("contextmenu", this.onContextMenu, this);
52362 c.on("keydown", this.onKeyDown, this);
52364 c.on("touchstart", this.onTouchStart, this);
52367 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52369 this.getSelectionModel().init(this);
52374 this.loadMask = new Roo.LoadMask(this.container,
52375 Roo.apply({store:this.dataSource}, this.loadMask));
52379 if (this.toolbar && this.toolbar.xtype) {
52380 this.toolbar.container = this.getView().getHeaderPanel(true);
52381 this.toolbar = new Roo.Toolbar(this.toolbar);
52383 if (this.footer && this.footer.xtype) {
52384 this.footer.dataSource = this.getDataSource();
52385 this.footer.container = this.getView().getFooterPanel(true);
52386 this.footer = Roo.factory(this.footer, Roo);
52388 if (this.dropTarget && this.dropTarget.xtype) {
52389 delete this.dropTarget.xtype;
52390 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52394 this.rendered = true;
52395 this.fireEvent('render', this);
52400 * Reconfigures the grid to use a different Store and Column Model.
52401 * The View will be bound to the new objects and refreshed.
52402 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52403 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52405 reconfigure : function(dataSource, colModel){
52407 this.loadMask.destroy();
52408 this.loadMask = new Roo.LoadMask(this.container,
52409 Roo.apply({store:dataSource}, this.loadMask));
52411 this.view.bind(dataSource, colModel);
52412 this.dataSource = dataSource;
52413 this.colModel = colModel;
52414 this.view.refresh(true);
52418 onKeyDown : function(e){
52419 this.fireEvent("keydown", e);
52423 * Destroy this grid.
52424 * @param {Boolean} removeEl True to remove the element
52426 destroy : function(removeEl, keepListeners){
52428 this.loadMask.destroy();
52430 var c = this.container;
52431 c.removeAllListeners();
52432 this.view.destroy();
52433 this.colModel.purgeListeners();
52434 if(!keepListeners){
52435 this.purgeListeners();
52438 if(removeEl === true){
52444 processEvent : function(name, e){
52445 // does this fire select???
52446 Roo.log('grid:processEvent ' + name);
52448 if (name != 'touchstart' ) {
52449 this.fireEvent(name, e);
52452 var t = e.getTarget();
52454 var header = v.findHeaderIndex(t);
52455 if(header !== false){
52456 var ename = name == 'touchstart' ? 'click' : name;
52458 this.fireEvent("header" + ename, this, header, e);
52460 var row = v.findRowIndex(t);
52461 var cell = v.findCellIndex(t);
52462 if (name == 'touchstart') {
52463 // first touch is always a click.
52464 // hopefull this happens after selection is updated.?
52467 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52468 var cs = this.selModel.getSelectedCell();
52469 if (row == cs[0] && cell == cs[1]){
52473 if (typeof(this.selModel.getSelections) != 'undefined') {
52474 var cs = this.selModel.getSelections();
52475 var ds = this.dataSource;
52476 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52487 this.fireEvent("row" + name, this, row, e);
52488 if(cell !== false){
52489 this.fireEvent("cell" + name, this, row, cell, e);
52496 onClick : function(e){
52497 this.processEvent("click", e);
52500 onTouchStart : function(e){
52501 this.processEvent("touchstart", e);
52505 onContextMenu : function(e, t){
52506 this.processEvent("contextmenu", e);
52510 onDblClick : function(e){
52511 this.processEvent("dblclick", e);
52515 walkCells : function(row, col, step, fn, scope){
52516 var cm = this.colModel, clen = cm.getColumnCount();
52517 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52529 if(fn.call(scope || this, row, col, cm) === true){
52547 if(fn.call(scope || this, row, col, cm) === true){
52559 getSelections : function(){
52560 return this.selModel.getSelections();
52564 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52565 * but if manual update is required this method will initiate it.
52567 autoSize : function(){
52569 this.view.layout();
52570 if(this.view.adjustForScroll){
52571 this.view.adjustForScroll();
52577 * Returns the grid's underlying element.
52578 * @return {Element} The element
52580 getGridEl : function(){
52581 return this.container;
52584 // private for compatibility, overridden by editor grid
52585 stopEditing : function(){},
52588 * Returns the grid's SelectionModel.
52589 * @return {SelectionModel}
52591 getSelectionModel : function(){
52592 if(!this.selModel){
52593 this.selModel = new Roo.grid.RowSelectionModel();
52595 return this.selModel;
52599 * Returns the grid's DataSource.
52600 * @return {DataSource}
52602 getDataSource : function(){
52603 return this.dataSource;
52607 * Returns the grid's ColumnModel.
52608 * @return {ColumnModel}
52610 getColumnModel : function(){
52611 return this.colModel;
52615 * Returns the grid's GridView object.
52616 * @return {GridView}
52618 getView : function(){
52620 this.view = new Roo.grid.GridView(this.viewConfig);
52625 * Called to get grid's drag proxy text, by default returns this.ddText.
52628 getDragDropText : function(){
52629 var count = this.selModel.getCount();
52630 return String.format(this.ddText, count, count == 1 ? '' : 's');
52634 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52635 * %0 is replaced with the number of selected rows.
52638 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52640 * Ext JS Library 1.1.1
52641 * Copyright(c) 2006-2007, Ext JS, LLC.
52643 * Originally Released Under LGPL - original licence link has changed is not relivant.
52646 * <script type="text/javascript">
52649 Roo.grid.AbstractGridView = function(){
52653 "beforerowremoved" : true,
52654 "beforerowsinserted" : true,
52655 "beforerefresh" : true,
52656 "rowremoved" : true,
52657 "rowsinserted" : true,
52658 "rowupdated" : true,
52661 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52664 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52665 rowClass : "x-grid-row",
52666 cellClass : "x-grid-cell",
52667 tdClass : "x-grid-td",
52668 hdClass : "x-grid-hd",
52669 splitClass : "x-grid-hd-split",
52671 init: function(grid){
52673 var cid = this.grid.getGridEl().id;
52674 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52675 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52676 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52677 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52680 getColumnRenderers : function(){
52681 var renderers = [];
52682 var cm = this.grid.colModel;
52683 var colCount = cm.getColumnCount();
52684 for(var i = 0; i < colCount; i++){
52685 renderers[i] = cm.getRenderer(i);
52690 getColumnIds : function(){
52692 var cm = this.grid.colModel;
52693 var colCount = cm.getColumnCount();
52694 for(var i = 0; i < colCount; i++){
52695 ids[i] = cm.getColumnId(i);
52700 getDataIndexes : function(){
52701 if(!this.indexMap){
52702 this.indexMap = this.buildIndexMap();
52704 return this.indexMap.colToData;
52707 getColumnIndexByDataIndex : function(dataIndex){
52708 if(!this.indexMap){
52709 this.indexMap = this.buildIndexMap();
52711 return this.indexMap.dataToCol[dataIndex];
52715 * Set a css style for a column dynamically.
52716 * @param {Number} colIndex The index of the column
52717 * @param {String} name The css property name
52718 * @param {String} value The css value
52720 setCSSStyle : function(colIndex, name, value){
52721 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52722 Roo.util.CSS.updateRule(selector, name, value);
52725 generateRules : function(cm){
52726 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52727 Roo.util.CSS.removeStyleSheet(rulesId);
52728 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52729 var cid = cm.getColumnId(i);
52730 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52731 this.tdSelector, cid, " {\n}\n",
52732 this.hdSelector, cid, " {\n}\n",
52733 this.splitSelector, cid, " {\n}\n");
52735 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52739 * Ext JS Library 1.1.1
52740 * Copyright(c) 2006-2007, Ext JS, LLC.
52742 * Originally Released Under LGPL - original licence link has changed is not relivant.
52745 * <script type="text/javascript">
52749 // This is a support class used internally by the Grid components
52750 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52752 this.view = grid.getView();
52753 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52754 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52756 this.setHandleElId(Roo.id(hd));
52757 this.setOuterHandleElId(Roo.id(hd2));
52759 this.scroll = false;
52761 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52763 getDragData : function(e){
52764 var t = Roo.lib.Event.getTarget(e);
52765 var h = this.view.findHeaderCell(t);
52767 return {ddel: h.firstChild, header:h};
52772 onInitDrag : function(e){
52773 this.view.headersDisabled = true;
52774 var clone = this.dragData.ddel.cloneNode(true);
52775 clone.id = Roo.id();
52776 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52777 this.proxy.update(clone);
52781 afterValidDrop : function(){
52783 setTimeout(function(){
52784 v.headersDisabled = false;
52788 afterInvalidDrop : function(){
52790 setTimeout(function(){
52791 v.headersDisabled = false;
52797 * Ext JS Library 1.1.1
52798 * Copyright(c) 2006-2007, Ext JS, LLC.
52800 * Originally Released Under LGPL - original licence link has changed is not relivant.
52803 * <script type="text/javascript">
52806 // This is a support class used internally by the Grid components
52807 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52809 this.view = grid.getView();
52810 // split the proxies so they don't interfere with mouse events
52811 this.proxyTop = Roo.DomHelper.append(document.body, {
52812 cls:"col-move-top", html:" "
52814 this.proxyBottom = Roo.DomHelper.append(document.body, {
52815 cls:"col-move-bottom", html:" "
52817 this.proxyTop.hide = this.proxyBottom.hide = function(){
52818 this.setLeftTop(-100,-100);
52819 this.setStyle("visibility", "hidden");
52821 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52822 // temporarily disabled
52823 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52824 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52826 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52827 proxyOffsets : [-4, -9],
52828 fly: Roo.Element.fly,
52830 getTargetFromEvent : function(e){
52831 var t = Roo.lib.Event.getTarget(e);
52832 var cindex = this.view.findCellIndex(t);
52833 if(cindex !== false){
52834 return this.view.getHeaderCell(cindex);
52839 nextVisible : function(h){
52840 var v = this.view, cm = this.grid.colModel;
52843 if(!cm.isHidden(v.getCellIndex(h))){
52851 prevVisible : function(h){
52852 var v = this.view, cm = this.grid.colModel;
52855 if(!cm.isHidden(v.getCellIndex(h))){
52863 positionIndicator : function(h, n, e){
52864 var x = Roo.lib.Event.getPageX(e);
52865 var r = Roo.lib.Dom.getRegion(n.firstChild);
52866 var px, pt, py = r.top + this.proxyOffsets[1];
52867 if((r.right - x) <= (r.right-r.left)/2){
52868 px = r.right+this.view.borderWidth;
52874 var oldIndex = this.view.getCellIndex(h);
52875 var newIndex = this.view.getCellIndex(n);
52877 if(this.grid.colModel.isFixed(newIndex)){
52881 var locked = this.grid.colModel.isLocked(newIndex);
52886 if(oldIndex < newIndex){
52889 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52892 px += this.proxyOffsets[0];
52893 this.proxyTop.setLeftTop(px, py);
52894 this.proxyTop.show();
52895 if(!this.bottomOffset){
52896 this.bottomOffset = this.view.mainHd.getHeight();
52898 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52899 this.proxyBottom.show();
52903 onNodeEnter : function(n, dd, e, data){
52904 if(data.header != n){
52905 this.positionIndicator(data.header, n, e);
52909 onNodeOver : function(n, dd, e, data){
52910 var result = false;
52911 if(data.header != n){
52912 result = this.positionIndicator(data.header, n, e);
52915 this.proxyTop.hide();
52916 this.proxyBottom.hide();
52918 return result ? this.dropAllowed : this.dropNotAllowed;
52921 onNodeOut : function(n, dd, e, data){
52922 this.proxyTop.hide();
52923 this.proxyBottom.hide();
52926 onNodeDrop : function(n, dd, e, data){
52927 var h = data.header;
52929 var cm = this.grid.colModel;
52930 var x = Roo.lib.Event.getPageX(e);
52931 var r = Roo.lib.Dom.getRegion(n.firstChild);
52932 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52933 var oldIndex = this.view.getCellIndex(h);
52934 var newIndex = this.view.getCellIndex(n);
52935 var locked = cm.isLocked(newIndex);
52939 if(oldIndex < newIndex){
52942 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52945 cm.setLocked(oldIndex, locked, true);
52946 cm.moveColumn(oldIndex, newIndex);
52947 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52955 * Ext JS Library 1.1.1
52956 * Copyright(c) 2006-2007, Ext JS, LLC.
52958 * Originally Released Under LGPL - original licence link has changed is not relivant.
52961 * <script type="text/javascript">
52965 * @class Roo.grid.GridView
52966 * @extends Roo.util.Observable
52969 * @param {Object} config
52971 Roo.grid.GridView = function(config){
52972 Roo.grid.GridView.superclass.constructor.call(this);
52975 Roo.apply(this, config);
52978 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52980 unselectable : 'unselectable="on"',
52981 unselectableCls : 'x-unselectable',
52984 rowClass : "x-grid-row",
52986 cellClass : "x-grid-col",
52988 tdClass : "x-grid-td",
52990 hdClass : "x-grid-hd",
52992 splitClass : "x-grid-split",
52994 sortClasses : ["sort-asc", "sort-desc"],
52996 enableMoveAnim : false,
53000 dh : Roo.DomHelper,
53002 fly : Roo.Element.fly,
53004 css : Roo.util.CSS,
53010 scrollIncrement : 22,
53012 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53014 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53016 bind : function(ds, cm){
53018 this.ds.un("load", this.onLoad, this);
53019 this.ds.un("datachanged", this.onDataChange, this);
53020 this.ds.un("add", this.onAdd, this);
53021 this.ds.un("remove", this.onRemove, this);
53022 this.ds.un("update", this.onUpdate, this);
53023 this.ds.un("clear", this.onClear, this);
53026 ds.on("load", this.onLoad, this);
53027 ds.on("datachanged", this.onDataChange, this);
53028 ds.on("add", this.onAdd, this);
53029 ds.on("remove", this.onRemove, this);
53030 ds.on("update", this.onUpdate, this);
53031 ds.on("clear", this.onClear, this);
53036 this.cm.un("widthchange", this.onColWidthChange, this);
53037 this.cm.un("headerchange", this.onHeaderChange, this);
53038 this.cm.un("hiddenchange", this.onHiddenChange, this);
53039 this.cm.un("columnmoved", this.onColumnMove, this);
53040 this.cm.un("columnlockchange", this.onColumnLock, this);
53043 this.generateRules(cm);
53044 cm.on("widthchange", this.onColWidthChange, this);
53045 cm.on("headerchange", this.onHeaderChange, this);
53046 cm.on("hiddenchange", this.onHiddenChange, this);
53047 cm.on("columnmoved", this.onColumnMove, this);
53048 cm.on("columnlockchange", this.onColumnLock, this);
53053 init: function(grid){
53054 Roo.grid.GridView.superclass.init.call(this, grid);
53056 this.bind(grid.dataSource, grid.colModel);
53058 grid.on("headerclick", this.handleHeaderClick, this);
53060 if(grid.trackMouseOver){
53061 grid.on("mouseover", this.onRowOver, this);
53062 grid.on("mouseout", this.onRowOut, this);
53064 grid.cancelTextSelection = function(){};
53065 this.gridId = grid.id;
53067 var tpls = this.templates || {};
53070 tpls.master = new Roo.Template(
53071 '<div class="x-grid" hidefocus="true">',
53072 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53073 '<div class="x-grid-topbar"></div>',
53074 '<div class="x-grid-scroller"><div></div></div>',
53075 '<div class="x-grid-locked">',
53076 '<div class="x-grid-header">{lockedHeader}</div>',
53077 '<div class="x-grid-body">{lockedBody}</div>',
53079 '<div class="x-grid-viewport">',
53080 '<div class="x-grid-header">{header}</div>',
53081 '<div class="x-grid-body">{body}</div>',
53083 '<div class="x-grid-bottombar"></div>',
53085 '<div class="x-grid-resize-proxy"> </div>',
53088 tpls.master.disableformats = true;
53092 tpls.header = new Roo.Template(
53093 '<table border="0" cellspacing="0" cellpadding="0">',
53094 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53097 tpls.header.disableformats = true;
53099 tpls.header.compile();
53102 tpls.hcell = new Roo.Template(
53103 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53104 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53107 tpls.hcell.disableFormats = true;
53109 tpls.hcell.compile();
53112 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53113 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53114 tpls.hsplit.disableFormats = true;
53116 tpls.hsplit.compile();
53119 tpls.body = new Roo.Template(
53120 '<table border="0" cellspacing="0" cellpadding="0">',
53121 "<tbody>{rows}</tbody>",
53124 tpls.body.disableFormats = true;
53126 tpls.body.compile();
53129 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53130 tpls.row.disableFormats = true;
53132 tpls.row.compile();
53135 tpls.cell = new Roo.Template(
53136 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53137 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53138 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53141 tpls.cell.disableFormats = true;
53143 tpls.cell.compile();
53145 this.templates = tpls;
53148 // remap these for backwards compat
53149 onColWidthChange : function(){
53150 this.updateColumns.apply(this, arguments);
53152 onHeaderChange : function(){
53153 this.updateHeaders.apply(this, arguments);
53155 onHiddenChange : function(){
53156 this.handleHiddenChange.apply(this, arguments);
53158 onColumnMove : function(){
53159 this.handleColumnMove.apply(this, arguments);
53161 onColumnLock : function(){
53162 this.handleLockChange.apply(this, arguments);
53165 onDataChange : function(){
53167 this.updateHeaderSortState();
53170 onClear : function(){
53174 onUpdate : function(ds, record){
53175 this.refreshRow(record);
53178 refreshRow : function(record){
53179 var ds = this.ds, index;
53180 if(typeof record == 'number'){
53182 record = ds.getAt(index);
53184 index = ds.indexOf(record);
53186 this.insertRows(ds, index, index, true);
53187 this.onRemove(ds, record, index+1, true);
53188 this.syncRowHeights(index, index);
53190 this.fireEvent("rowupdated", this, index, record);
53193 onAdd : function(ds, records, index){
53194 this.insertRows(ds, index, index + (records.length-1));
53197 onRemove : function(ds, record, index, isUpdate){
53198 if(isUpdate !== true){
53199 this.fireEvent("beforerowremoved", this, index, record);
53201 var bt = this.getBodyTable(), lt = this.getLockedTable();
53202 if(bt.rows[index]){
53203 bt.firstChild.removeChild(bt.rows[index]);
53205 if(lt.rows[index]){
53206 lt.firstChild.removeChild(lt.rows[index]);
53208 if(isUpdate !== true){
53209 this.stripeRows(index);
53210 this.syncRowHeights(index, index);
53212 this.fireEvent("rowremoved", this, index, record);
53216 onLoad : function(){
53217 this.scrollToTop();
53221 * Scrolls the grid to the top
53223 scrollToTop : function(){
53225 this.scroller.dom.scrollTop = 0;
53231 * Gets a panel in the header of the grid that can be used for toolbars etc.
53232 * After modifying the contents of this panel a call to grid.autoSize() may be
53233 * required to register any changes in size.
53234 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53235 * @return Roo.Element
53237 getHeaderPanel : function(doShow){
53239 this.headerPanel.show();
53241 return this.headerPanel;
53245 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53246 * After modifying the contents of this panel a call to grid.autoSize() may be
53247 * required to register any changes in size.
53248 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53249 * @return Roo.Element
53251 getFooterPanel : function(doShow){
53253 this.footerPanel.show();
53255 return this.footerPanel;
53258 initElements : function(){
53259 var E = Roo.Element;
53260 var el = this.grid.getGridEl().dom.firstChild;
53261 var cs = el.childNodes;
53263 this.el = new E(el);
53265 this.focusEl = new E(el.firstChild);
53266 this.focusEl.swallowEvent("click", true);
53268 this.headerPanel = new E(cs[1]);
53269 this.headerPanel.enableDisplayMode("block");
53271 this.scroller = new E(cs[2]);
53272 this.scrollSizer = new E(this.scroller.dom.firstChild);
53274 this.lockedWrap = new E(cs[3]);
53275 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53276 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53278 this.mainWrap = new E(cs[4]);
53279 this.mainHd = new E(this.mainWrap.dom.firstChild);
53280 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53282 this.footerPanel = new E(cs[5]);
53283 this.footerPanel.enableDisplayMode("block");
53285 this.resizeProxy = new E(cs[6]);
53287 this.headerSelector = String.format(
53288 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53289 this.lockedHd.id, this.mainHd.id
53292 this.splitterSelector = String.format(
53293 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53294 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53297 idToCssName : function(s)
53299 return s.replace(/[^a-z0-9]+/ig, '-');
53302 getHeaderCell : function(index){
53303 return Roo.DomQuery.select(this.headerSelector)[index];
53306 getHeaderCellMeasure : function(index){
53307 return this.getHeaderCell(index).firstChild;
53310 getHeaderCellText : function(index){
53311 return this.getHeaderCell(index).firstChild.firstChild;
53314 getLockedTable : function(){
53315 return this.lockedBody.dom.firstChild;
53318 getBodyTable : function(){
53319 return this.mainBody.dom.firstChild;
53322 getLockedRow : function(index){
53323 return this.getLockedTable().rows[index];
53326 getRow : function(index){
53327 return this.getBodyTable().rows[index];
53330 getRowComposite : function(index){
53332 this.rowEl = new Roo.CompositeElementLite();
53334 var els = [], lrow, mrow;
53335 if(lrow = this.getLockedRow(index)){
53338 if(mrow = this.getRow(index)){
53341 this.rowEl.elements = els;
53345 * Gets the 'td' of the cell
53347 * @param {Integer} rowIndex row to select
53348 * @param {Integer} colIndex column to select
53352 getCell : function(rowIndex, colIndex){
53353 var locked = this.cm.getLockedCount();
53355 if(colIndex < locked){
53356 source = this.lockedBody.dom.firstChild;
53358 source = this.mainBody.dom.firstChild;
53359 colIndex -= locked;
53361 return source.rows[rowIndex].childNodes[colIndex];
53364 getCellText : function(rowIndex, colIndex){
53365 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53368 getCellBox : function(cell){
53369 var b = this.fly(cell).getBox();
53370 if(Roo.isOpera){ // opera fails to report the Y
53371 b.y = cell.offsetTop + this.mainBody.getY();
53376 getCellIndex : function(cell){
53377 var id = String(cell.className).match(this.cellRE);
53379 return parseInt(id[1], 10);
53384 findHeaderIndex : function(n){
53385 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53386 return r ? this.getCellIndex(r) : false;
53389 findHeaderCell : function(n){
53390 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53391 return r ? r : false;
53394 findRowIndex : function(n){
53398 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53399 return r ? r.rowIndex : false;
53402 findCellIndex : function(node){
53403 var stop = this.el.dom;
53404 while(node && node != stop){
53405 if(this.findRE.test(node.className)){
53406 return this.getCellIndex(node);
53408 node = node.parentNode;
53413 getColumnId : function(index){
53414 return this.cm.getColumnId(index);
53417 getSplitters : function()
53419 if(this.splitterSelector){
53420 return Roo.DomQuery.select(this.splitterSelector);
53426 getSplitter : function(index){
53427 return this.getSplitters()[index];
53430 onRowOver : function(e, t){
53432 if((row = this.findRowIndex(t)) !== false){
53433 this.getRowComposite(row).addClass("x-grid-row-over");
53437 onRowOut : function(e, t){
53439 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53440 this.getRowComposite(row).removeClass("x-grid-row-over");
53444 renderHeaders : function(){
53446 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53447 var cb = [], lb = [], sb = [], lsb = [], p = {};
53448 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53449 p.cellId = "x-grid-hd-0-" + i;
53450 p.splitId = "x-grid-csplit-0-" + i;
53451 p.id = cm.getColumnId(i);
53452 p.title = cm.getColumnTooltip(i) || "";
53453 p.value = cm.getColumnHeader(i) || "";
53454 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53455 if(!cm.isLocked(i)){
53456 cb[cb.length] = ct.apply(p);
53457 sb[sb.length] = st.apply(p);
53459 lb[lb.length] = ct.apply(p);
53460 lsb[lsb.length] = st.apply(p);
53463 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53464 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53467 updateHeaders : function(){
53468 var html = this.renderHeaders();
53469 this.lockedHd.update(html[0]);
53470 this.mainHd.update(html[1]);
53474 * Focuses the specified row.
53475 * @param {Number} row The row index
53477 focusRow : function(row)
53479 //Roo.log('GridView.focusRow');
53480 var x = this.scroller.dom.scrollLeft;
53481 this.focusCell(row, 0, false);
53482 this.scroller.dom.scrollLeft = x;
53486 * Focuses the specified cell.
53487 * @param {Number} row The row index
53488 * @param {Number} col The column index
53489 * @param {Boolean} hscroll false to disable horizontal scrolling
53491 focusCell : function(row, col, hscroll)
53493 //Roo.log('GridView.focusCell');
53494 var el = this.ensureVisible(row, col, hscroll);
53495 this.focusEl.alignTo(el, "tl-tl");
53497 this.focusEl.focus();
53499 this.focusEl.focus.defer(1, this.focusEl);
53504 * Scrolls the specified cell into view
53505 * @param {Number} row The row index
53506 * @param {Number} col The column index
53507 * @param {Boolean} hscroll false to disable horizontal scrolling
53509 ensureVisible : function(row, col, hscroll)
53511 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53512 //return null; //disable for testing.
53513 if(typeof row != "number"){
53514 row = row.rowIndex;
53516 if(row < 0 && row >= this.ds.getCount()){
53519 col = (col !== undefined ? col : 0);
53520 var cm = this.grid.colModel;
53521 while(cm.isHidden(col)){
53525 var el = this.getCell(row, col);
53529 var c = this.scroller.dom;
53531 var ctop = parseInt(el.offsetTop, 10);
53532 var cleft = parseInt(el.offsetLeft, 10);
53533 var cbot = ctop + el.offsetHeight;
53534 var cright = cleft + el.offsetWidth;
53536 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53537 var stop = parseInt(c.scrollTop, 10);
53538 var sleft = parseInt(c.scrollLeft, 10);
53539 var sbot = stop + ch;
53540 var sright = sleft + c.clientWidth;
53542 Roo.log('GridView.ensureVisible:' +
53544 ' c.clientHeight:' + c.clientHeight +
53545 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53553 c.scrollTop = ctop;
53554 //Roo.log("set scrolltop to ctop DISABLE?");
53555 }else if(cbot > sbot){
53556 //Roo.log("set scrolltop to cbot-ch");
53557 c.scrollTop = cbot-ch;
53560 if(hscroll !== false){
53562 c.scrollLeft = cleft;
53563 }else if(cright > sright){
53564 c.scrollLeft = cright-c.clientWidth;
53571 updateColumns : function(){
53572 this.grid.stopEditing();
53573 var cm = this.grid.colModel, colIds = this.getColumnIds();
53574 //var totalWidth = cm.getTotalWidth();
53576 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53577 //if(cm.isHidden(i)) continue;
53578 var w = cm.getColumnWidth(i);
53579 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53580 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53582 this.updateSplitters();
53585 generateRules : function(cm){
53586 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53587 Roo.util.CSS.removeStyleSheet(rulesId);
53588 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53589 var cid = cm.getColumnId(i);
53591 if(cm.config[i].align){
53592 align = 'text-align:'+cm.config[i].align+';';
53595 if(cm.isHidden(i)){
53596 hidden = 'display:none;';
53598 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53600 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53601 this.hdSelector, cid, " {\n", align, width, "}\n",
53602 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53603 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53605 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53608 updateSplitters : function(){
53609 var cm = this.cm, s = this.getSplitters();
53610 if(s){ // splitters not created yet
53611 var pos = 0, locked = true;
53612 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53613 if(cm.isHidden(i)) continue;
53614 var w = cm.getColumnWidth(i); // make sure it's a number
53615 if(!cm.isLocked(i) && locked){
53620 s[i].style.left = (pos-this.splitOffset) + "px";
53625 handleHiddenChange : function(colModel, colIndex, hidden){
53627 this.hideColumn(colIndex);
53629 this.unhideColumn(colIndex);
53633 hideColumn : function(colIndex){
53634 var cid = this.getColumnId(colIndex);
53635 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53636 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53638 this.updateHeaders();
53640 this.updateSplitters();
53644 unhideColumn : function(colIndex){
53645 var cid = this.getColumnId(colIndex);
53646 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53647 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53650 this.updateHeaders();
53652 this.updateSplitters();
53656 insertRows : function(dm, firstRow, lastRow, isUpdate){
53657 if(firstRow == 0 && lastRow == dm.getCount()-1){
53661 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53663 var s = this.getScrollState();
53664 var markup = this.renderRows(firstRow, lastRow);
53665 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53666 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53667 this.restoreScroll(s);
53669 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53670 this.syncRowHeights(firstRow, lastRow);
53671 this.stripeRows(firstRow);
53677 bufferRows : function(markup, target, index){
53678 var before = null, trows = target.rows, tbody = target.tBodies[0];
53679 if(index < trows.length){
53680 before = trows[index];
53682 var b = document.createElement("div");
53683 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53684 var rows = b.firstChild.rows;
53685 for(var i = 0, len = rows.length; i < len; i++){
53687 tbody.insertBefore(rows[0], before);
53689 tbody.appendChild(rows[0]);
53696 deleteRows : function(dm, firstRow, lastRow){
53697 if(dm.getRowCount()<1){
53698 this.fireEvent("beforerefresh", this);
53699 this.mainBody.update("");
53700 this.lockedBody.update("");
53701 this.fireEvent("refresh", this);
53703 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53704 var bt = this.getBodyTable();
53705 var tbody = bt.firstChild;
53706 var rows = bt.rows;
53707 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53708 tbody.removeChild(rows[firstRow]);
53710 this.stripeRows(firstRow);
53711 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53715 updateRows : function(dataSource, firstRow, lastRow){
53716 var s = this.getScrollState();
53718 this.restoreScroll(s);
53721 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53725 this.updateHeaderSortState();
53728 getScrollState : function(){
53730 var sb = this.scroller.dom;
53731 return {left: sb.scrollLeft, top: sb.scrollTop};
53734 stripeRows : function(startRow){
53735 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53738 startRow = startRow || 0;
53739 var rows = this.getBodyTable().rows;
53740 var lrows = this.getLockedTable().rows;
53741 var cls = ' x-grid-row-alt ';
53742 for(var i = startRow, len = rows.length; i < len; i++){
53743 var row = rows[i], lrow = lrows[i];
53744 var isAlt = ((i+1) % 2 == 0);
53745 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53746 if(isAlt == hasAlt){
53750 row.className += " x-grid-row-alt";
53752 row.className = row.className.replace("x-grid-row-alt", "");
53755 lrow.className = row.className;
53760 restoreScroll : function(state){
53761 //Roo.log('GridView.restoreScroll');
53762 var sb = this.scroller.dom;
53763 sb.scrollLeft = state.left;
53764 sb.scrollTop = state.top;
53768 syncScroll : function(){
53769 //Roo.log('GridView.syncScroll');
53770 var sb = this.scroller.dom;
53771 var sh = this.mainHd.dom;
53772 var bs = this.mainBody.dom;
53773 var lv = this.lockedBody.dom;
53774 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53775 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53778 handleScroll : function(e){
53780 var sb = this.scroller.dom;
53781 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53785 handleWheel : function(e){
53786 var d = e.getWheelDelta();
53787 this.scroller.dom.scrollTop -= d*22;
53788 // set this here to prevent jumpy scrolling on large tables
53789 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53793 renderRows : function(startRow, endRow){
53794 // pull in all the crap needed to render rows
53795 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53796 var colCount = cm.getColumnCount();
53798 if(ds.getCount() < 1){
53802 // build a map for all the columns
53804 for(var i = 0; i < colCount; i++){
53805 var name = cm.getDataIndex(i);
53807 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53808 renderer : cm.getRenderer(i),
53809 id : cm.getColumnId(i),
53810 locked : cm.isLocked(i)
53814 startRow = startRow || 0;
53815 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53817 // records to render
53818 var rs = ds.getRange(startRow, endRow);
53820 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53823 // As much as I hate to duplicate code, this was branched because FireFox really hates
53824 // [].join("") on strings. The performance difference was substantial enough to
53825 // branch this function
53826 doRender : Roo.isGecko ?
53827 function(cs, rs, ds, startRow, colCount, stripe){
53828 var ts = this.templates, ct = ts.cell, rt = ts.row;
53830 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53832 var hasListener = this.grid.hasListener('rowclass');
53834 for(var j = 0, len = rs.length; j < len; j++){
53835 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53836 for(var i = 0; i < colCount; i++){
53838 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53840 p.css = p.attr = "";
53841 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53842 if(p.value == undefined || p.value === "") p.value = " ";
53843 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53844 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53846 var markup = ct.apply(p);
53854 if(stripe && ((rowIndex+1) % 2 == 0)){
53855 alt.push("x-grid-row-alt")
53858 alt.push( " x-grid-dirty-row");
53861 if(this.getRowClass){
53862 alt.push(this.getRowClass(r, rowIndex));
53868 rowIndex : rowIndex,
53871 this.grid.fireEvent('rowclass', this, rowcfg);
53872 alt.push(rowcfg.rowClass);
53874 rp.alt = alt.join(" ");
53875 lbuf+= rt.apply(rp);
53877 buf+= rt.apply(rp);
53879 return [lbuf, buf];
53881 function(cs, rs, ds, startRow, colCount, stripe){
53882 var ts = this.templates, ct = ts.cell, rt = ts.row;
53884 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53885 var hasListener = this.grid.hasListener('rowclass');
53888 for(var j = 0, len = rs.length; j < len; j++){
53889 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53890 for(var i = 0; i < colCount; i++){
53892 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53894 p.css = p.attr = "";
53895 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53896 if(p.value == undefined || p.value === "") p.value = " ";
53897 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53898 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53901 var markup = ct.apply(p);
53903 cb[cb.length] = markup;
53905 lcb[lcb.length] = markup;
53909 if(stripe && ((rowIndex+1) % 2 == 0)){
53910 alt.push( "x-grid-row-alt");
53913 alt.push(" x-grid-dirty-row");
53916 if(this.getRowClass){
53917 alt.push( this.getRowClass(r, rowIndex));
53923 rowIndex : rowIndex,
53926 this.grid.fireEvent('rowclass', this, rowcfg);
53927 alt.push(rowcfg.rowClass);
53929 rp.alt = alt.join(" ");
53930 rp.cells = lcb.join("");
53931 lbuf[lbuf.length] = rt.apply(rp);
53932 rp.cells = cb.join("");
53933 buf[buf.length] = rt.apply(rp);
53935 return [lbuf.join(""), buf.join("")];
53938 renderBody : function(){
53939 var markup = this.renderRows();
53940 var bt = this.templates.body;
53941 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53945 * Refreshes the grid
53946 * @param {Boolean} headersToo
53948 refresh : function(headersToo){
53949 this.fireEvent("beforerefresh", this);
53950 this.grid.stopEditing();
53951 var result = this.renderBody();
53952 this.lockedBody.update(result[0]);
53953 this.mainBody.update(result[1]);
53954 if(headersToo === true){
53955 this.updateHeaders();
53956 this.updateColumns();
53957 this.updateSplitters();
53958 this.updateHeaderSortState();
53960 this.syncRowHeights();
53962 this.fireEvent("refresh", this);
53965 handleColumnMove : function(cm, oldIndex, newIndex){
53966 this.indexMap = null;
53967 var s = this.getScrollState();
53968 this.refresh(true);
53969 this.restoreScroll(s);
53970 this.afterMove(newIndex);
53973 afterMove : function(colIndex){
53974 if(this.enableMoveAnim && Roo.enableFx){
53975 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53977 // if multisort - fix sortOrder, and reload..
53978 if (this.grid.dataSource.multiSort) {
53979 // the we can call sort again..
53980 var dm = this.grid.dataSource;
53981 var cm = this.grid.colModel;
53983 for(var i = 0; i < cm.config.length; i++ ) {
53985 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53986 continue; // dont' bother, it's not in sort list or being set.
53989 so.push(cm.config[i].dataIndex);
53992 dm.load(dm.lastOptions);
53999 updateCell : function(dm, rowIndex, dataIndex){
54000 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54001 if(typeof colIndex == "undefined"){ // not present in grid
54004 var cm = this.grid.colModel;
54005 var cell = this.getCell(rowIndex, colIndex);
54006 var cellText = this.getCellText(rowIndex, colIndex);
54009 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54010 id : cm.getColumnId(colIndex),
54011 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54013 var renderer = cm.getRenderer(colIndex);
54014 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54015 if(typeof val == "undefined" || val === "") val = " ";
54016 cellText.innerHTML = val;
54017 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54018 this.syncRowHeights(rowIndex, rowIndex);
54021 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54023 if(this.grid.autoSizeHeaders){
54024 var h = this.getHeaderCellMeasure(colIndex);
54025 maxWidth = Math.max(maxWidth, h.scrollWidth);
54028 if(this.cm.isLocked(colIndex)){
54029 tb = this.getLockedTable();
54032 tb = this.getBodyTable();
54033 index = colIndex - this.cm.getLockedCount();
54036 var rows = tb.rows;
54037 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54038 for(var i = 0; i < stopIndex; i++){
54039 var cell = rows[i].childNodes[index].firstChild;
54040 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54043 return maxWidth + /*margin for error in IE*/ 5;
54046 * Autofit a column to its content.
54047 * @param {Number} colIndex
54048 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54050 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54051 if(this.cm.isHidden(colIndex)){
54052 return; // can't calc a hidden column
54055 var cid = this.cm.getColumnId(colIndex);
54056 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54057 if(this.grid.autoSizeHeaders){
54058 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54061 var newWidth = this.calcColumnWidth(colIndex);
54062 this.cm.setColumnWidth(colIndex,
54063 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54064 if(!suppressEvent){
54065 this.grid.fireEvent("columnresize", colIndex, newWidth);
54070 * Autofits all columns to their content and then expands to fit any extra space in the grid
54072 autoSizeColumns : function(){
54073 var cm = this.grid.colModel;
54074 var colCount = cm.getColumnCount();
54075 for(var i = 0; i < colCount; i++){
54076 this.autoSizeColumn(i, true, true);
54078 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54081 this.updateColumns();
54087 * Autofits all columns to the grid's width proportionate with their current size
54088 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54090 fitColumns : function(reserveScrollSpace){
54091 var cm = this.grid.colModel;
54092 var colCount = cm.getColumnCount();
54096 for (i = 0; i < colCount; i++){
54097 if(!cm.isHidden(i) && !cm.isFixed(i)){
54098 w = cm.getColumnWidth(i);
54104 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54105 if(reserveScrollSpace){
54108 var frac = (avail - cm.getTotalWidth())/width;
54109 while (cols.length){
54112 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54114 this.updateColumns();
54118 onRowSelect : function(rowIndex){
54119 var row = this.getRowComposite(rowIndex);
54120 row.addClass("x-grid-row-selected");
54123 onRowDeselect : function(rowIndex){
54124 var row = this.getRowComposite(rowIndex);
54125 row.removeClass("x-grid-row-selected");
54128 onCellSelect : function(row, col){
54129 var cell = this.getCell(row, col);
54131 Roo.fly(cell).addClass("x-grid-cell-selected");
54135 onCellDeselect : function(row, col){
54136 var cell = this.getCell(row, col);
54138 Roo.fly(cell).removeClass("x-grid-cell-selected");
54142 updateHeaderSortState : function(){
54144 // sort state can be single { field: xxx, direction : yyy}
54145 // or { xxx=>ASC , yyy : DESC ..... }
54148 if (!this.ds.multiSort) {
54149 var state = this.ds.getSortState();
54153 mstate[state.field] = state.direction;
54154 // FIXME... - this is not used here.. but might be elsewhere..
54155 this.sortState = state;
54158 mstate = this.ds.sortToggle;
54160 //remove existing sort classes..
54162 var sc = this.sortClasses;
54163 var hds = this.el.select(this.headerSelector).removeClass(sc);
54165 for(var f in mstate) {
54167 var sortColumn = this.cm.findColumnIndex(f);
54169 if(sortColumn != -1){
54170 var sortDir = mstate[f];
54171 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54180 handleHeaderClick : function(g, index,e){
54182 Roo.log("header click");
54185 // touch events on header are handled by context
54186 this.handleHdCtx(g,index,e);
54191 if(this.headersDisabled){
54194 var dm = g.dataSource, cm = g.colModel;
54195 if(!cm.isSortable(index)){
54200 if (dm.multiSort) {
54201 // update the sortOrder
54203 for(var i = 0; i < cm.config.length; i++ ) {
54205 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54206 continue; // dont' bother, it's not in sort list or being set.
54209 so.push(cm.config[i].dataIndex);
54215 dm.sort(cm.getDataIndex(index));
54219 destroy : function(){
54221 this.colMenu.removeAll();
54222 Roo.menu.MenuMgr.unregister(this.colMenu);
54223 this.colMenu.getEl().remove();
54224 delete this.colMenu;
54227 this.hmenu.removeAll();
54228 Roo.menu.MenuMgr.unregister(this.hmenu);
54229 this.hmenu.getEl().remove();
54232 if(this.grid.enableColumnMove){
54233 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54235 for(var dd in dds){
54236 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54237 var elid = dds[dd].dragElId;
54239 Roo.get(elid).remove();
54240 } else if(dds[dd].config.isTarget){
54241 dds[dd].proxyTop.remove();
54242 dds[dd].proxyBottom.remove();
54245 if(Roo.dd.DDM.locationCache[dd]){
54246 delete Roo.dd.DDM.locationCache[dd];
54249 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54252 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54253 this.bind(null, null);
54254 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54257 handleLockChange : function(){
54258 this.refresh(true);
54261 onDenyColumnLock : function(){
54265 onDenyColumnHide : function(){
54269 handleHdMenuClick : function(item){
54270 var index = this.hdCtxIndex;
54271 var cm = this.cm, ds = this.ds;
54274 ds.sort(cm.getDataIndex(index), "ASC");
54277 ds.sort(cm.getDataIndex(index), "DESC");
54280 var lc = cm.getLockedCount();
54281 if(cm.getColumnCount(true) <= lc+1){
54282 this.onDenyColumnLock();
54286 cm.setLocked(index, true, true);
54287 cm.moveColumn(index, lc);
54288 this.grid.fireEvent("columnmove", index, lc);
54290 cm.setLocked(index, true);
54294 var lc = cm.getLockedCount();
54295 if((lc-1) != index){
54296 cm.setLocked(index, false, true);
54297 cm.moveColumn(index, lc-1);
54298 this.grid.fireEvent("columnmove", index, lc-1);
54300 cm.setLocked(index, false);
54303 case 'wider': // used to expand cols on touch..
54305 var cw = cm.getColumnWidth(index);
54306 cw += (item.id == 'wider' ? 1 : -1) * 50;
54307 cw = Math.max(0, cw);
54308 cw = Math.min(cw,4000);
54309 cm.setColumnWidth(index, cw);
54313 index = cm.getIndexById(item.id.substr(4));
54315 if(item.checked && cm.getColumnCount(true) <= 1){
54316 this.onDenyColumnHide();
54319 cm.setHidden(index, item.checked);
54325 beforeColMenuShow : function(){
54326 var cm = this.cm, colCount = cm.getColumnCount();
54327 this.colMenu.removeAll();
54328 for(var i = 0; i < colCount; i++){
54329 this.colMenu.add(new Roo.menu.CheckItem({
54330 id: "col-"+cm.getColumnId(i),
54331 text: cm.getColumnHeader(i),
54332 checked: !cm.isHidden(i),
54338 handleHdCtx : function(g, index, e){
54340 var hd = this.getHeaderCell(index);
54341 this.hdCtxIndex = index;
54342 var ms = this.hmenu.items, cm = this.cm;
54343 ms.get("asc").setDisabled(!cm.isSortable(index));
54344 ms.get("desc").setDisabled(!cm.isSortable(index));
54345 if(this.grid.enableColLock !== false){
54346 ms.get("lock").setDisabled(cm.isLocked(index));
54347 ms.get("unlock").setDisabled(!cm.isLocked(index));
54349 this.hmenu.show(hd, "tl-bl");
54352 handleHdOver : function(e){
54353 var hd = this.findHeaderCell(e.getTarget());
54354 if(hd && !this.headersDisabled){
54355 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54356 this.fly(hd).addClass("x-grid-hd-over");
54361 handleHdOut : function(e){
54362 var hd = this.findHeaderCell(e.getTarget());
54364 this.fly(hd).removeClass("x-grid-hd-over");
54368 handleSplitDblClick : function(e, t){
54369 var i = this.getCellIndex(t);
54370 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54371 this.autoSizeColumn(i, true);
54376 render : function(){
54379 var colCount = cm.getColumnCount();
54381 if(this.grid.monitorWindowResize === true){
54382 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54384 var header = this.renderHeaders();
54385 var body = this.templates.body.apply({rows:""});
54386 var html = this.templates.master.apply({
54389 lockedHeader: header[0],
54393 //this.updateColumns();
54395 this.grid.getGridEl().dom.innerHTML = html;
54397 this.initElements();
54399 // a kludge to fix the random scolling effect in webkit
54400 this.el.on("scroll", function() {
54401 this.el.dom.scrollTop=0; // hopefully not recursive..
54404 this.scroller.on("scroll", this.handleScroll, this);
54405 this.lockedBody.on("mousewheel", this.handleWheel, this);
54406 this.mainBody.on("mousewheel", this.handleWheel, this);
54408 this.mainHd.on("mouseover", this.handleHdOver, this);
54409 this.mainHd.on("mouseout", this.handleHdOut, this);
54410 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54411 {delegate: "."+this.splitClass});
54413 this.lockedHd.on("mouseover", this.handleHdOver, this);
54414 this.lockedHd.on("mouseout", this.handleHdOut, this);
54415 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54416 {delegate: "."+this.splitClass});
54418 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54419 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54422 this.updateSplitters();
54424 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54425 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54426 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54429 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54430 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54432 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54433 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54435 if(this.grid.enableColLock !== false){
54436 this.hmenu.add('-',
54437 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54438 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54442 this.hmenu.add('-',
54443 {id:"wider", text: this.columnsWiderText},
54444 {id:"narrow", text: this.columnsNarrowText }
54450 if(this.grid.enableColumnHide !== false){
54452 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54453 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54454 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54456 this.hmenu.add('-',
54457 {id:"columns", text: this.columnsText, menu: this.colMenu}
54460 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54462 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54465 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54466 this.dd = new Roo.grid.GridDragZone(this.grid, {
54467 ddGroup : this.grid.ddGroup || 'GridDD'
54473 for(var i = 0; i < colCount; i++){
54474 if(cm.isHidden(i)){
54475 this.hideColumn(i);
54477 if(cm.config[i].align){
54478 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54479 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54483 this.updateHeaderSortState();
54485 this.beforeInitialResize();
54488 // two part rendering gives faster view to the user
54489 this.renderPhase2.defer(1, this);
54492 renderPhase2 : function(){
54493 // render the rows now
54495 if(this.grid.autoSizeColumns){
54496 this.autoSizeColumns();
54500 beforeInitialResize : function(){
54504 onColumnSplitterMoved : function(i, w){
54505 this.userResized = true;
54506 var cm = this.grid.colModel;
54507 cm.setColumnWidth(i, w, true);
54508 var cid = cm.getColumnId(i);
54509 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54510 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54511 this.updateSplitters();
54513 this.grid.fireEvent("columnresize", i, w);
54516 syncRowHeights : function(startIndex, endIndex){
54517 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54518 startIndex = startIndex || 0;
54519 var mrows = this.getBodyTable().rows;
54520 var lrows = this.getLockedTable().rows;
54521 var len = mrows.length-1;
54522 endIndex = Math.min(endIndex || len, len);
54523 for(var i = startIndex; i <= endIndex; i++){
54524 var m = mrows[i], l = lrows[i];
54525 var h = Math.max(m.offsetHeight, l.offsetHeight);
54526 m.style.height = l.style.height = h + "px";
54531 layout : function(initialRender, is2ndPass){
54533 var auto = g.autoHeight;
54534 var scrollOffset = 16;
54535 var c = g.getGridEl(), cm = this.cm,
54536 expandCol = g.autoExpandColumn,
54538 //c.beginMeasure();
54540 if(!c.dom.offsetWidth){ // display:none?
54542 this.lockedWrap.show();
54543 this.mainWrap.show();
54548 var hasLock = this.cm.isLocked(0);
54550 var tbh = this.headerPanel.getHeight();
54551 var bbh = this.footerPanel.getHeight();
54554 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54555 var newHeight = ch + c.getBorderWidth("tb");
54557 newHeight = Math.min(g.maxHeight, newHeight);
54559 c.setHeight(newHeight);
54563 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54566 var s = this.scroller;
54568 var csize = c.getSize(true);
54570 this.el.setSize(csize.width, csize.height);
54572 this.headerPanel.setWidth(csize.width);
54573 this.footerPanel.setWidth(csize.width);
54575 var hdHeight = this.mainHd.getHeight();
54576 var vw = csize.width;
54577 var vh = csize.height - (tbh + bbh);
54581 var bt = this.getBodyTable();
54582 var ltWidth = hasLock ?
54583 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54585 var scrollHeight = bt.offsetHeight;
54586 var scrollWidth = ltWidth + bt.offsetWidth;
54587 var vscroll = false, hscroll = false;
54589 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54591 var lw = this.lockedWrap, mw = this.mainWrap;
54592 var lb = this.lockedBody, mb = this.mainBody;
54594 setTimeout(function(){
54595 var t = s.dom.offsetTop;
54596 var w = s.dom.clientWidth,
54597 h = s.dom.clientHeight;
54600 lw.setSize(ltWidth, h);
54602 mw.setLeftTop(ltWidth, t);
54603 mw.setSize(w-ltWidth, h);
54605 lb.setHeight(h-hdHeight);
54606 mb.setHeight(h-hdHeight);
54608 if(is2ndPass !== true && !gv.userResized && expandCol){
54609 // high speed resize without full column calculation
54611 var ci = cm.getIndexById(expandCol);
54613 ci = cm.findColumnIndex(expandCol);
54615 ci = Math.max(0, ci); // make sure it's got at least the first col.
54616 var expandId = cm.getColumnId(ci);
54617 var tw = cm.getTotalWidth(false);
54618 var currentWidth = cm.getColumnWidth(ci);
54619 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54620 if(currentWidth != cw){
54621 cm.setColumnWidth(ci, cw, true);
54622 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54623 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54624 gv.updateSplitters();
54625 gv.layout(false, true);
54637 onWindowResize : function(){
54638 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54644 appendFooter : function(parentEl){
54648 sortAscText : "Sort Ascending",
54649 sortDescText : "Sort Descending",
54650 lockText : "Lock Column",
54651 unlockText : "Unlock Column",
54652 columnsText : "Columns",
54654 columnsWiderText : "Wider",
54655 columnsNarrowText : "Thinner"
54659 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54660 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54661 this.proxy.el.addClass('x-grid3-col-dd');
54664 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54665 handleMouseDown : function(e){
54669 callHandleMouseDown : function(e){
54670 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54675 * Ext JS Library 1.1.1
54676 * Copyright(c) 2006-2007, Ext JS, LLC.
54678 * Originally Released Under LGPL - original licence link has changed is not relivant.
54681 * <script type="text/javascript">
54685 // This is a support class used internally by the Grid components
54686 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54688 this.view = grid.getView();
54689 this.proxy = this.view.resizeProxy;
54690 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54691 "gridSplitters" + this.grid.getGridEl().id, {
54692 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54694 this.setHandleElId(Roo.id(hd));
54695 this.setOuterHandleElId(Roo.id(hd2));
54696 this.scroll = false;
54698 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54699 fly: Roo.Element.fly,
54701 b4StartDrag : function(x, y){
54702 this.view.headersDisabled = true;
54703 this.proxy.setHeight(this.view.mainWrap.getHeight());
54704 var w = this.cm.getColumnWidth(this.cellIndex);
54705 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54706 this.resetConstraints();
54707 this.setXConstraint(minw, 1000);
54708 this.setYConstraint(0, 0);
54709 this.minX = x - minw;
54710 this.maxX = x + 1000;
54712 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54716 handleMouseDown : function(e){
54717 ev = Roo.EventObject.setEvent(e);
54718 var t = this.fly(ev.getTarget());
54719 if(t.hasClass("x-grid-split")){
54720 this.cellIndex = this.view.getCellIndex(t.dom);
54721 this.split = t.dom;
54722 this.cm = this.grid.colModel;
54723 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54724 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54729 endDrag : function(e){
54730 this.view.headersDisabled = false;
54731 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54732 var diff = endX - this.startPos;
54733 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54736 autoOffset : function(){
54737 this.setDelta(0,0);
54741 * Ext JS Library 1.1.1
54742 * Copyright(c) 2006-2007, Ext JS, LLC.
54744 * Originally Released Under LGPL - original licence link has changed is not relivant.
54747 * <script type="text/javascript">
54751 // This is a support class used internally by the Grid components
54752 Roo.grid.GridDragZone = function(grid, config){
54753 this.view = grid.getView();
54754 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54755 if(this.view.lockedBody){
54756 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54757 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54759 this.scroll = false;
54761 this.ddel = document.createElement('div');
54762 this.ddel.className = 'x-grid-dd-wrap';
54765 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54766 ddGroup : "GridDD",
54768 getDragData : function(e){
54769 var t = Roo.lib.Event.getTarget(e);
54770 var rowIndex = this.view.findRowIndex(t);
54771 var sm = this.grid.selModel;
54773 //Roo.log(rowIndex);
54775 if (sm.getSelectedCell) {
54776 // cell selection..
54777 if (!sm.getSelectedCell()) {
54780 if (rowIndex != sm.getSelectedCell()[0]) {
54786 if(rowIndex !== false){
54791 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54793 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54796 if (e.hasModifier()){
54797 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54800 Roo.log("getDragData");
54805 rowIndex: rowIndex,
54806 selections:sm.getSelections ? sm.getSelections() : (
54807 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54814 onInitDrag : function(e){
54815 var data = this.dragData;
54816 this.ddel.innerHTML = this.grid.getDragDropText();
54817 this.proxy.update(this.ddel);
54818 // fire start drag?
54821 afterRepair : function(){
54822 this.dragging = false;
54825 getRepairXY : function(e, data){
54829 onEndDrag : function(data, e){
54833 onValidDrop : function(dd, e, id){
54838 beforeInvalidDrop : function(e, id){
54843 * Ext JS Library 1.1.1
54844 * Copyright(c) 2006-2007, Ext JS, LLC.
54846 * Originally Released Under LGPL - original licence link has changed is not relivant.
54849 * <script type="text/javascript">
54854 * @class Roo.grid.ColumnModel
54855 * @extends Roo.util.Observable
54856 * This is the default implementation of a ColumnModel used by the Grid. It defines
54857 * the columns in the grid.
54860 var colModel = new Roo.grid.ColumnModel([
54861 {header: "Ticker", width: 60, sortable: true, locked: true},
54862 {header: "Company Name", width: 150, sortable: true},
54863 {header: "Market Cap.", width: 100, sortable: true},
54864 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54865 {header: "Employees", width: 100, sortable: true, resizable: false}
54870 * The config options listed for this class are options which may appear in each
54871 * individual column definition.
54872 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54874 * @param {Object} config An Array of column config objects. See this class's
54875 * config objects for details.
54877 Roo.grid.ColumnModel = function(config){
54879 * The config passed into the constructor
54881 this.config = config;
54884 // if no id, create one
54885 // if the column does not have a dataIndex mapping,
54886 // map it to the order it is in the config
54887 for(var i = 0, len = config.length; i < len; i++){
54889 if(typeof c.dataIndex == "undefined"){
54892 if(typeof c.renderer == "string"){
54893 c.renderer = Roo.util.Format[c.renderer];
54895 if(typeof c.id == "undefined"){
54898 if(c.editor && c.editor.xtype){
54899 c.editor = Roo.factory(c.editor, Roo.grid);
54901 if(c.editor && c.editor.isFormField){
54902 c.editor = new Roo.grid.GridEditor(c.editor);
54904 this.lookup[c.id] = c;
54908 * The width of columns which have no width specified (defaults to 100)
54911 this.defaultWidth = 100;
54914 * Default sortable of columns which have no sortable specified (defaults to false)
54917 this.defaultSortable = false;
54921 * @event widthchange
54922 * Fires when the width of a column changes.
54923 * @param {ColumnModel} this
54924 * @param {Number} columnIndex The column index
54925 * @param {Number} newWidth The new width
54927 "widthchange": true,
54929 * @event headerchange
54930 * Fires when the text of a header changes.
54931 * @param {ColumnModel} this
54932 * @param {Number} columnIndex The column index
54933 * @param {Number} newText The new header text
54935 "headerchange": true,
54937 * @event hiddenchange
54938 * Fires when a column is hidden or "unhidden".
54939 * @param {ColumnModel} this
54940 * @param {Number} columnIndex The column index
54941 * @param {Boolean} hidden true if hidden, false otherwise
54943 "hiddenchange": true,
54945 * @event columnmoved
54946 * Fires when a column is moved.
54947 * @param {ColumnModel} this
54948 * @param {Number} oldIndex
54949 * @param {Number} newIndex
54951 "columnmoved" : true,
54953 * @event columlockchange
54954 * Fires when a column's locked state is changed
54955 * @param {ColumnModel} this
54956 * @param {Number} colIndex
54957 * @param {Boolean} locked true if locked
54959 "columnlockchange" : true
54961 Roo.grid.ColumnModel.superclass.constructor.call(this);
54963 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54965 * @cfg {String} header The header text to display in the Grid view.
54968 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54969 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54970 * specified, the column's index is used as an index into the Record's data Array.
54973 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54974 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54977 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54978 * Defaults to the value of the {@link #defaultSortable} property.
54979 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54982 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54985 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54988 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54991 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54994 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54995 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54996 * default renderer uses the raw data value. If an object is returned (bootstrap only)
54997 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55000 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55003 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55007 * Returns the id of the column at the specified index.
55008 * @param {Number} index The column index
55009 * @return {String} the id
55011 getColumnId : function(index){
55012 return this.config[index].id;
55016 * Returns the column for a specified id.
55017 * @param {String} id The column id
55018 * @return {Object} the column
55020 getColumnById : function(id){
55021 return this.lookup[id];
55026 * Returns the column for a specified dataIndex.
55027 * @param {String} dataIndex The column dataIndex
55028 * @return {Object|Boolean} the column or false if not found
55030 getColumnByDataIndex: function(dataIndex){
55031 var index = this.findColumnIndex(dataIndex);
55032 return index > -1 ? this.config[index] : false;
55036 * Returns the index for a specified column id.
55037 * @param {String} id The column id
55038 * @return {Number} the index, or -1 if not found
55040 getIndexById : function(id){
55041 for(var i = 0, len = this.config.length; i < len; i++){
55042 if(this.config[i].id == id){
55050 * Returns the index for a specified column dataIndex.
55051 * @param {String} dataIndex The column dataIndex
55052 * @return {Number} the index, or -1 if not found
55055 findColumnIndex : function(dataIndex){
55056 for(var i = 0, len = this.config.length; i < len; i++){
55057 if(this.config[i].dataIndex == dataIndex){
55065 moveColumn : function(oldIndex, newIndex){
55066 var c = this.config[oldIndex];
55067 this.config.splice(oldIndex, 1);
55068 this.config.splice(newIndex, 0, c);
55069 this.dataMap = null;
55070 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55073 isLocked : function(colIndex){
55074 return this.config[colIndex].locked === true;
55077 setLocked : function(colIndex, value, suppressEvent){
55078 if(this.isLocked(colIndex) == value){
55081 this.config[colIndex].locked = value;
55082 if(!suppressEvent){
55083 this.fireEvent("columnlockchange", this, colIndex, value);
55087 getTotalLockedWidth : function(){
55088 var totalWidth = 0;
55089 for(var i = 0; i < this.config.length; i++){
55090 if(this.isLocked(i) && !this.isHidden(i)){
55091 this.totalWidth += this.getColumnWidth(i);
55097 getLockedCount : function(){
55098 for(var i = 0, len = this.config.length; i < len; i++){
55099 if(!this.isLocked(i)){
55106 * Returns the number of columns.
55109 getColumnCount : function(visibleOnly){
55110 if(visibleOnly === true){
55112 for(var i = 0, len = this.config.length; i < len; i++){
55113 if(!this.isHidden(i)){
55119 return this.config.length;
55123 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55124 * @param {Function} fn
55125 * @param {Object} scope (optional)
55126 * @return {Array} result
55128 getColumnsBy : function(fn, scope){
55130 for(var i = 0, len = this.config.length; i < len; i++){
55131 var c = this.config[i];
55132 if(fn.call(scope||this, c, i) === true){
55140 * Returns true if the specified column is sortable.
55141 * @param {Number} col The column index
55142 * @return {Boolean}
55144 isSortable : function(col){
55145 if(typeof this.config[col].sortable == "undefined"){
55146 return this.defaultSortable;
55148 return this.config[col].sortable;
55152 * Returns the rendering (formatting) function defined for the column.
55153 * @param {Number} col The column index.
55154 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55156 getRenderer : function(col){
55157 if(!this.config[col].renderer){
55158 return Roo.grid.ColumnModel.defaultRenderer;
55160 return this.config[col].renderer;
55164 * Sets the rendering (formatting) function for a column.
55165 * @param {Number} col The column index
55166 * @param {Function} fn The function to use to process the cell's raw data
55167 * to return HTML markup for the grid view. The render function is called with
55168 * the following parameters:<ul>
55169 * <li>Data value.</li>
55170 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55171 * <li>css A CSS style string to apply to the table cell.</li>
55172 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55173 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55174 * <li>Row index</li>
55175 * <li>Column index</li>
55176 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55178 setRenderer : function(col, fn){
55179 this.config[col].renderer = fn;
55183 * Returns the width for the specified column.
55184 * @param {Number} col The column index
55187 getColumnWidth : function(col){
55188 return this.config[col].width * 1 || this.defaultWidth;
55192 * Sets the width for a column.
55193 * @param {Number} col The column index
55194 * @param {Number} width The new width
55196 setColumnWidth : function(col, width, suppressEvent){
55197 this.config[col].width = width;
55198 this.totalWidth = null;
55199 if(!suppressEvent){
55200 this.fireEvent("widthchange", this, col, width);
55205 * Returns the total width of all columns.
55206 * @param {Boolean} includeHidden True to include hidden column widths
55209 getTotalWidth : function(includeHidden){
55210 if(!this.totalWidth){
55211 this.totalWidth = 0;
55212 for(var i = 0, len = this.config.length; i < len; i++){
55213 if(includeHidden || !this.isHidden(i)){
55214 this.totalWidth += this.getColumnWidth(i);
55218 return this.totalWidth;
55222 * Returns the header for the specified column.
55223 * @param {Number} col The column index
55226 getColumnHeader : function(col){
55227 return this.config[col].header;
55231 * Sets the header for a column.
55232 * @param {Number} col The column index
55233 * @param {String} header The new header
55235 setColumnHeader : function(col, header){
55236 this.config[col].header = header;
55237 this.fireEvent("headerchange", this, col, header);
55241 * Returns the tooltip for the specified column.
55242 * @param {Number} col The column index
55245 getColumnTooltip : function(col){
55246 return this.config[col].tooltip;
55249 * Sets the tooltip for a column.
55250 * @param {Number} col The column index
55251 * @param {String} tooltip The new tooltip
55253 setColumnTooltip : function(col, tooltip){
55254 this.config[col].tooltip = tooltip;
55258 * Returns the dataIndex for the specified column.
55259 * @param {Number} col The column index
55262 getDataIndex : function(col){
55263 return this.config[col].dataIndex;
55267 * Sets the dataIndex for a column.
55268 * @param {Number} col The column index
55269 * @param {Number} dataIndex The new dataIndex
55271 setDataIndex : function(col, dataIndex){
55272 this.config[col].dataIndex = dataIndex;
55278 * Returns true if the cell is editable.
55279 * @param {Number} colIndex The column index
55280 * @param {Number} rowIndex The row index
55281 * @return {Boolean}
55283 isCellEditable : function(colIndex, rowIndex){
55284 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55288 * Returns the editor defined for the cell/column.
55289 * return false or null to disable editing.
55290 * @param {Number} colIndex The column index
55291 * @param {Number} rowIndex The row index
55294 getCellEditor : function(colIndex, rowIndex){
55295 return this.config[colIndex].editor;
55299 * Sets if a column is editable.
55300 * @param {Number} col The column index
55301 * @param {Boolean} editable True if the column is editable
55303 setEditable : function(col, editable){
55304 this.config[col].editable = editable;
55309 * Returns true if the column is hidden.
55310 * @param {Number} colIndex The column index
55311 * @return {Boolean}
55313 isHidden : function(colIndex){
55314 return this.config[colIndex].hidden;
55319 * Returns true if the column width cannot be changed
55321 isFixed : function(colIndex){
55322 return this.config[colIndex].fixed;
55326 * Returns true if the column can be resized
55327 * @return {Boolean}
55329 isResizable : function(colIndex){
55330 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55333 * Sets if a column is hidden.
55334 * @param {Number} colIndex The column index
55335 * @param {Boolean} hidden True if the column is hidden
55337 setHidden : function(colIndex, hidden){
55338 this.config[colIndex].hidden = hidden;
55339 this.totalWidth = null;
55340 this.fireEvent("hiddenchange", this, colIndex, hidden);
55344 * Sets the editor for a column.
55345 * @param {Number} col The column index
55346 * @param {Object} editor The editor object
55348 setEditor : function(col, editor){
55349 this.config[col].editor = editor;
55353 Roo.grid.ColumnModel.defaultRenderer = function(value){
55354 if(typeof value == "string" && value.length < 1){
55360 // Alias for backwards compatibility
55361 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55364 * Ext JS Library 1.1.1
55365 * Copyright(c) 2006-2007, Ext JS, LLC.
55367 * Originally Released Under LGPL - original licence link has changed is not relivant.
55370 * <script type="text/javascript">
55374 * @class Roo.grid.AbstractSelectionModel
55375 * @extends Roo.util.Observable
55376 * Abstract base class for grid SelectionModels. It provides the interface that should be
55377 * implemented by descendant classes. This class should not be directly instantiated.
55380 Roo.grid.AbstractSelectionModel = function(){
55381 this.locked = false;
55382 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55385 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55386 /** @ignore Called by the grid automatically. Do not call directly. */
55387 init : function(grid){
55393 * Locks the selections.
55396 this.locked = true;
55400 * Unlocks the selections.
55402 unlock : function(){
55403 this.locked = false;
55407 * Returns true if the selections are locked.
55408 * @return {Boolean}
55410 isLocked : function(){
55411 return this.locked;
55415 * Ext JS Library 1.1.1
55416 * Copyright(c) 2006-2007, Ext JS, LLC.
55418 * Originally Released Under LGPL - original licence link has changed is not relivant.
55421 * <script type="text/javascript">
55424 * @extends Roo.grid.AbstractSelectionModel
55425 * @class Roo.grid.RowSelectionModel
55426 * The default SelectionModel used by {@link Roo.grid.Grid}.
55427 * It supports multiple selections and keyboard selection/navigation.
55429 * @param {Object} config
55431 Roo.grid.RowSelectionModel = function(config){
55432 Roo.apply(this, config);
55433 this.selections = new Roo.util.MixedCollection(false, function(o){
55438 this.lastActive = false;
55442 * @event selectionchange
55443 * Fires when the selection changes
55444 * @param {SelectionModel} this
55446 "selectionchange" : true,
55448 * @event afterselectionchange
55449 * Fires after the selection changes (eg. by key press or clicking)
55450 * @param {SelectionModel} this
55452 "afterselectionchange" : true,
55454 * @event beforerowselect
55455 * Fires when a row is selected being selected, return false to cancel.
55456 * @param {SelectionModel} this
55457 * @param {Number} rowIndex The selected index
55458 * @param {Boolean} keepExisting False if other selections will be cleared
55460 "beforerowselect" : true,
55463 * Fires when a row is selected.
55464 * @param {SelectionModel} this
55465 * @param {Number} rowIndex The selected index
55466 * @param {Roo.data.Record} r The record
55468 "rowselect" : true,
55470 * @event rowdeselect
55471 * Fires when a row is deselected.
55472 * @param {SelectionModel} this
55473 * @param {Number} rowIndex The selected index
55475 "rowdeselect" : true
55477 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55478 this.locked = false;
55481 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55483 * @cfg {Boolean} singleSelect
55484 * True to allow selection of only one row at a time (defaults to false)
55486 singleSelect : false,
55489 initEvents : function(){
55491 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55492 this.grid.on("mousedown", this.handleMouseDown, this);
55493 }else{ // allow click to work like normal
55494 this.grid.on("rowclick", this.handleDragableRowClick, this);
55497 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55498 "up" : function(e){
55500 this.selectPrevious(e.shiftKey);
55501 }else if(this.last !== false && this.lastActive !== false){
55502 var last = this.last;
55503 this.selectRange(this.last, this.lastActive-1);
55504 this.grid.getView().focusRow(this.lastActive);
55505 if(last !== false){
55509 this.selectFirstRow();
55511 this.fireEvent("afterselectionchange", this);
55513 "down" : function(e){
55515 this.selectNext(e.shiftKey);
55516 }else if(this.last !== false && this.lastActive !== false){
55517 var last = this.last;
55518 this.selectRange(this.last, this.lastActive+1);
55519 this.grid.getView().focusRow(this.lastActive);
55520 if(last !== false){
55524 this.selectFirstRow();
55526 this.fireEvent("afterselectionchange", this);
55531 var view = this.grid.view;
55532 view.on("refresh", this.onRefresh, this);
55533 view.on("rowupdated", this.onRowUpdated, this);
55534 view.on("rowremoved", this.onRemove, this);
55538 onRefresh : function(){
55539 var ds = this.grid.dataSource, i, v = this.grid.view;
55540 var s = this.selections;
55541 s.each(function(r){
55542 if((i = ds.indexOfId(r.id)) != -1){
55551 onRemove : function(v, index, r){
55552 this.selections.remove(r);
55556 onRowUpdated : function(v, index, r){
55557 if(this.isSelected(r)){
55558 v.onRowSelect(index);
55564 * @param {Array} records The records to select
55565 * @param {Boolean} keepExisting (optional) True to keep existing selections
55567 selectRecords : function(records, keepExisting){
55569 this.clearSelections();
55571 var ds = this.grid.dataSource;
55572 for(var i = 0, len = records.length; i < len; i++){
55573 this.selectRow(ds.indexOf(records[i]), true);
55578 * Gets the number of selected rows.
55581 getCount : function(){
55582 return this.selections.length;
55586 * Selects the first row in the grid.
55588 selectFirstRow : function(){
55593 * Select the last row.
55594 * @param {Boolean} keepExisting (optional) True to keep existing selections
55596 selectLastRow : function(keepExisting){
55597 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55601 * Selects the row immediately following the last selected row.
55602 * @param {Boolean} keepExisting (optional) True to keep existing selections
55604 selectNext : function(keepExisting){
55605 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55606 this.selectRow(this.last+1, keepExisting);
55607 this.grid.getView().focusRow(this.last);
55612 * Selects the row that precedes the last selected row.
55613 * @param {Boolean} keepExisting (optional) True to keep existing selections
55615 selectPrevious : function(keepExisting){
55617 this.selectRow(this.last-1, keepExisting);
55618 this.grid.getView().focusRow(this.last);
55623 * Returns the selected records
55624 * @return {Array} Array of selected records
55626 getSelections : function(){
55627 return [].concat(this.selections.items);
55631 * Returns the first selected record.
55634 getSelected : function(){
55635 return this.selections.itemAt(0);
55640 * Clears all selections.
55642 clearSelections : function(fast){
55643 if(this.locked) return;
55645 var ds = this.grid.dataSource;
55646 var s = this.selections;
55647 s.each(function(r){
55648 this.deselectRow(ds.indexOfId(r.id));
55652 this.selections.clear();
55659 * Selects all rows.
55661 selectAll : function(){
55662 if(this.locked) return;
55663 this.selections.clear();
55664 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55665 this.selectRow(i, true);
55670 * Returns True if there is a selection.
55671 * @return {Boolean}
55673 hasSelection : function(){
55674 return this.selections.length > 0;
55678 * Returns True if the specified row is selected.
55679 * @param {Number/Record} record The record or index of the record to check
55680 * @return {Boolean}
55682 isSelected : function(index){
55683 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55684 return (r && this.selections.key(r.id) ? true : false);
55688 * Returns True if the specified record id is selected.
55689 * @param {String} id The id of record to check
55690 * @return {Boolean}
55692 isIdSelected : function(id){
55693 return (this.selections.key(id) ? true : false);
55697 handleMouseDown : function(e, t){
55698 var view = this.grid.getView(), rowIndex;
55699 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55702 if(e.shiftKey && this.last !== false){
55703 var last = this.last;
55704 this.selectRange(last, rowIndex, e.ctrlKey);
55705 this.last = last; // reset the last
55706 view.focusRow(rowIndex);
55708 var isSelected = this.isSelected(rowIndex);
55709 if(e.button !== 0 && isSelected){
55710 view.focusRow(rowIndex);
55711 }else if(e.ctrlKey && isSelected){
55712 this.deselectRow(rowIndex);
55713 }else if(!isSelected){
55714 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55715 view.focusRow(rowIndex);
55718 this.fireEvent("afterselectionchange", this);
55721 handleDragableRowClick : function(grid, rowIndex, e)
55723 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55724 this.selectRow(rowIndex, false);
55725 grid.view.focusRow(rowIndex);
55726 this.fireEvent("afterselectionchange", this);
55731 * Selects multiple rows.
55732 * @param {Array} rows Array of the indexes of the row to select
55733 * @param {Boolean} keepExisting (optional) True to keep existing selections
55735 selectRows : function(rows, keepExisting){
55737 this.clearSelections();
55739 for(var i = 0, len = rows.length; i < len; i++){
55740 this.selectRow(rows[i], true);
55745 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55746 * @param {Number} startRow The index of the first row in the range
55747 * @param {Number} endRow The index of the last row in the range
55748 * @param {Boolean} keepExisting (optional) True to retain existing selections
55750 selectRange : function(startRow, endRow, keepExisting){
55751 if(this.locked) return;
55753 this.clearSelections();
55755 if(startRow <= endRow){
55756 for(var i = startRow; i <= endRow; i++){
55757 this.selectRow(i, true);
55760 for(var i = startRow; i >= endRow; i--){
55761 this.selectRow(i, true);
55767 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55768 * @param {Number} startRow The index of the first row in the range
55769 * @param {Number} endRow The index of the last row in the range
55771 deselectRange : function(startRow, endRow, preventViewNotify){
55772 if(this.locked) return;
55773 for(var i = startRow; i <= endRow; i++){
55774 this.deselectRow(i, preventViewNotify);
55780 * @param {Number} row The index of the row to select
55781 * @param {Boolean} keepExisting (optional) True to keep existing selections
55783 selectRow : function(index, keepExisting, preventViewNotify){
55784 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55785 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55786 if(!keepExisting || this.singleSelect){
55787 this.clearSelections();
55789 var r = this.grid.dataSource.getAt(index);
55790 this.selections.add(r);
55791 this.last = this.lastActive = index;
55792 if(!preventViewNotify){
55793 this.grid.getView().onRowSelect(index);
55795 this.fireEvent("rowselect", this, index, r);
55796 this.fireEvent("selectionchange", this);
55802 * @param {Number} row The index of the row to deselect
55804 deselectRow : function(index, preventViewNotify){
55805 if(this.locked) return;
55806 if(this.last == index){
55809 if(this.lastActive == index){
55810 this.lastActive = false;
55812 var r = this.grid.dataSource.getAt(index);
55813 this.selections.remove(r);
55814 if(!preventViewNotify){
55815 this.grid.getView().onRowDeselect(index);
55817 this.fireEvent("rowdeselect", this, index);
55818 this.fireEvent("selectionchange", this);
55822 restoreLast : function(){
55824 this.last = this._last;
55829 acceptsNav : function(row, col, cm){
55830 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55834 onEditorKey : function(field, e){
55835 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55840 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55842 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55844 }else if(k == e.ENTER && !e.ctrlKey){
55848 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55850 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55852 }else if(k == e.ESC){
55856 g.startEditing(newCell[0], newCell[1]);
55861 * Ext JS Library 1.1.1
55862 * Copyright(c) 2006-2007, Ext JS, LLC.
55864 * Originally Released Under LGPL - original licence link has changed is not relivant.
55867 * <script type="text/javascript">
55870 * @class Roo.grid.CellSelectionModel
55871 * @extends Roo.grid.AbstractSelectionModel
55872 * This class provides the basic implementation for cell selection in a grid.
55874 * @param {Object} config The object containing the configuration of this model.
55875 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55877 Roo.grid.CellSelectionModel = function(config){
55878 Roo.apply(this, config);
55880 this.selection = null;
55884 * @event beforerowselect
55885 * Fires before a cell is selected.
55886 * @param {SelectionModel} this
55887 * @param {Number} rowIndex The selected row index
55888 * @param {Number} colIndex The selected cell index
55890 "beforecellselect" : true,
55892 * @event cellselect
55893 * Fires when a cell is selected.
55894 * @param {SelectionModel} this
55895 * @param {Number} rowIndex The selected row index
55896 * @param {Number} colIndex The selected cell index
55898 "cellselect" : true,
55900 * @event selectionchange
55901 * Fires when the active selection changes.
55902 * @param {SelectionModel} this
55903 * @param {Object} selection null for no selection or an object (o) with two properties
55905 <li>o.record: the record object for the row the selection is in</li>
55906 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55909 "selectionchange" : true,
55912 * Fires when the tab (or enter) was pressed on the last editable cell
55913 * You can use this to trigger add new row.
55914 * @param {SelectionModel} this
55918 * @event beforeeditnext
55919 * Fires before the next editable sell is made active
55920 * You can use this to skip to another cell or fire the tabend
55921 * if you set cell to false
55922 * @param {Object} eventdata object : { cell : [ row, col ] }
55924 "beforeeditnext" : true
55926 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55929 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55931 enter_is_tab: false,
55934 initEvents : function(){
55935 this.grid.on("mousedown", this.handleMouseDown, this);
55936 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55937 var view = this.grid.view;
55938 view.on("refresh", this.onViewChange, this);
55939 view.on("rowupdated", this.onRowUpdated, this);
55940 view.on("beforerowremoved", this.clearSelections, this);
55941 view.on("beforerowsinserted", this.clearSelections, this);
55942 if(this.grid.isEditor){
55943 this.grid.on("beforeedit", this.beforeEdit, this);
55948 beforeEdit : function(e){
55949 this.select(e.row, e.column, false, true, e.record);
55953 onRowUpdated : function(v, index, r){
55954 if(this.selection && this.selection.record == r){
55955 v.onCellSelect(index, this.selection.cell[1]);
55960 onViewChange : function(){
55961 this.clearSelections(true);
55965 * Returns the currently selected cell,.
55966 * @return {Array} The selected cell (row, column) or null if none selected.
55968 getSelectedCell : function(){
55969 return this.selection ? this.selection.cell : null;
55973 * Clears all selections.
55974 * @param {Boolean} true to prevent the gridview from being notified about the change.
55976 clearSelections : function(preventNotify){
55977 var s = this.selection;
55979 if(preventNotify !== true){
55980 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55982 this.selection = null;
55983 this.fireEvent("selectionchange", this, null);
55988 * Returns true if there is a selection.
55989 * @return {Boolean}
55991 hasSelection : function(){
55992 return this.selection ? true : false;
55996 handleMouseDown : function(e, t){
55997 var v = this.grid.getView();
55998 if(this.isLocked()){
56001 var row = v.findRowIndex(t);
56002 var cell = v.findCellIndex(t);
56003 if(row !== false && cell !== false){
56004 this.select(row, cell);
56010 * @param {Number} rowIndex
56011 * @param {Number} collIndex
56013 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56014 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56015 this.clearSelections();
56016 r = r || this.grid.dataSource.getAt(rowIndex);
56019 cell : [rowIndex, colIndex]
56021 if(!preventViewNotify){
56022 var v = this.grid.getView();
56023 v.onCellSelect(rowIndex, colIndex);
56024 if(preventFocus !== true){
56025 v.focusCell(rowIndex, colIndex);
56028 this.fireEvent("cellselect", this, rowIndex, colIndex);
56029 this.fireEvent("selectionchange", this, this.selection);
56034 isSelectable : function(rowIndex, colIndex, cm){
56035 return !cm.isHidden(colIndex);
56039 handleKeyDown : function(e){
56040 //Roo.log('Cell Sel Model handleKeyDown');
56041 if(!e.isNavKeyPress()){
56044 var g = this.grid, s = this.selection;
56047 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56049 this.select(cell[0], cell[1]);
56054 var walk = function(row, col, step){
56055 return g.walkCells(row, col, step, sm.isSelectable, sm);
56057 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56064 // handled by onEditorKey
56065 if (g.isEditor && g.editing) {
56069 newCell = walk(r, c-1, -1);
56071 newCell = walk(r, c+1, 1);
56076 newCell = walk(r+1, c, 1);
56080 newCell = walk(r-1, c, -1);
56084 newCell = walk(r, c+1, 1);
56088 newCell = walk(r, c-1, -1);
56093 if(g.isEditor && !g.editing){
56094 g.startEditing(r, c);
56103 this.select(newCell[0], newCell[1]);
56109 acceptsNav : function(row, col, cm){
56110 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56114 * @param {Number} field (not used) - as it's normally used as a listener
56115 * @param {Number} e - event - fake it by using
56117 * var e = Roo.EventObjectImpl.prototype;
56118 * e.keyCode = e.TAB
56122 onEditorKey : function(field, e){
56124 var k = e.getKey(),
56127 ed = g.activeEditor,
56129 ///Roo.log('onEditorKey' + k);
56132 if (this.enter_is_tab && k == e.ENTER) {
56138 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56140 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56146 } else if(k == e.ENTER && !e.ctrlKey){
56149 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56151 } else if(k == e.ESC){
56156 var ecall = { cell : newCell, forward : forward };
56157 this.fireEvent('beforeeditnext', ecall );
56158 newCell = ecall.cell;
56159 forward = ecall.forward;
56163 //Roo.log('next cell after edit');
56164 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56165 } else if (forward) {
56166 // tabbed past last
56167 this.fireEvent.defer(100, this, ['tabend',this]);
56172 * Ext JS Library 1.1.1
56173 * Copyright(c) 2006-2007, Ext JS, LLC.
56175 * Originally Released Under LGPL - original licence link has changed is not relivant.
56178 * <script type="text/javascript">
56182 * @class Roo.grid.EditorGrid
56183 * @extends Roo.grid.Grid
56184 * Class for creating and editable grid.
56185 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56186 * The container MUST have some type of size defined for the grid to fill. The container will be
56187 * automatically set to position relative if it isn't already.
56188 * @param {Object} dataSource The data model to bind to
56189 * @param {Object} colModel The column model with info about this grid's columns
56191 Roo.grid.EditorGrid = function(container, config){
56192 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56193 this.getGridEl().addClass("xedit-grid");
56195 if(!this.selModel){
56196 this.selModel = new Roo.grid.CellSelectionModel();
56199 this.activeEditor = null;
56203 * @event beforeedit
56204 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56205 * <ul style="padding:5px;padding-left:16px;">
56206 * <li>grid - This grid</li>
56207 * <li>record - The record being edited</li>
56208 * <li>field - The field name being edited</li>
56209 * <li>value - The value for the field being edited.</li>
56210 * <li>row - The grid row index</li>
56211 * <li>column - The grid column index</li>
56212 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56214 * @param {Object} e An edit event (see above for description)
56216 "beforeedit" : true,
56219 * Fires after a cell is edited. <br />
56220 * <ul style="padding:5px;padding-left:16px;">
56221 * <li>grid - This grid</li>
56222 * <li>record - The record being edited</li>
56223 * <li>field - The field name being edited</li>
56224 * <li>value - The value being set</li>
56225 * <li>originalValue - The original value for the field, before the edit.</li>
56226 * <li>row - The grid row index</li>
56227 * <li>column - The grid column index</li>
56229 * @param {Object} e An edit event (see above for description)
56231 "afteredit" : true,
56233 * @event validateedit
56234 * Fires after a cell is edited, but before the value is set in the record.
56235 * You can use this to modify the value being set in the field, Return false
56236 * to cancel the change. The edit event object has the following properties <br />
56237 * <ul style="padding:5px;padding-left:16px;">
56238 * <li>editor - This editor</li>
56239 * <li>grid - This grid</li>
56240 * <li>record - The record being edited</li>
56241 * <li>field - The field name being edited</li>
56242 * <li>value - The value being set</li>
56243 * <li>originalValue - The original value for the field, before the edit.</li>
56244 * <li>row - The grid row index</li>
56245 * <li>column - The grid column index</li>
56246 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56248 * @param {Object} e An edit event (see above for description)
56250 "validateedit" : true
56252 this.on("bodyscroll", this.stopEditing, this);
56253 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56256 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56258 * @cfg {Number} clicksToEdit
56259 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56266 trackMouseOver: false, // causes very odd FF errors
56268 onCellDblClick : function(g, row, col){
56269 this.startEditing(row, col);
56272 onEditComplete : function(ed, value, startValue){
56273 this.editing = false;
56274 this.activeEditor = null;
56275 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56277 var field = this.colModel.getDataIndex(ed.col);
56282 originalValue: startValue,
56289 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56292 if(String(value) !== String(startValue)){
56294 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56295 r.set(field, e.value);
56296 // if we are dealing with a combo box..
56297 // then we also set the 'name' colum to be the displayField
56298 if (ed.field.displayField && ed.field.name) {
56299 r.set(ed.field.name, ed.field.el.dom.value);
56302 delete e.cancel; //?? why!!!
56303 this.fireEvent("afteredit", e);
56306 this.fireEvent("afteredit", e); // always fire it!
56308 this.view.focusCell(ed.row, ed.col);
56312 * Starts editing the specified for the specified row/column
56313 * @param {Number} rowIndex
56314 * @param {Number} colIndex
56316 startEditing : function(row, col){
56317 this.stopEditing();
56318 if(this.colModel.isCellEditable(col, row)){
56319 this.view.ensureVisible(row, col, true);
56321 var r = this.dataSource.getAt(row);
56322 var field = this.colModel.getDataIndex(col);
56323 var cell = Roo.get(this.view.getCell(row,col));
56328 value: r.data[field],
56333 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56334 this.editing = true;
56335 var ed = this.colModel.getCellEditor(col, row);
56341 ed.render(ed.parentEl || document.body);
56347 (function(){ // complex but required for focus issues in safari, ie and opera
56351 ed.on("complete", this.onEditComplete, this, {single: true});
56352 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56353 this.activeEditor = ed;
56354 var v = r.data[field];
56355 ed.startEdit(this.view.getCell(row, col), v);
56356 // combo's with 'displayField and name set
56357 if (ed.field.displayField && ed.field.name) {
56358 ed.field.el.dom.value = r.data[ed.field.name];
56362 }).defer(50, this);
56368 * Stops any active editing
56370 stopEditing : function(){
56371 if(this.activeEditor){
56372 this.activeEditor.completeEdit();
56374 this.activeEditor = null;
56378 * Called to get grid's drag proxy text, by default returns this.ddText.
56381 getDragDropText : function(){
56382 var count = this.selModel.getSelectedCell() ? 1 : 0;
56383 return String.format(this.ddText, count, count == 1 ? '' : 's');
56388 * Ext JS Library 1.1.1
56389 * Copyright(c) 2006-2007, Ext JS, LLC.
56391 * Originally Released Under LGPL - original licence link has changed is not relivant.
56394 * <script type="text/javascript">
56397 // private - not really -- you end up using it !
56398 // This is a support class used internally by the Grid components
56401 * @class Roo.grid.GridEditor
56402 * @extends Roo.Editor
56403 * Class for creating and editable grid elements.
56404 * @param {Object} config any settings (must include field)
56406 Roo.grid.GridEditor = function(field, config){
56407 if (!config && field.field) {
56409 field = Roo.factory(config.field, Roo.form);
56411 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56412 field.monitorTab = false;
56415 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56418 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56421 alignment: "tl-tl",
56424 cls: "x-small-editor x-grid-editor",
56429 * Ext JS Library 1.1.1
56430 * Copyright(c) 2006-2007, Ext JS, LLC.
56432 * Originally Released Under LGPL - original licence link has changed is not relivant.
56435 * <script type="text/javascript">
56440 Roo.grid.PropertyRecord = Roo.data.Record.create([
56441 {name:'name',type:'string'}, 'value'
56445 Roo.grid.PropertyStore = function(grid, source){
56447 this.store = new Roo.data.Store({
56448 recordType : Roo.grid.PropertyRecord
56450 this.store.on('update', this.onUpdate, this);
56452 this.setSource(source);
56454 Roo.grid.PropertyStore.superclass.constructor.call(this);
56459 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56460 setSource : function(o){
56462 this.store.removeAll();
56465 if(this.isEditableValue(o[k])){
56466 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56469 this.store.loadRecords({records: data}, {}, true);
56472 onUpdate : function(ds, record, type){
56473 if(type == Roo.data.Record.EDIT){
56474 var v = record.data['value'];
56475 var oldValue = record.modified['value'];
56476 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56477 this.source[record.id] = v;
56479 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56486 getProperty : function(row){
56487 return this.store.getAt(row);
56490 isEditableValue: function(val){
56491 if(val && val instanceof Date){
56493 }else if(typeof val == 'object' || typeof val == 'function'){
56499 setValue : function(prop, value){
56500 this.source[prop] = value;
56501 this.store.getById(prop).set('value', value);
56504 getSource : function(){
56505 return this.source;
56509 Roo.grid.PropertyColumnModel = function(grid, store){
56512 g.PropertyColumnModel.superclass.constructor.call(this, [
56513 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56514 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56516 this.store = store;
56517 this.bselect = Roo.DomHelper.append(document.body, {
56518 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56519 {tag: 'option', value: 'true', html: 'true'},
56520 {tag: 'option', value: 'false', html: 'false'}
56523 Roo.id(this.bselect);
56526 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56527 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56528 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56529 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56530 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56532 this.renderCellDelegate = this.renderCell.createDelegate(this);
56533 this.renderPropDelegate = this.renderProp.createDelegate(this);
56536 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56540 valueText : 'Value',
56542 dateFormat : 'm/j/Y',
56545 renderDate : function(dateVal){
56546 return dateVal.dateFormat(this.dateFormat);
56549 renderBool : function(bVal){
56550 return bVal ? 'true' : 'false';
56553 isCellEditable : function(colIndex, rowIndex){
56554 return colIndex == 1;
56557 getRenderer : function(col){
56559 this.renderCellDelegate : this.renderPropDelegate;
56562 renderProp : function(v){
56563 return this.getPropertyName(v);
56566 renderCell : function(val){
56568 if(val instanceof Date){
56569 rv = this.renderDate(val);
56570 }else if(typeof val == 'boolean'){
56571 rv = this.renderBool(val);
56573 return Roo.util.Format.htmlEncode(rv);
56576 getPropertyName : function(name){
56577 var pn = this.grid.propertyNames;
56578 return pn && pn[name] ? pn[name] : name;
56581 getCellEditor : function(colIndex, rowIndex){
56582 var p = this.store.getProperty(rowIndex);
56583 var n = p.data['name'], val = p.data['value'];
56585 if(typeof(this.grid.customEditors[n]) == 'string'){
56586 return this.editors[this.grid.customEditors[n]];
56588 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56589 return this.grid.customEditors[n];
56591 if(val instanceof Date){
56592 return this.editors['date'];
56593 }else if(typeof val == 'number'){
56594 return this.editors['number'];
56595 }else if(typeof val == 'boolean'){
56596 return this.editors['boolean'];
56598 return this.editors['string'];
56604 * @class Roo.grid.PropertyGrid
56605 * @extends Roo.grid.EditorGrid
56606 * This class represents the interface of a component based property grid control.
56607 * <br><br>Usage:<pre><code>
56608 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56616 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56617 * The container MUST have some type of size defined for the grid to fill. The container will be
56618 * automatically set to position relative if it isn't already.
56619 * @param {Object} config A config object that sets properties on this grid.
56621 Roo.grid.PropertyGrid = function(container, config){
56622 config = config || {};
56623 var store = new Roo.grid.PropertyStore(this);
56624 this.store = store;
56625 var cm = new Roo.grid.PropertyColumnModel(this, store);
56626 store.store.sort('name', 'ASC');
56627 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56630 enableColLock:false,
56631 enableColumnMove:false,
56633 trackMouseOver: false,
56636 this.getGridEl().addClass('x-props-grid');
56637 this.lastEditRow = null;
56638 this.on('columnresize', this.onColumnResize, this);
56641 * @event beforepropertychange
56642 * Fires before a property changes (return false to stop?)
56643 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56644 * @param {String} id Record Id
56645 * @param {String} newval New Value
56646 * @param {String} oldval Old Value
56648 "beforepropertychange": true,
56650 * @event propertychange
56651 * Fires after a property changes
56652 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56653 * @param {String} id Record Id
56654 * @param {String} newval New Value
56655 * @param {String} oldval Old Value
56657 "propertychange": true
56659 this.customEditors = this.customEditors || {};
56661 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56664 * @cfg {Object} customEditors map of colnames=> custom editors.
56665 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56666 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56667 * false disables editing of the field.
56671 * @cfg {Object} propertyNames map of property Names to their displayed value
56674 render : function(){
56675 Roo.grid.PropertyGrid.superclass.render.call(this);
56676 this.autoSize.defer(100, this);
56679 autoSize : function(){
56680 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56682 this.view.fitColumns();
56686 onColumnResize : function(){
56687 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56691 * Sets the data for the Grid
56692 * accepts a Key => Value object of all the elements avaiable.
56693 * @param {Object} data to appear in grid.
56695 setSource : function(source){
56696 this.store.setSource(source);
56700 * Gets all the data from the grid.
56701 * @return {Object} data data stored in grid
56703 getSource : function(){
56704 return this.store.getSource();
56713 * @class Roo.grid.Calendar
56714 * @extends Roo.util.Grid
56715 * This class extends the Grid to provide a calendar widget
56716 * <br><br>Usage:<pre><code>
56717 var grid = new Roo.grid.Calendar("my-container-id", {
56720 selModel: mySelectionModel,
56721 autoSizeColumns: true,
56722 monitorWindowResize: false,
56723 trackMouseOver: true
56724 eventstore : real data store..
56730 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56731 * The container MUST have some type of size defined for the grid to fill. The container will be
56732 * automatically set to position relative if it isn't already.
56733 * @param {Object} config A config object that sets properties on this grid.
56735 Roo.grid.Calendar = function(container, config){
56736 // initialize the container
56737 this.container = Roo.get(container);
56738 this.container.update("");
56739 this.container.setStyle("overflow", "hidden");
56740 this.container.addClass('x-grid-container');
56742 this.id = this.container.id;
56744 Roo.apply(this, config);
56745 // check and correct shorthanded configs
56749 for (var r = 0;r < 6;r++) {
56752 for (var c =0;c < 7;c++) {
56756 if (this.eventStore) {
56757 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56758 this.eventStore.on('load',this.onLoad, this);
56759 this.eventStore.on('beforeload',this.clearEvents, this);
56763 this.dataSource = new Roo.data.Store({
56764 proxy: new Roo.data.MemoryProxy(rows),
56765 reader: new Roo.data.ArrayReader({}, [
56766 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56769 this.dataSource.load();
56770 this.ds = this.dataSource;
56771 this.ds.xmodule = this.xmodule || false;
56774 var cellRender = function(v,x,r)
56776 return String.format(
56777 '<div class="fc-day fc-widget-content"><div>' +
56778 '<div class="fc-event-container"></div>' +
56779 '<div class="fc-day-number">{0}</div>'+
56781 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56782 '</div></div>', v);
56787 this.colModel = new Roo.grid.ColumnModel( [
56789 xtype: 'ColumnModel',
56791 dataIndex : 'weekday0',
56793 renderer : cellRender
56796 xtype: 'ColumnModel',
56798 dataIndex : 'weekday1',
56800 renderer : cellRender
56803 xtype: 'ColumnModel',
56805 dataIndex : 'weekday2',
56806 header : 'Tuesday',
56807 renderer : cellRender
56810 xtype: 'ColumnModel',
56812 dataIndex : 'weekday3',
56813 header : 'Wednesday',
56814 renderer : cellRender
56817 xtype: 'ColumnModel',
56819 dataIndex : 'weekday4',
56820 header : 'Thursday',
56821 renderer : cellRender
56824 xtype: 'ColumnModel',
56826 dataIndex : 'weekday5',
56828 renderer : cellRender
56831 xtype: 'ColumnModel',
56833 dataIndex : 'weekday6',
56834 header : 'Saturday',
56835 renderer : cellRender
56838 this.cm = this.colModel;
56839 this.cm.xmodule = this.xmodule || false;
56843 //this.selModel = new Roo.grid.CellSelectionModel();
56844 //this.sm = this.selModel;
56845 //this.selModel.init(this);
56849 this.container.setWidth(this.width);
56853 this.container.setHeight(this.height);
56860 * The raw click event for the entire grid.
56861 * @param {Roo.EventObject} e
56866 * The raw dblclick event for the entire grid.
56867 * @param {Roo.EventObject} e
56871 * @event contextmenu
56872 * The raw contextmenu event for the entire grid.
56873 * @param {Roo.EventObject} e
56875 "contextmenu" : true,
56878 * The raw mousedown event for the entire grid.
56879 * @param {Roo.EventObject} e
56881 "mousedown" : true,
56884 * The raw mouseup event for the entire grid.
56885 * @param {Roo.EventObject} e
56890 * The raw mouseover event for the entire grid.
56891 * @param {Roo.EventObject} e
56893 "mouseover" : true,
56896 * The raw mouseout event for the entire grid.
56897 * @param {Roo.EventObject} e
56902 * The raw keypress event for the entire grid.
56903 * @param {Roo.EventObject} e
56908 * The raw keydown event for the entire grid.
56909 * @param {Roo.EventObject} e
56917 * Fires when a cell is clicked
56918 * @param {Grid} this
56919 * @param {Number} rowIndex
56920 * @param {Number} columnIndex
56921 * @param {Roo.EventObject} e
56923 "cellclick" : true,
56925 * @event celldblclick
56926 * Fires when a cell is double clicked
56927 * @param {Grid} this
56928 * @param {Number} rowIndex
56929 * @param {Number} columnIndex
56930 * @param {Roo.EventObject} e
56932 "celldblclick" : true,
56935 * Fires when a row is clicked
56936 * @param {Grid} this
56937 * @param {Number} rowIndex
56938 * @param {Roo.EventObject} e
56942 * @event rowdblclick
56943 * Fires when a row is double clicked
56944 * @param {Grid} this
56945 * @param {Number} rowIndex
56946 * @param {Roo.EventObject} e
56948 "rowdblclick" : true,
56950 * @event headerclick
56951 * Fires when a header is clicked
56952 * @param {Grid} this
56953 * @param {Number} columnIndex
56954 * @param {Roo.EventObject} e
56956 "headerclick" : true,
56958 * @event headerdblclick
56959 * Fires when a header cell is double clicked
56960 * @param {Grid} this
56961 * @param {Number} columnIndex
56962 * @param {Roo.EventObject} e
56964 "headerdblclick" : true,
56966 * @event rowcontextmenu
56967 * Fires when a row is right clicked
56968 * @param {Grid} this
56969 * @param {Number} rowIndex
56970 * @param {Roo.EventObject} e
56972 "rowcontextmenu" : true,
56974 * @event cellcontextmenu
56975 * Fires when a cell is right clicked
56976 * @param {Grid} this
56977 * @param {Number} rowIndex
56978 * @param {Number} cellIndex
56979 * @param {Roo.EventObject} e
56981 "cellcontextmenu" : true,
56983 * @event headercontextmenu
56984 * Fires when a header is right clicked
56985 * @param {Grid} this
56986 * @param {Number} columnIndex
56987 * @param {Roo.EventObject} e
56989 "headercontextmenu" : true,
56991 * @event bodyscroll
56992 * Fires when the body element is scrolled
56993 * @param {Number} scrollLeft
56994 * @param {Number} scrollTop
56996 "bodyscroll" : true,
56998 * @event columnresize
56999 * Fires when the user resizes a column
57000 * @param {Number} columnIndex
57001 * @param {Number} newSize
57003 "columnresize" : true,
57005 * @event columnmove
57006 * Fires when the user moves a column
57007 * @param {Number} oldIndex
57008 * @param {Number} newIndex
57010 "columnmove" : true,
57013 * Fires when row(s) start being dragged
57014 * @param {Grid} this
57015 * @param {Roo.GridDD} dd The drag drop object
57016 * @param {event} e The raw browser event
57018 "startdrag" : true,
57021 * Fires when a drag operation is complete
57022 * @param {Grid} this
57023 * @param {Roo.GridDD} dd The drag drop object
57024 * @param {event} e The raw browser event
57029 * Fires when dragged row(s) are dropped on a valid DD target
57030 * @param {Grid} this
57031 * @param {Roo.GridDD} dd The drag drop object
57032 * @param {String} targetId The target drag drop object
57033 * @param {event} e The raw browser event
57038 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57039 * @param {Grid} this
57040 * @param {Roo.GridDD} dd The drag drop object
57041 * @param {String} targetId The target drag drop object
57042 * @param {event} e The raw browser event
57047 * Fires when the dragged row(s) first cross another DD target while being dragged
57048 * @param {Grid} this
57049 * @param {Roo.GridDD} dd The drag drop object
57050 * @param {String} targetId The target drag drop object
57051 * @param {event} e The raw browser event
57053 "dragenter" : true,
57056 * Fires when the dragged row(s) leave another DD target while being dragged
57057 * @param {Grid} this
57058 * @param {Roo.GridDD} dd The drag drop object
57059 * @param {String} targetId The target drag drop object
57060 * @param {event} e The raw browser event
57065 * Fires when a row is rendered, so you can change add a style to it.
57066 * @param {GridView} gridview The grid view
57067 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57073 * Fires when the grid is rendered
57074 * @param {Grid} grid
57079 * Fires when a date is selected
57080 * @param {DatePicker} this
57081 * @param {Date} date The selected date
57085 * @event monthchange
57086 * Fires when the displayed month changes
57087 * @param {DatePicker} this
57088 * @param {Date} date The selected month
57090 'monthchange': true,
57092 * @event evententer
57093 * Fires when mouse over an event
57094 * @param {Calendar} this
57095 * @param {event} Event
57097 'evententer': true,
57099 * @event eventleave
57100 * Fires when the mouse leaves an
57101 * @param {Calendar} this
57104 'eventleave': true,
57106 * @event eventclick
57107 * Fires when the mouse click an
57108 * @param {Calendar} this
57111 'eventclick': true,
57113 * @event eventrender
57114 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57115 * @param {Calendar} this
57116 * @param {data} data to be modified
57118 'eventrender': true
57122 Roo.grid.Grid.superclass.constructor.call(this);
57123 this.on('render', function() {
57124 this.view.el.addClass('x-grid-cal');
57126 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57130 if (!Roo.grid.Calendar.style) {
57131 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57134 '.x-grid-cal .x-grid-col' : {
57135 height: 'auto !important',
57136 'vertical-align': 'top'
57138 '.x-grid-cal .fc-event-hori' : {
57149 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57151 * @cfg {Store} eventStore The store that loads events.
57156 activeDate : false,
57159 monitorWindowResize : false,
57162 resizeColumns : function() {
57163 var col = (this.view.el.getWidth() / 7) - 3;
57164 // loop through cols, and setWidth
57165 for(var i =0 ; i < 7 ; i++){
57166 this.cm.setColumnWidth(i, col);
57169 setDate :function(date) {
57171 Roo.log('setDate?');
57173 this.resizeColumns();
57174 var vd = this.activeDate;
57175 this.activeDate = date;
57176 // if(vd && this.el){
57177 // var t = date.getTime();
57178 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57179 // Roo.log('using add remove');
57181 // this.fireEvent('monthchange', this, date);
57183 // this.cells.removeClass("fc-state-highlight");
57184 // this.cells.each(function(c){
57185 // if(c.dateValue == t){
57186 // c.addClass("fc-state-highlight");
57187 // setTimeout(function(){
57188 // try{c.dom.firstChild.focus();}catch(e){}
57198 var days = date.getDaysInMonth();
57200 var firstOfMonth = date.getFirstDateOfMonth();
57201 var startingPos = firstOfMonth.getDay()-this.startDay;
57203 if(startingPos < this.startDay){
57207 var pm = date.add(Date.MONTH, -1);
57208 var prevStart = pm.getDaysInMonth()-startingPos;
57212 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57214 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57215 //this.cells.addClassOnOver('fc-state-hover');
57217 var cells = this.cells.elements;
57218 var textEls = this.textNodes;
57220 //Roo.each(cells, function(cell){
57221 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57224 days += startingPos;
57226 // convert everything to numbers so it's fast
57227 var day = 86400000;
57228 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57231 //Roo.log(prevStart);
57233 var today = new Date().clearTime().getTime();
57234 var sel = date.clearTime().getTime();
57235 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57236 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57237 var ddMatch = this.disabledDatesRE;
57238 var ddText = this.disabledDatesText;
57239 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57240 var ddaysText = this.disabledDaysText;
57241 var format = this.format;
57243 var setCellClass = function(cal, cell){
57245 //Roo.log('set Cell Class');
57247 var t = d.getTime();
57252 cell.dateValue = t;
57254 cell.className += " fc-today";
57255 cell.className += " fc-state-highlight";
57256 cell.title = cal.todayText;
57259 // disable highlight in other month..
57260 cell.className += " fc-state-highlight";
57265 //cell.className = " fc-state-disabled";
57266 cell.title = cal.minText;
57270 //cell.className = " fc-state-disabled";
57271 cell.title = cal.maxText;
57275 if(ddays.indexOf(d.getDay()) != -1){
57276 // cell.title = ddaysText;
57277 // cell.className = " fc-state-disabled";
57280 if(ddMatch && format){
57281 var fvalue = d.dateFormat(format);
57282 if(ddMatch.test(fvalue)){
57283 cell.title = ddText.replace("%0", fvalue);
57284 cell.className = " fc-state-disabled";
57288 if (!cell.initialClassName) {
57289 cell.initialClassName = cell.dom.className;
57292 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57297 for(; i < startingPos; i++) {
57298 cells[i].dayName = (++prevStart);
57299 Roo.log(textEls[i]);
57300 d.setDate(d.getDate()+1);
57302 //cells[i].className = "fc-past fc-other-month";
57303 setCellClass(this, cells[i]);
57308 for(; i < days; i++){
57309 intDay = i - startingPos + 1;
57310 cells[i].dayName = (intDay);
57311 d.setDate(d.getDate()+1);
57313 cells[i].className = ''; // "x-date-active";
57314 setCellClass(this, cells[i]);
57318 for(; i < 42; i++) {
57319 //textEls[i].innerHTML = (++extraDays);
57321 d.setDate(d.getDate()+1);
57322 cells[i].dayName = (++extraDays);
57323 cells[i].className = "fc-future fc-other-month";
57324 setCellClass(this, cells[i]);
57327 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57329 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57331 // this will cause all the cells to mis
57334 for (var r = 0;r < 6;r++) {
57335 for (var c =0;c < 7;c++) {
57336 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57340 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57341 for(i=0;i<cells.length;i++) {
57343 this.cells.elements[i].dayName = cells[i].dayName ;
57344 this.cells.elements[i].className = cells[i].className;
57345 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57346 this.cells.elements[i].title = cells[i].title ;
57347 this.cells.elements[i].dateValue = cells[i].dateValue ;
57353 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57354 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57356 ////if(totalRows != 6){
57357 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57358 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57361 this.fireEvent('monthchange', this, date);
57366 * Returns the grid's SelectionModel.
57367 * @return {SelectionModel}
57369 getSelectionModel : function(){
57370 if(!this.selModel){
57371 this.selModel = new Roo.grid.CellSelectionModel();
57373 return this.selModel;
57377 this.eventStore.load()
57383 findCell : function(dt) {
57384 dt = dt.clearTime().getTime();
57386 this.cells.each(function(c){
57387 //Roo.log("check " +c.dateValue + '?=' + dt);
57388 if(c.dateValue == dt){
57398 findCells : function(rec) {
57399 var s = rec.data.start_dt.clone().clearTime().getTime();
57401 var e= rec.data.end_dt.clone().clearTime().getTime();
57404 this.cells.each(function(c){
57405 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57407 if(c.dateValue > e){
57410 if(c.dateValue < s){
57419 findBestRow: function(cells)
57423 for (var i =0 ; i < cells.length;i++) {
57424 ret = Math.max(cells[i].rows || 0,ret);
57431 addItem : function(rec)
57433 // look for vertical location slot in
57434 var cells = this.findCells(rec);
57436 rec.row = this.findBestRow(cells);
57438 // work out the location.
57442 for(var i =0; i < cells.length; i++) {
57450 if (crow.start.getY() == cells[i].getY()) {
57452 crow.end = cells[i];
57468 for (var i = 0; i < cells.length;i++) {
57469 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57476 clearEvents: function() {
57478 if (!this.eventStore.getCount()) {
57481 // reset number of rows in cells.
57482 Roo.each(this.cells.elements, function(c){
57486 this.eventStore.each(function(e) {
57487 this.clearEvent(e);
57492 clearEvent : function(ev)
57495 Roo.each(ev.els, function(el) {
57496 el.un('mouseenter' ,this.onEventEnter, this);
57497 el.un('mouseleave' ,this.onEventLeave, this);
57505 renderEvent : function(ev,ctr) {
57507 ctr = this.view.el.select('.fc-event-container',true).first();
57511 this.clearEvent(ev);
57517 var cells = ev.cells;
57518 var rows = ev.rows;
57519 this.fireEvent('eventrender', this, ev);
57521 for(var i =0; i < rows.length; i++) {
57525 cls += ' fc-event-start';
57527 if ((i+1) == rows.length) {
57528 cls += ' fc-event-end';
57531 //Roo.log(ev.data);
57532 // how many rows should it span..
57533 var cg = this.eventTmpl.append(ctr,Roo.apply({
57536 }, ev.data) , true);
57539 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57540 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57541 cg.on('click', this.onEventClick, this, ev);
57545 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57546 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57549 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57550 cg.setWidth(ebox.right - sbox.x -2);
57554 renderEvents: function()
57556 // first make sure there is enough space..
57558 if (!this.eventTmpl) {
57559 this.eventTmpl = new Roo.Template(
57560 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57561 '<div class="fc-event-inner">' +
57562 '<span class="fc-event-time">{time}</span>' +
57563 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57565 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57573 this.cells.each(function(c) {
57574 //Roo.log(c.select('.fc-day-content div',true).first());
57575 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57578 var ctr = this.view.el.select('.fc-event-container',true).first();
57581 this.eventStore.each(function(ev){
57583 this.renderEvent(ev);
57587 this.view.layout();
57591 onEventEnter: function (e, el,event,d) {
57592 this.fireEvent('evententer', this, el, event);
57595 onEventLeave: function (e, el,event,d) {
57596 this.fireEvent('eventleave', this, el, event);
57599 onEventClick: function (e, el,event,d) {
57600 this.fireEvent('eventclick', this, el, event);
57603 onMonthChange: function () {
57607 onLoad: function () {
57609 //Roo.log('calendar onload');
57611 if(this.eventStore.getCount() > 0){
57615 this.eventStore.each(function(d){
57620 if (typeof(add.end_dt) == 'undefined') {
57621 Roo.log("Missing End time in calendar data: ");
57625 if (typeof(add.start_dt) == 'undefined') {
57626 Roo.log("Missing Start time in calendar data: ");
57630 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57631 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57632 add.id = add.id || d.id;
57633 add.title = add.title || '??';
57641 this.renderEvents();
57651 render : function ()
57655 if (!this.view.el.hasClass('course-timesheet')) {
57656 this.view.el.addClass('course-timesheet');
57658 if (this.tsStyle) {
57663 Roo.log(_this.grid.view.el.getWidth());
57666 this.tsStyle = Roo.util.CSS.createStyleSheet({
57667 '.course-timesheet .x-grid-row' : {
57670 '.x-grid-row td' : {
57671 'vertical-align' : 0
57673 '.course-edit-link' : {
57675 'text-overflow' : 'ellipsis',
57676 'overflow' : 'hidden',
57677 'white-space' : 'nowrap',
57678 'cursor' : 'pointer'
57683 '.de-act-sup-link' : {
57684 'color' : 'purple',
57685 'text-decoration' : 'line-through'
57689 'text-decoration' : 'line-through'
57691 '.course-timesheet .course-highlight' : {
57692 'border-top-style': 'dashed !important',
57693 'border-bottom-bottom': 'dashed !important'
57695 '.course-timesheet .course-item' : {
57696 'font-family' : 'tahoma, arial, helvetica',
57697 'font-size' : '11px',
57698 'overflow' : 'hidden',
57699 'padding-left' : '10px',
57700 'padding-right' : '10px',
57701 'padding-top' : '10px'
57709 monitorWindowResize : false,
57710 cellrenderer : function(v,x,r)
57715 xtype: 'CellSelectionModel',
57722 beforeload : function (_self, options)
57724 options.params = options.params || {};
57725 options.params._month = _this.monthField.getValue();
57726 options.params.limit = 9999;
57727 options.params['sort'] = 'when_dt';
57728 options.params['dir'] = 'ASC';
57729 this.proxy.loadResponse = this.loadResponse;
57731 //this.addColumns();
57733 load : function (_self, records, options)
57735 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57736 // if you click on the translation.. you can edit it...
57737 var el = Roo.get(this);
57738 var id = el.dom.getAttribute('data-id');
57739 var d = el.dom.getAttribute('data-date');
57740 var t = el.dom.getAttribute('data-time');
57741 //var id = this.child('span').dom.textContent;
57744 Pman.Dialog.CourseCalendar.show({
57748 productitem_active : id ? 1 : 0
57750 _this.grid.ds.load({});
57755 _this.panel.fireEvent('resize', [ '', '' ]);
57758 loadResponse : function(o, success, response){
57759 // this is overridden on before load..
57761 Roo.log("our code?");
57762 //Roo.log(success);
57763 //Roo.log(response)
57764 delete this.activeRequest;
57766 this.fireEvent("loadexception", this, o, response);
57767 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57772 result = o.reader.read(response);
57774 Roo.log("load exception?");
57775 this.fireEvent("loadexception", this, o, response, e);
57776 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57779 Roo.log("ready...");
57780 // loop through result.records;
57781 // and set this.tdate[date] = [] << array of records..
57783 Roo.each(result.records, function(r){
57785 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57786 _this.tdata[r.data.when_dt.format('j')] = [];
57788 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57791 //Roo.log(_this.tdata);
57793 result.records = [];
57794 result.totalRecords = 6;
57796 // let's generate some duumy records for the rows.
57797 //var st = _this.dateField.getValue();
57799 // work out monday..
57800 //st = st.add(Date.DAY, -1 * st.format('w'));
57802 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57804 var firstOfMonth = date.getFirstDayOfMonth();
57805 var days = date.getDaysInMonth();
57807 var firstAdded = false;
57808 for (var i = 0; i < result.totalRecords ; i++) {
57809 //var d= st.add(Date.DAY, i);
57812 for(var w = 0 ; w < 7 ; w++){
57813 if(!firstAdded && firstOfMonth != w){
57820 var dd = (d > 0 && d < 10) ? "0"+d : d;
57821 row['weekday'+w] = String.format(
57822 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57823 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57825 date.format('Y-m-')+dd
57828 if(typeof(_this.tdata[d]) != 'undefined'){
57829 Roo.each(_this.tdata[d], function(r){
57833 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57834 if(r.parent_id*1>0){
57835 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57838 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57839 deactive = 'de-act-link';
57842 row['weekday'+w] += String.format(
57843 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57845 r.product_id_name, //1
57846 r.when_dt.format('h:ia'), //2
57856 // only do this if something added..
57858 result.records.push(_this.grid.dataSource.reader.newRow(row));
57862 // push it twice. (second one with an hour..
57866 this.fireEvent("load", this, o, o.request.arg);
57867 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57869 sortInfo : {field: 'when_dt', direction : 'ASC' },
57871 xtype: 'HttpProxy',
57874 url : baseURL + '/Roo/Shop_course.php'
57877 xtype: 'JsonReader',
57894 'name': 'parent_id',
57898 'name': 'product_id',
57902 'name': 'productitem_id',
57920 click : function (_self, e)
57922 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57923 sd.setMonth(sd.getMonth()-1);
57924 _this.monthField.setValue(sd.format('Y-m-d'));
57925 _this.grid.ds.load({});
57931 xtype: 'Separator',
57935 xtype: 'MonthField',
57938 render : function (_self)
57940 _this.monthField = _self;
57941 // _this.monthField.set today
57943 select : function (combo, date)
57945 _this.grid.ds.load({});
57948 value : (function() { return new Date(); })()
57951 xtype: 'Separator',
57957 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57967 click : function (_self, e)
57969 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57970 sd.setMonth(sd.getMonth()+1);
57971 _this.monthField.setValue(sd.format('Y-m-d'));
57972 _this.grid.ds.load({});
57985 * Ext JS Library 1.1.1
57986 * Copyright(c) 2006-2007, Ext JS, LLC.
57988 * Originally Released Under LGPL - original licence link has changed is not relivant.
57991 * <script type="text/javascript">
57995 * @class Roo.LoadMask
57996 * A simple utility class for generically masking elements while loading data. If the element being masked has
57997 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57998 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57999 * element's UpdateManager load indicator and will be destroyed after the initial load.
58001 * Create a new LoadMask
58002 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58003 * @param {Object} config The config object
58005 Roo.LoadMask = function(el, config){
58006 this.el = Roo.get(el);
58007 Roo.apply(this, config);
58009 this.store.on('beforeload', this.onBeforeLoad, this);
58010 this.store.on('load', this.onLoad, this);
58011 this.store.on('loadexception', this.onLoadException, this);
58012 this.removeMask = false;
58014 var um = this.el.getUpdateManager();
58015 um.showLoadIndicator = false; // disable the default indicator
58016 um.on('beforeupdate', this.onBeforeLoad, this);
58017 um.on('update', this.onLoad, this);
58018 um.on('failure', this.onLoad, this);
58019 this.removeMask = true;
58023 Roo.LoadMask.prototype = {
58025 * @cfg {Boolean} removeMask
58026 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58027 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58030 * @cfg {String} msg
58031 * The text to display in a centered loading message box (defaults to 'Loading...')
58033 msg : 'Loading...',
58035 * @cfg {String} msgCls
58036 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58038 msgCls : 'x-mask-loading',
58041 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58047 * Disables the mask to prevent it from being displayed
58049 disable : function(){
58050 this.disabled = true;
58054 * Enables the mask so that it can be displayed
58056 enable : function(){
58057 this.disabled = false;
58060 onLoadException : function()
58062 Roo.log(arguments);
58064 if (typeof(arguments[3]) != 'undefined') {
58065 Roo.MessageBox.alert("Error loading",arguments[3]);
58069 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58070 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58079 this.el.unmask(this.removeMask);
58082 onLoad : function()
58084 this.el.unmask(this.removeMask);
58088 onBeforeLoad : function(){
58089 if(!this.disabled){
58090 this.el.mask(this.msg, this.msgCls);
58095 destroy : function(){
58097 this.store.un('beforeload', this.onBeforeLoad, this);
58098 this.store.un('load', this.onLoad, this);
58099 this.store.un('loadexception', this.onLoadException, this);
58101 var um = this.el.getUpdateManager();
58102 um.un('beforeupdate', this.onBeforeLoad, this);
58103 um.un('update', this.onLoad, this);
58104 um.un('failure', this.onLoad, this);
58109 * Ext JS Library 1.1.1
58110 * Copyright(c) 2006-2007, Ext JS, LLC.
58112 * Originally Released Under LGPL - original licence link has changed is not relivant.
58115 * <script type="text/javascript">
58120 * @class Roo.XTemplate
58121 * @extends Roo.Template
58122 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58124 var t = new Roo.XTemplate(
58125 '<select name="{name}">',
58126 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58130 // then append, applying the master template values
58133 * Supported features:
58138 {a_variable} - output encoded.
58139 {a_variable.format:("Y-m-d")} - call a method on the variable
58140 {a_variable:raw} - unencoded output
58141 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58142 {a_variable:this.method_on_template(...)} - call a method on the template object.
58147 <tpl for="a_variable or condition.."></tpl>
58148 <tpl if="a_variable or condition"></tpl>
58149 <tpl exec="some javascript"></tpl>
58150 <tpl name="named_template"></tpl> (experimental)
58152 <tpl for="."></tpl> - just iterate the property..
58153 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58157 Roo.XTemplate = function()
58159 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58166 Roo.extend(Roo.XTemplate, Roo.Template, {
58169 * The various sub templates
58174 * basic tag replacing syntax
58177 * // you can fake an object call by doing this
58181 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58184 * compile the template
58186 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58189 compile: function()
58193 s = ['<tpl>', s, '</tpl>'].join('');
58195 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58196 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58197 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58198 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58199 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58204 while(true == !!(m = s.match(re))){
58205 var forMatch = m[0].match(nameRe),
58206 ifMatch = m[0].match(ifRe),
58207 execMatch = m[0].match(execRe),
58208 namedMatch = m[0].match(namedRe),
58213 name = forMatch && forMatch[1] ? forMatch[1] : '';
58216 // if - puts fn into test..
58217 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58219 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58224 // exec - calls a function... returns empty if true is returned.
58225 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58227 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58235 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58236 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58237 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58240 var uid = namedMatch ? namedMatch[1] : id;
58244 id: namedMatch ? namedMatch[1] : id,
58251 s = s.replace(m[0], '');
58253 s = s.replace(m[0], '{xtpl'+ id + '}');
58258 for(var i = tpls.length-1; i >= 0; --i){
58259 this.compileTpl(tpls[i]);
58260 this.tpls[tpls[i].id] = tpls[i];
58262 this.master = tpls[tpls.length-1];
58266 * same as applyTemplate, except it's done to one of the subTemplates
58267 * when using named templates, you can do:
58269 * var str = pl.applySubTemplate('your-name', values);
58272 * @param {Number} id of the template
58273 * @param {Object} values to apply to template
58274 * @param {Object} parent (normaly the instance of this object)
58276 applySubTemplate : function(id, values, parent)
58280 var t = this.tpls[id];
58284 if(t.test && !t.test.call(this, values, parent)){
58288 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58289 Roo.log(e.toString());
58295 if(t.exec && t.exec.call(this, values, parent)){
58299 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58300 Roo.log(e.toString());
58305 var vs = t.target ? t.target.call(this, values, parent) : values;
58306 parent = t.target ? values : parent;
58307 if(t.target && vs instanceof Array){
58309 for(var i = 0, len = vs.length; i < len; i++){
58310 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58312 return buf.join('');
58314 return t.compiled.call(this, vs, parent);
58316 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58317 Roo.log(e.toString());
58318 Roo.log(t.compiled);
58323 compileTpl : function(tpl)
58325 var fm = Roo.util.Format;
58326 var useF = this.disableFormats !== true;
58327 var sep = Roo.isGecko ? "+" : ",";
58328 var undef = function(str) {
58329 Roo.log("Property not found :" + str);
58333 var fn = function(m, name, format, args)
58335 //Roo.log(arguments);
58336 args = args ? args.replace(/\\'/g,"'") : args;
58337 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58338 if (typeof(format) == 'undefined') {
58339 format= 'htmlEncode';
58341 if (format == 'raw' ) {
58345 if(name.substr(0, 4) == 'xtpl'){
58346 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58349 // build an array of options to determine if value is undefined..
58351 // basically get 'xxxx.yyyy' then do
58352 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58353 // (function () { Roo.log("Property not found"); return ''; })() :
58358 Roo.each(name.split('.'), function(st) {
58359 lookfor += (lookfor.length ? '.': '') + st;
58360 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58363 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58366 if(format && useF){
58368 args = args ? ',' + args : "";
58370 if(format.substr(0, 5) != "this."){
58371 format = "fm." + format + '(';
58373 format = 'this.call("'+ format.substr(5) + '", ';
58377 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58381 // called with xxyx.yuu:(test,test)
58383 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58385 // raw.. - :raw modifier..
58386 return "'"+ sep + udef_st + name + ")"+sep+"'";
58390 // branched to use + in gecko and [].join() in others
58392 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58393 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58396 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58397 body.push(tpl.body.replace(/(\r\n|\n)/g,
58398 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58399 body.push("'].join('');};};");
58400 body = body.join('');
58403 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58405 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58411 applyTemplate : function(values){
58412 return this.master.compiled.call(this, values, {});
58413 //var s = this.subs;
58416 apply : function(){
58417 return this.applyTemplate.apply(this, arguments);
58422 Roo.XTemplate.from = function(el){
58423 el = Roo.getDom(el);
58424 return new Roo.XTemplate(el.value || el.innerHTML);