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 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1241 + "if (results && results.length > 0) {";
1244 var special = false;
1246 for (var i = 0; i < format.length; ++i) {
1247 ch = format.charAt(i);
1248 if (!special && ch == "\\") {
1253 regex += String.escape(ch);
1256 var obj = Date.formatCodeToRegex(ch, currentGroup);
1257 currentGroup += obj.g;
1259 if (obj.g && obj.c) {
1265 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1266 + "{v = new Date(y, m, d, h, i, s);}\n"
1267 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1268 + "{v = new Date(y, m, d, h, i);}\n"
1269 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1270 + "{v = new Date(y, m, d, h);}\n"
1271 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1272 + "{v = new Date(y, m, d);}\n"
1273 + "else if (y >= 0 && m >= 0)\n"
1274 + "{v = new Date(y, m);}\n"
1275 + "else if (y >= 0)\n"
1276 + "{v = new Date(y);}\n"
1277 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1278 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1279 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1282 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1283 /** eval:var:zzzzzzzzzzzzz */
1288 Date.formatCodeToRegex = function(character, currentGroup) {
1289 switch (character) {
1293 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1296 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1297 s:"(\\d{1,2})"}; // day of month without leading zeroes
1300 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1301 s:"(\\d{2})"}; // day of month with leading zeroes
1305 s:"(?:" + Date.dayNames.join("|") + ")"};
1309 s:"(?:st|nd|rd|th)"};
1324 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1325 s:"(" + Date.monthNames.join("|") + ")"};
1328 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1329 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1332 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1333 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1336 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1337 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1348 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1352 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1353 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1357 c:"if (results[" + currentGroup + "] == 'am') {\n"
1358 + "if (h == 12) { h = 0; }\n"
1359 + "} else { if (h < 12) { h += 12; }}",
1363 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1364 + "if (h == 12) { h = 0; }\n"
1365 + "} else { if (h < 12) { h += 12; }}",
1370 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1375 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1376 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1379 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1383 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1388 "o = results[", currentGroup, "];\n",
1389 "var sn = o.substring(0,1);\n", // get + / - sign
1390 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1391 "var mn = o.substring(3,5) % 60;\n", // get minutes
1392 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1393 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1395 s:"([+\-]\\d{2,4})"};
1401 "o = results[", currentGroup, "];\n",
1402 "var sn = o.substring(0,1);\n",
1403 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1404 "var mn = o.substring(4,6) % 60;\n",
1405 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1406 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1412 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1415 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1416 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1417 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1421 s:String.escape(character)};
1426 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1427 * @return {String} The abbreviated timezone name (e.g. 'CST')
1429 Date.prototype.getTimezone = function() {
1430 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1434 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1435 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1437 Date.prototype.getGMTOffset = function() {
1438 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1439 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1440 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1444 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1445 * @return {String} 2-characters representing hours and 2-characters representing minutes
1446 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1448 Date.prototype.getGMTColonOffset = function() {
1449 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1450 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1452 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1456 * Get the numeric day number of the year, adjusted for leap year.
1457 * @return {Number} 0 through 364 (365 in leap years)
1459 Date.prototype.getDayOfYear = function() {
1461 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1462 for (var i = 0; i < this.getMonth(); ++i) {
1463 num += Date.daysInMonth[i];
1465 return num + this.getDate() - 1;
1469 * Get the string representation of the numeric week number of the year
1470 * (equivalent to the format specifier 'W').
1471 * @return {String} '00' through '52'
1473 Date.prototype.getWeekOfYear = function() {
1474 // Skip to Thursday of this week
1475 var now = this.getDayOfYear() + (4 - this.getDay());
1476 // Find the first Thursday of the year
1477 var jan1 = new Date(this.getFullYear(), 0, 1);
1478 var then = (7 - jan1.getDay() + 4);
1479 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1483 * Whether or not the current date is in a leap year.
1484 * @return {Boolean} True if the current date is in a leap year, else false
1486 Date.prototype.isLeapYear = function() {
1487 var year = this.getFullYear();
1488 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1492 * Get the first day of the current month, adjusted for leap year. The returned value
1493 * is the numeric day index within the week (0-6) which can be used in conjunction with
1494 * the {@link #monthNames} array to retrieve the textual day name.
1497 var dt = new Date('1/10/2007');
1498 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1500 * @return {Number} The day number (0-6)
1502 Date.prototype.getFirstDayOfMonth = function() {
1503 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1504 return (day < 0) ? (day + 7) : day;
1508 * Get the last day of the current month, adjusted for leap year. The returned value
1509 * is the numeric day index within the week (0-6) which can be used in conjunction with
1510 * the {@link #monthNames} array to retrieve the textual day name.
1513 var dt = new Date('1/10/2007');
1514 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1516 * @return {Number} The day number (0-6)
1518 Date.prototype.getLastDayOfMonth = function() {
1519 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1520 return (day < 0) ? (day + 7) : day;
1525 * Get the first date of this date's month
1528 Date.prototype.getFirstDateOfMonth = function() {
1529 return new Date(this.getFullYear(), this.getMonth(), 1);
1533 * Get the last date of this date's month
1536 Date.prototype.getLastDateOfMonth = function() {
1537 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1540 * Get the number of days in the current month, adjusted for leap year.
1541 * @return {Number} The number of days in the month
1543 Date.prototype.getDaysInMonth = function() {
1544 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1545 return Date.daysInMonth[this.getMonth()];
1549 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1550 * @return {String} 'st, 'nd', 'rd' or 'th'
1552 Date.prototype.getSuffix = function() {
1553 switch (this.getDate()) {
1570 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1573 * An array of textual month names.
1574 * Override these values for international dates, for example...
1575 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1594 * An array of textual day names.
1595 * Override these values for international dates, for example...
1596 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1612 Date.monthNumbers = {
1627 * Creates and returns a new Date instance with the exact same date value as the called instance.
1628 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1629 * variable will also be changed. When the intention is to create a new variable that will not
1630 * modify the original instance, you should create a clone.
1632 * Example of correctly cloning a date:
1635 var orig = new Date('10/1/2006');
1638 document.write(orig); //returns 'Thu Oct 05 2006'!
1641 var orig = new Date('10/1/2006');
1642 var copy = orig.clone();
1644 document.write(orig); //returns 'Thu Oct 01 2006'
1646 * @return {Date} The new Date instance
1648 Date.prototype.clone = function() {
1649 return new Date(this.getTime());
1653 * Clears any time information from this date
1654 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1655 @return {Date} this or the clone
1657 Date.prototype.clearTime = function(clone){
1659 return this.clone().clearTime();
1664 this.setMilliseconds(0);
1669 // safari setMonth is broken
1671 Date.brokenSetMonth = Date.prototype.setMonth;
1672 Date.prototype.setMonth = function(num){
1674 var n = Math.ceil(-num);
1675 var back_year = Math.ceil(n/12);
1676 var month = (n % 12) ? 12 - n % 12 : 0 ;
1677 this.setFullYear(this.getFullYear() - back_year);
1678 return Date.brokenSetMonth.call(this, month);
1680 return Date.brokenSetMonth.apply(this, arguments);
1685 /** Date interval constant
1689 /** Date interval constant
1693 /** Date interval constant
1697 /** Date interval constant
1701 /** Date interval constant
1705 /** Date interval constant
1709 /** Date interval constant
1715 * Provides a convenient method of performing basic date arithmetic. This method
1716 * does not modify the Date instance being called - it creates and returns
1717 * a new Date instance containing the resulting date value.
1722 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1723 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1725 //Negative values will subtract correctly:
1726 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1727 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1729 //You can even chain several calls together in one line!
1730 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1731 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1734 * @param {String} interval A valid date interval enum value
1735 * @param {Number} value The amount to add to the current date
1736 * @return {Date} The new Date instance
1738 Date.prototype.add = function(interval, value){
1739 var d = this.clone();
1740 if (!interval || value === 0) return d;
1741 switch(interval.toLowerCase()){
1743 d.setMilliseconds(this.getMilliseconds() + value);
1746 d.setSeconds(this.getSeconds() + value);
1749 d.setMinutes(this.getMinutes() + value);
1752 d.setHours(this.getHours() + value);
1755 d.setDate(this.getDate() + value);
1758 var day = this.getDate();
1760 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1763 d.setMonth(this.getMonth() + value);
1766 d.setFullYear(this.getFullYear() + value);
1773 * Ext JS Library 1.1.1
1774 * Copyright(c) 2006-2007, Ext JS, LLC.
1776 * Originally Released Under LGPL - original licence link has changed is not relivant.
1779 * <script type="text/javascript">
1783 * @class Roo.lib.Dom
1786 * Dom utils (from YIU afaik)
1791 * Get the view width
1792 * @param {Boolean} full True will get the full document, otherwise it's the view width
1793 * @return {Number} The width
1796 getViewWidth : function(full) {
1797 return full ? this.getDocumentWidth() : this.getViewportWidth();
1800 * Get the view height
1801 * @param {Boolean} full True will get the full document, otherwise it's the view height
1802 * @return {Number} The height
1804 getViewHeight : function(full) {
1805 return full ? this.getDocumentHeight() : this.getViewportHeight();
1808 getDocumentHeight: function() {
1809 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1810 return Math.max(scrollHeight, this.getViewportHeight());
1813 getDocumentWidth: function() {
1814 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1815 return Math.max(scrollWidth, this.getViewportWidth());
1818 getViewportHeight: function() {
1819 var height = self.innerHeight;
1820 var mode = document.compatMode;
1822 if ((mode || Roo.isIE) && !Roo.isOpera) {
1823 height = (mode == "CSS1Compat") ?
1824 document.documentElement.clientHeight :
1825 document.body.clientHeight;
1831 getViewportWidth: function() {
1832 var width = self.innerWidth;
1833 var mode = document.compatMode;
1835 if (mode || Roo.isIE) {
1836 width = (mode == "CSS1Compat") ?
1837 document.documentElement.clientWidth :
1838 document.body.clientWidth;
1843 isAncestor : function(p, c) {
1850 if (p.contains && !Roo.isSafari) {
1851 return p.contains(c);
1852 } else if (p.compareDocumentPosition) {
1853 return !!(p.compareDocumentPosition(c) & 16);
1855 var parent = c.parentNode;
1860 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1863 parent = parent.parentNode;
1869 getRegion : function(el) {
1870 return Roo.lib.Region.getRegion(el);
1873 getY : function(el) {
1874 return this.getXY(el)[1];
1877 getX : function(el) {
1878 return this.getXY(el)[0];
1881 getXY : function(el) {
1882 var p, pe, b, scroll, bd = document.body;
1883 el = Roo.getDom(el);
1884 var fly = Roo.lib.AnimBase.fly;
1885 if (el.getBoundingClientRect) {
1886 b = el.getBoundingClientRect();
1887 scroll = fly(document).getScroll();
1888 return [b.left + scroll.left, b.top + scroll.top];
1894 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1901 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1908 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1909 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1916 if (p != el && pe.getStyle('overflow') != 'visible') {
1924 if (Roo.isSafari && hasAbsolute) {
1929 if (Roo.isGecko && !hasAbsolute) {
1931 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1932 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1936 while (p && p != bd) {
1937 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1949 setXY : function(el, xy) {
1950 el = Roo.fly(el, '_setXY');
1952 var pts = el.translatePoints(xy);
1953 if (xy[0] !== false) {
1954 el.dom.style.left = pts.left + "px";
1956 if (xy[1] !== false) {
1957 el.dom.style.top = pts.top + "px";
1961 setX : function(el, x) {
1962 this.setXY(el, [x, false]);
1965 setY : function(el, y) {
1966 this.setXY(el, [false, y]);
1970 * Portions of this file are based on pieces of Yahoo User Interface Library
1971 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1972 * YUI licensed under the BSD License:
1973 * http://developer.yahoo.net/yui/license.txt
1974 * <script type="text/javascript">
1978 Roo.lib.Event = function() {
1979 var loadComplete = false;
1981 var unloadListeners = [];
1983 var onAvailStack = [];
1985 var lastError = null;
1998 startInterval: function() {
1999 if (!this._interval) {
2001 var callback = function() {
2002 self._tryPreloadAttach();
2004 this._interval = setInterval(callback, this.POLL_INTERVAL);
2009 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2010 onAvailStack.push({ id: p_id,
2013 override: p_override,
2014 checkReady: false });
2016 retryCount = this.POLL_RETRYS;
2017 this.startInterval();
2021 addListener: function(el, eventName, fn) {
2022 el = Roo.getDom(el);
2027 if ("unload" == eventName) {
2028 unloadListeners[unloadListeners.length] =
2029 [el, eventName, fn];
2033 var wrappedFn = function(e) {
2034 return fn(Roo.lib.Event.getEvent(e));
2037 var li = [el, eventName, fn, wrappedFn];
2039 var index = listeners.length;
2040 listeners[index] = li;
2042 this.doAdd(el, eventName, wrappedFn, false);
2048 removeListener: function(el, eventName, fn) {
2051 el = Roo.getDom(el);
2054 return this.purgeElement(el, false, eventName);
2058 if ("unload" == eventName) {
2060 for (i = 0,len = unloadListeners.length; i < len; i++) {
2061 var li = unloadListeners[i];
2064 li[1] == eventName &&
2066 unloadListeners.splice(i, 1);
2074 var cacheItem = null;
2077 var index = arguments[3];
2079 if ("undefined" == typeof index) {
2080 index = this._getCacheIndex(el, eventName, fn);
2084 cacheItem = listeners[index];
2087 if (!el || !cacheItem) {
2091 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2093 delete listeners[index][this.WFN];
2094 delete listeners[index][this.FN];
2095 listeners.splice(index, 1);
2102 getTarget: function(ev, resolveTextNode) {
2103 ev = ev.browserEvent || ev;
2104 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2105 var t = ev.target || ev.srcElement;
2106 return this.resolveTextNode(t);
2110 resolveTextNode: function(node) {
2111 if (Roo.isSafari && node && 3 == node.nodeType) {
2112 return node.parentNode;
2119 getPageX: function(ev) {
2120 ev = ev.browserEvent || ev;
2121 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2123 if (!x && 0 !== x) {
2124 x = ev.clientX || 0;
2127 x += this.getScroll()[1];
2135 getPageY: function(ev) {
2136 ev = ev.browserEvent || ev;
2137 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2139 if (!y && 0 !== y) {
2140 y = ev.clientY || 0;
2143 y += this.getScroll()[0];
2152 getXY: function(ev) {
2153 ev = ev.browserEvent || ev;
2154 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2155 return [this.getPageX(ev), this.getPageY(ev)];
2159 getRelatedTarget: function(ev) {
2160 ev = ev.browserEvent || ev;
2161 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2162 var t = ev.relatedTarget;
2164 if (ev.type == "mouseout") {
2166 } else if (ev.type == "mouseover") {
2171 return this.resolveTextNode(t);
2175 getTime: function(ev) {
2176 ev = ev.browserEvent || ev;
2177 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2179 var t = new Date().getTime();
2183 this.lastError = ex;
2192 stopEvent: function(ev) {
2193 this.stopPropagation(ev);
2194 this.preventDefault(ev);
2198 stopPropagation: function(ev) {
2199 ev = ev.browserEvent || ev;
2200 if (ev.stopPropagation) {
2201 ev.stopPropagation();
2203 ev.cancelBubble = true;
2208 preventDefault: function(ev) {
2209 ev = ev.browserEvent || ev;
2210 if(ev.preventDefault) {
2211 ev.preventDefault();
2213 ev.returnValue = false;
2218 getEvent: function(e) {
2219 var ev = e || window.event;
2221 var c = this.getEvent.caller;
2223 ev = c.arguments[0];
2224 if (ev && Event == ev.constructor) {
2234 getCharCode: function(ev) {
2235 ev = ev.browserEvent || ev;
2236 return ev.charCode || ev.keyCode || 0;
2240 _getCacheIndex: function(el, eventName, fn) {
2241 for (var i = 0,len = listeners.length; i < len; ++i) {
2242 var li = listeners[i];
2244 li[this.FN] == fn &&
2245 li[this.EL] == el &&
2246 li[this.TYPE] == eventName) {
2258 getEl: function(id) {
2259 return document.getElementById(id);
2263 clearCache: function() {
2267 _load: function(e) {
2268 loadComplete = true;
2269 var EU = Roo.lib.Event;
2273 EU.doRemove(window, "load", EU._load);
2278 _tryPreloadAttach: function() {
2287 var tryAgain = !loadComplete;
2289 tryAgain = (retryCount > 0);
2294 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2295 var item = onAvailStack[i];
2297 var el = this.getEl(item.id);
2300 if (!item.checkReady ||
2303 (document && document.body)) {
2306 if (item.override) {
2307 if (item.override === true) {
2310 scope = item.override;
2313 item.fn.call(scope, item.obj);
2314 onAvailStack[i] = null;
2317 notAvail.push(item);
2322 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2326 this.startInterval();
2328 clearInterval(this._interval);
2329 this._interval = null;
2332 this.locked = false;
2339 purgeElement: function(el, recurse, eventName) {
2340 var elListeners = this.getListeners(el, eventName);
2342 for (var i = 0,len = elListeners.length; i < len; ++i) {
2343 var l = elListeners[i];
2344 this.removeListener(el, l.type, l.fn);
2348 if (recurse && el && el.childNodes) {
2349 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2350 this.purgeElement(el.childNodes[i], recurse, eventName);
2356 getListeners: function(el, eventName) {
2357 var results = [], searchLists;
2359 searchLists = [listeners, unloadListeners];
2360 } else if (eventName == "unload") {
2361 searchLists = [unloadListeners];
2363 searchLists = [listeners];
2366 for (var j = 0; j < searchLists.length; ++j) {
2367 var searchList = searchLists[j];
2368 if (searchList && searchList.length > 0) {
2369 for (var i = 0,len = searchList.length; i < len; ++i) {
2370 var l = searchList[i];
2371 if (l && l[this.EL] === el &&
2372 (!eventName || eventName === l[this.TYPE])) {
2377 adjust: l[this.ADJ_SCOPE],
2385 return (results.length) ? results : null;
2389 _unload: function(e) {
2391 var EU = Roo.lib.Event, i, j, l, len, index;
2393 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2394 l = unloadListeners[i];
2397 if (l[EU.ADJ_SCOPE]) {
2398 if (l[EU.ADJ_SCOPE] === true) {
2401 scope = l[EU.ADJ_SCOPE];
2404 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2405 unloadListeners[i] = null;
2411 unloadListeners = null;
2413 if (listeners && listeners.length > 0) {
2414 j = listeners.length;
2417 l = listeners[index];
2419 EU.removeListener(l[EU.EL], l[EU.TYPE],
2429 EU.doRemove(window, "unload", EU._unload);
2434 getScroll: function() {
2435 var dd = document.documentElement, db = document.body;
2436 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2437 return [dd.scrollTop, dd.scrollLeft];
2439 return [db.scrollTop, db.scrollLeft];
2446 doAdd: function () {
2447 if (window.addEventListener) {
2448 return function(el, eventName, fn, capture) {
2449 el.addEventListener(eventName, fn, (capture));
2451 } else if (window.attachEvent) {
2452 return function(el, eventName, fn, capture) {
2453 el.attachEvent("on" + eventName, fn);
2462 doRemove: function() {
2463 if (window.removeEventListener) {
2464 return function (el, eventName, fn, capture) {
2465 el.removeEventListener(eventName, fn, (capture));
2467 } else if (window.detachEvent) {
2468 return function (el, eventName, fn) {
2469 el.detachEvent("on" + eventName, fn);
2481 var E = Roo.lib.Event;
2482 E.on = E.addListener;
2483 E.un = E.removeListener;
2485 if (document && document.body) {
2488 E.doAdd(window, "load", E._load);
2490 E.doAdd(window, "unload", E._unload);
2491 E._tryPreloadAttach();
2495 * Portions of this file are based on pieces of Yahoo User Interface Library
2496 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2497 * YUI licensed under the BSD License:
2498 * http://developer.yahoo.net/yui/license.txt
2499 * <script type="text/javascript">
2505 * @class Roo.lib.Ajax
2512 request : function(method, uri, cb, data, options) {
2514 var hs = options.headers;
2517 if(hs.hasOwnProperty(h)){
2518 this.initHeader(h, hs[h], false);
2522 if(options.xmlData){
2523 this.initHeader('Content-Type', 'text/xml', false);
2525 data = options.xmlData;
2529 return this.asyncRequest(method, uri, cb, data);
2532 serializeForm : function(form) {
2533 if(typeof form == 'string') {
2534 form = (document.getElementById(form) || document.forms[form]);
2537 var el, name, val, disabled, data = '', hasSubmit = false;
2538 for (var i = 0; i < form.elements.length; i++) {
2539 el = form.elements[i];
2540 disabled = form.elements[i].disabled;
2541 name = form.elements[i].name;
2542 val = form.elements[i].value;
2544 if (!disabled && name){
2548 case 'select-multiple':
2549 for (var j = 0; j < el.options.length; j++) {
2550 if (el.options[j].selected) {
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2555 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2563 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2576 if(hasSubmit == false) {
2577 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2582 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2587 data = data.substr(0, data.length - 1);
2595 useDefaultHeader:true,
2597 defaultPostHeader:'application/x-www-form-urlencoded',
2599 useDefaultXhrHeader:true,
2601 defaultXhrHeader:'XMLHttpRequest',
2603 hasDefaultHeaders:true,
2615 setProgId:function(id)
2617 this.activeX.unshift(id);
2620 setDefaultPostHeader:function(b)
2622 this.useDefaultHeader = b;
2625 setDefaultXhrHeader:function(b)
2627 this.useDefaultXhrHeader = b;
2630 setPollingInterval:function(i)
2632 if (typeof i == 'number' && isFinite(i)) {
2633 this.pollInterval = i;
2637 createXhrObject:function(transactionId)
2643 http = new XMLHttpRequest();
2645 obj = { conn:http, tId:transactionId };
2649 for (var i = 0; i < this.activeX.length; ++i) {
2653 http = new ActiveXObject(this.activeX[i]);
2655 obj = { conn:http, tId:transactionId };
2668 getConnectionObject:function()
2671 var tId = this.transactionId;
2675 o = this.createXhrObject(tId);
2677 this.transactionId++;
2688 asyncRequest:function(method, uri, callback, postData)
2690 var o = this.getConnectionObject();
2696 o.conn.open(method, uri, true);
2698 if (this.useDefaultXhrHeader) {
2699 if (!this.defaultHeaders['X-Requested-With']) {
2700 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2704 if(postData && this.useDefaultHeader){
2705 this.initHeader('Content-Type', this.defaultPostHeader);
2708 if (this.hasDefaultHeaders || this.hasHeaders) {
2712 this.handleReadyState(o, callback);
2713 o.conn.send(postData || null);
2719 handleReadyState:function(o, callback)
2723 if (callback && callback.timeout) {
2725 this.timeout[o.tId] = window.setTimeout(function() {
2726 oConn.abort(o, callback, true);
2727 }, callback.timeout);
2730 this.poll[o.tId] = window.setInterval(
2732 if (o.conn && o.conn.readyState == 4) {
2733 window.clearInterval(oConn.poll[o.tId]);
2734 delete oConn.poll[o.tId];
2736 if(callback && callback.timeout) {
2737 window.clearTimeout(oConn.timeout[o.tId]);
2738 delete oConn.timeout[o.tId];
2741 oConn.handleTransactionResponse(o, callback);
2744 , this.pollInterval);
2747 handleTransactionResponse:function(o, callback, isAbort)
2751 this.releaseObject(o);
2755 var httpStatus, responseObject;
2759 if (o.conn.status !== undefined && o.conn.status != 0) {
2760 httpStatus = o.conn.status;
2772 if (httpStatus >= 200 && httpStatus < 300) {
2773 responseObject = this.createResponseObject(o, callback.argument);
2774 if (callback.success) {
2775 if (!callback.scope) {
2776 callback.success(responseObject);
2781 callback.success.apply(callback.scope, [responseObject]);
2786 switch (httpStatus) {
2794 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2795 if (callback.failure) {
2796 if (!callback.scope) {
2797 callback.failure(responseObject);
2800 callback.failure.apply(callback.scope, [responseObject]);
2805 responseObject = this.createResponseObject(o, callback.argument);
2806 if (callback.failure) {
2807 if (!callback.scope) {
2808 callback.failure(responseObject);
2811 callback.failure.apply(callback.scope, [responseObject]);
2817 this.releaseObject(o);
2818 responseObject = null;
2821 createResponseObject:function(o, callbackArg)
2828 var headerStr = o.conn.getAllResponseHeaders();
2829 var header = headerStr.split('\n');
2830 for (var i = 0; i < header.length; i++) {
2831 var delimitPos = header[i].indexOf(':');
2832 if (delimitPos != -1) {
2833 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2841 obj.status = o.conn.status;
2842 obj.statusText = o.conn.statusText;
2843 obj.getResponseHeader = headerObj;
2844 obj.getAllResponseHeaders = headerStr;
2845 obj.responseText = o.conn.responseText;
2846 obj.responseXML = o.conn.responseXML;
2848 if (typeof callbackArg !== undefined) {
2849 obj.argument = callbackArg;
2855 createExceptionObject:function(tId, callbackArg, isAbort)
2858 var COMM_ERROR = 'communication failure';
2859 var ABORT_CODE = -1;
2860 var ABORT_ERROR = 'transaction aborted';
2866 obj.status = ABORT_CODE;
2867 obj.statusText = ABORT_ERROR;
2870 obj.status = COMM_CODE;
2871 obj.statusText = COMM_ERROR;
2875 obj.argument = callbackArg;
2881 initHeader:function(label, value, isDefault)
2883 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2885 if (headerObj[label] === undefined) {
2886 headerObj[label] = value;
2891 headerObj[label] = value + "," + headerObj[label];
2895 this.hasDefaultHeaders = true;
2898 this.hasHeaders = true;
2903 setHeader:function(o)
2905 if (this.hasDefaultHeaders) {
2906 for (var prop in this.defaultHeaders) {
2907 if (this.defaultHeaders.hasOwnProperty(prop)) {
2908 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2913 if (this.hasHeaders) {
2914 for (var prop in this.headers) {
2915 if (this.headers.hasOwnProperty(prop)) {
2916 o.conn.setRequestHeader(prop, this.headers[prop]);
2920 this.hasHeaders = false;
2924 resetDefaultHeaders:function() {
2925 delete this.defaultHeaders;
2926 this.defaultHeaders = {};
2927 this.hasDefaultHeaders = false;
2930 abort:function(o, callback, isTimeout)
2932 if(this.isCallInProgress(o)) {
2934 window.clearInterval(this.poll[o.tId]);
2935 delete this.poll[o.tId];
2937 delete this.timeout[o.tId];
2940 this.handleTransactionResponse(o, callback, true);
2950 isCallInProgress:function(o)
2953 return o.conn.readyState != 4 && o.conn.readyState != 0;
2962 releaseObject:function(o)
2971 'MSXML2.XMLHTTP.3.0',
2979 * Portions of this file are based on pieces of Yahoo User Interface Library
2980 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2981 * YUI licensed under the BSD License:
2982 * http://developer.yahoo.net/yui/license.txt
2983 * <script type="text/javascript">
2987 Roo.lib.Region = function(t, r, b, l) {
2997 Roo.lib.Region.prototype = {
2998 contains : function(region) {
2999 return ( region.left >= this.left &&
3000 region.right <= this.right &&
3001 region.top >= this.top &&
3002 region.bottom <= this.bottom );
3006 getArea : function() {
3007 return ( (this.bottom - this.top) * (this.right - this.left) );
3010 intersect : function(region) {
3011 var t = Math.max(this.top, region.top);
3012 var r = Math.min(this.right, region.right);
3013 var b = Math.min(this.bottom, region.bottom);
3014 var l = Math.max(this.left, region.left);
3016 if (b >= t && r >= l) {
3017 return new Roo.lib.Region(t, r, b, l);
3022 union : function(region) {
3023 var t = Math.min(this.top, region.top);
3024 var r = Math.max(this.right, region.right);
3025 var b = Math.max(this.bottom, region.bottom);
3026 var l = Math.min(this.left, region.left);
3028 return new Roo.lib.Region(t, r, b, l);
3031 adjust : function(t, l, b, r) {
3040 Roo.lib.Region.getRegion = function(el) {
3041 var p = Roo.lib.Dom.getXY(el);
3044 var r = p[0] + el.offsetWidth;
3045 var b = p[1] + el.offsetHeight;
3048 return new Roo.lib.Region(t, r, b, l);
3051 * Portions of this file are based on pieces of Yahoo User Interface Library
3052 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3053 * YUI licensed under the BSD License:
3054 * http://developer.yahoo.net/yui/license.txt
3055 * <script type="text/javascript">
3058 //@@dep Roo.lib.Region
3061 Roo.lib.Point = function(x, y) {
3062 if (x instanceof Array) {
3066 this.x = this.right = this.left = this[0] = x;
3067 this.y = this.top = this.bottom = this[1] = y;
3070 Roo.lib.Point.prototype = new Roo.lib.Region();
3072 * Portions of this file are based on pieces of Yahoo User Interface Library
3073 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3074 * YUI licensed under the BSD License:
3075 * http://developer.yahoo.net/yui/license.txt
3076 * <script type="text/javascript">
3083 scroll : function(el, args, duration, easing, cb, scope) {
3084 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3087 motion : function(el, args, duration, easing, cb, scope) {
3088 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3091 color : function(el, args, duration, easing, cb, scope) {
3092 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3095 run : function(el, args, duration, easing, cb, scope, type) {
3096 type = type || Roo.lib.AnimBase;
3097 if (typeof easing == "string") {
3098 easing = Roo.lib.Easing[easing];
3100 var anim = new type(el, args, duration, easing);
3101 anim.animateX(function() {
3102 Roo.callback(cb, scope);
3108 * Portions of this file are based on pieces of Yahoo User Interface Library
3109 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3110 * YUI licensed under the BSD License:
3111 * http://developer.yahoo.net/yui/license.txt
3112 * <script type="text/javascript">
3120 if (!libFlyweight) {
3121 libFlyweight = new Roo.Element.Flyweight();
3123 libFlyweight.dom = el;
3124 return libFlyweight;
3127 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3131 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3133 this.init(el, attributes, duration, method);
3137 Roo.lib.AnimBase.fly = fly;
3141 Roo.lib.AnimBase.prototype = {
3143 toString: function() {
3144 var el = this.getEl();
3145 var id = el.id || el.tagName;
3146 return ("Anim " + id);
3150 noNegatives: /width|height|opacity|padding/i,
3151 offsetAttribute: /^((width|height)|(top|left))$/,
3152 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3153 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3157 doMethod: function(attr, start, end) {
3158 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3162 setAttribute: function(attr, val, unit) {
3163 if (this.patterns.noNegatives.test(attr)) {
3164 val = (val > 0) ? val : 0;
3167 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3171 getAttribute: function(attr) {
3172 var el = this.getEl();
3173 var val = fly(el).getStyle(attr);
3175 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3176 return parseFloat(val);
3179 var a = this.patterns.offsetAttribute.exec(attr) || [];
3180 var pos = !!( a[3] );
3181 var box = !!( a[2] );
3184 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3185 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3194 getDefaultUnit: function(attr) {
3195 if (this.patterns.defaultUnit.test(attr)) {
3202 animateX : function(callback, scope) {
3203 var f = function() {
3204 this.onComplete.removeListener(f);
3205 if (typeof callback == "function") {
3206 callback.call(scope || this, this);
3209 this.onComplete.addListener(f, this);
3214 setRuntimeAttribute: function(attr) {
3217 var attributes = this.attributes;
3219 this.runtimeAttributes[attr] = {};
3221 var isset = function(prop) {
3222 return (typeof prop !== 'undefined');
3225 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3229 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3232 if (isset(attributes[attr]['to'])) {
3233 end = attributes[attr]['to'];
3234 } else if (isset(attributes[attr]['by'])) {
3235 if (start.constructor == Array) {
3237 for (var i = 0, len = start.length; i < len; ++i) {
3238 end[i] = start[i] + attributes[attr]['by'][i];
3241 end = start + attributes[attr]['by'];
3245 this.runtimeAttributes[attr].start = start;
3246 this.runtimeAttributes[attr].end = end;
3249 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3253 init: function(el, attributes, duration, method) {
3255 var isAnimated = false;
3258 var startTime = null;
3261 var actualFrames = 0;
3264 el = Roo.getDom(el);
3267 this.attributes = attributes || {};
3270 this.duration = duration || 1;
3273 this.method = method || Roo.lib.Easing.easeNone;
3276 this.useSeconds = true;
3279 this.currentFrame = 0;
3282 this.totalFrames = Roo.lib.AnimMgr.fps;
3285 this.getEl = function() {
3290 this.isAnimated = function() {
3295 this.getStartTime = function() {
3299 this.runtimeAttributes = {};
3302 this.animate = function() {
3303 if (this.isAnimated()) {
3307 this.currentFrame = 0;
3309 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3311 Roo.lib.AnimMgr.registerElement(this);
3315 this.stop = function(finish) {
3317 this.currentFrame = this.totalFrames;
3318 this._onTween.fire();
3320 Roo.lib.AnimMgr.stop(this);
3323 var onStart = function() {
3324 this.onStart.fire();
3326 this.runtimeAttributes = {};
3327 for (var attr in this.attributes) {
3328 this.setRuntimeAttribute(attr);
3333 startTime = new Date();
3337 var onTween = function() {
3339 duration: new Date() - this.getStartTime(),
3340 currentFrame: this.currentFrame
3343 data.toString = function() {
3345 'duration: ' + data.duration +
3346 ', currentFrame: ' + data.currentFrame
3350 this.onTween.fire(data);
3352 var runtimeAttributes = this.runtimeAttributes;
3354 for (var attr in runtimeAttributes) {
3355 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3361 var onComplete = function() {
3362 var actual_duration = (new Date() - startTime) / 1000 ;
3365 duration: actual_duration,
3366 frames: actualFrames,
3367 fps: actualFrames / actual_duration
3370 data.toString = function() {
3372 'duration: ' + data.duration +
3373 ', frames: ' + data.frames +
3374 ', fps: ' + data.fps
3380 this.onComplete.fire(data);
3384 this._onStart = new Roo.util.Event(this);
3385 this.onStart = new Roo.util.Event(this);
3386 this.onTween = new Roo.util.Event(this);
3387 this._onTween = new Roo.util.Event(this);
3388 this.onComplete = new Roo.util.Event(this);
3389 this._onComplete = new Roo.util.Event(this);
3390 this._onStart.addListener(onStart);
3391 this._onTween.addListener(onTween);
3392 this._onComplete.addListener(onComplete);
3397 * Portions of this file are based on pieces of Yahoo User Interface Library
3398 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3399 * YUI licensed under the BSD License:
3400 * http://developer.yahoo.net/yui/license.txt
3401 * <script type="text/javascript">
3405 Roo.lib.AnimMgr = new function() {
3422 this.registerElement = function(tween) {
3423 queue[queue.length] = tween;
3425 tween._onStart.fire();
3430 this.unRegister = function(tween, index) {
3431 tween._onComplete.fire();
3432 index = index || getIndex(tween);
3434 queue.splice(index, 1);
3438 if (tweenCount <= 0) {
3444 this.start = function() {
3445 if (thread === null) {
3446 thread = setInterval(this.run, this.delay);
3451 this.stop = function(tween) {
3453 clearInterval(thread);
3455 for (var i = 0, len = queue.length; i < len; ++i) {
3456 if (queue[0].isAnimated()) {
3457 this.unRegister(queue[0], 0);
3466 this.unRegister(tween);
3471 this.run = function() {
3472 for (var i = 0, len = queue.length; i < len; ++i) {
3473 var tween = queue[i];
3474 if (!tween || !tween.isAnimated()) {
3478 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3480 tween.currentFrame += 1;
3482 if (tween.useSeconds) {
3483 correctFrame(tween);
3485 tween._onTween.fire();
3488 Roo.lib.AnimMgr.stop(tween, i);
3493 var getIndex = function(anim) {
3494 for (var i = 0, len = queue.length; i < len; ++i) {
3495 if (queue[i] == anim) {
3503 var correctFrame = function(tween) {
3504 var frames = tween.totalFrames;
3505 var frame = tween.currentFrame;
3506 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3507 var elapsed = (new Date() - tween.getStartTime());
3510 if (elapsed < tween.duration * 1000) {
3511 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3513 tweak = frames - (frame + 1);
3515 if (tweak > 0 && isFinite(tweak)) {
3516 if (tween.currentFrame + tweak >= frames) {
3517 tweak = frames - (frame + 1);
3520 tween.currentFrame += tweak;
3526 * Portions of this file are based on pieces of Yahoo User Interface Library
3527 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3528 * YUI licensed under the BSD License:
3529 * http://developer.yahoo.net/yui/license.txt
3530 * <script type="text/javascript">
3533 Roo.lib.Bezier = new function() {
3535 this.getPosition = function(points, t) {
3536 var n = points.length;
3539 for (var i = 0; i < n; ++i) {
3540 tmp[i] = [points[i][0], points[i][1]];
3543 for (var j = 1; j < n; ++j) {
3544 for (i = 0; i < n - j; ++i) {
3545 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3546 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3550 return [ tmp[0][0], tmp[0][1] ];
3554 * Portions of this file are based on pieces of Yahoo User Interface Library
3555 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3556 * YUI licensed under the BSD License:
3557 * http://developer.yahoo.net/yui/license.txt
3558 * <script type="text/javascript">
3563 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3564 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3567 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3569 var fly = Roo.lib.AnimBase.fly;
3571 var superclass = Y.ColorAnim.superclass;
3572 var proto = Y.ColorAnim.prototype;
3574 proto.toString = function() {
3575 var el = this.getEl();
3576 var id = el.id || el.tagName;
3577 return ("ColorAnim " + id);
3580 proto.patterns.color = /color$/i;
3581 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3582 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3583 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3584 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3587 proto.parseColor = function(s) {
3588 if (s.length == 3) {
3592 var c = this.patterns.hex.exec(s);
3593 if (c && c.length == 4) {
3594 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3597 c = this.patterns.rgb.exec(s);
3598 if (c && c.length == 4) {
3599 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3602 c = this.patterns.hex3.exec(s);
3603 if (c && c.length == 4) {
3604 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3609 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3610 proto.getAttribute = function(attr) {
3611 var el = this.getEl();
3612 if (this.patterns.color.test(attr)) {
3613 var val = fly(el).getStyle(attr);
3615 if (this.patterns.transparent.test(val)) {
3616 var parent = el.parentNode;
3617 val = fly(parent).getStyle(attr);
3619 while (parent && this.patterns.transparent.test(val)) {
3620 parent = parent.parentNode;
3621 val = fly(parent).getStyle(attr);
3622 if (parent.tagName.toUpperCase() == 'HTML') {
3628 val = superclass.getAttribute.call(this, attr);
3633 proto.getAttribute = function(attr) {
3634 var el = this.getEl();
3635 if (this.patterns.color.test(attr)) {
3636 var val = fly(el).getStyle(attr);
3638 if (this.patterns.transparent.test(val)) {
3639 var parent = el.parentNode;
3640 val = fly(parent).getStyle(attr);
3642 while (parent && this.patterns.transparent.test(val)) {
3643 parent = parent.parentNode;
3644 val = fly(parent).getStyle(attr);
3645 if (parent.tagName.toUpperCase() == 'HTML') {
3651 val = superclass.getAttribute.call(this, attr);
3657 proto.doMethod = function(attr, start, end) {
3660 if (this.patterns.color.test(attr)) {
3662 for (var i = 0, len = start.length; i < len; ++i) {
3663 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3666 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3669 val = superclass.doMethod.call(this, attr, start, end);
3675 proto.setRuntimeAttribute = function(attr) {
3676 superclass.setRuntimeAttribute.call(this, attr);
3678 if (this.patterns.color.test(attr)) {
3679 var attributes = this.attributes;
3680 var start = this.parseColor(this.runtimeAttributes[attr].start);
3681 var end = this.parseColor(this.runtimeAttributes[attr].end);
3683 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3684 end = this.parseColor(attributes[attr].by);
3686 for (var i = 0, len = start.length; i < len; ++i) {
3687 end[i] = start[i] + end[i];
3691 this.runtimeAttributes[attr].start = start;
3692 this.runtimeAttributes[attr].end = end;
3698 * Portions of this file are based on pieces of Yahoo User Interface Library
3699 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3700 * YUI licensed under the BSD License:
3701 * http://developer.yahoo.net/yui/license.txt
3702 * <script type="text/javascript">
3708 easeNone: function (t, b, c, d) {
3709 return c * t / d + b;
3713 easeIn: function (t, b, c, d) {
3714 return c * (t /= d) * t + b;
3718 easeOut: function (t, b, c, d) {
3719 return -c * (t /= d) * (t - 2) + b;
3723 easeBoth: function (t, b, c, d) {
3724 if ((t /= d / 2) < 1) {
3725 return c / 2 * t * t + b;
3728 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3732 easeInStrong: function (t, b, c, d) {
3733 return c * (t /= d) * t * t * t + b;
3737 easeOutStrong: function (t, b, c, d) {
3738 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3742 easeBothStrong: function (t, b, c, d) {
3743 if ((t /= d / 2) < 1) {
3744 return c / 2 * t * t * t * t + b;
3747 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3752 elasticIn: function (t, b, c, d, a, p) {
3756 if ((t /= d) == 1) {
3763 if (!a || a < Math.abs(c)) {
3768 var s = p / (2 * Math.PI) * Math.asin(c / a);
3771 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3775 elasticOut: function (t, b, c, d, a, p) {
3779 if ((t /= d) == 1) {
3786 if (!a || a < Math.abs(c)) {
3791 var s = p / (2 * Math.PI) * Math.asin(c / a);
3794 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3798 elasticBoth: function (t, b, c, d, a, p) {
3803 if ((t /= d / 2) == 2) {
3811 if (!a || a < Math.abs(c)) {
3816 var s = p / (2 * Math.PI) * Math.asin(c / a);
3820 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3821 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3823 return a * Math.pow(2, -10 * (t -= 1)) *
3824 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3829 backIn: function (t, b, c, d, s) {
3830 if (typeof s == 'undefined') {
3833 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3837 backOut: function (t, b, c, d, s) {
3838 if (typeof s == 'undefined') {
3841 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3845 backBoth: function (t, b, c, d, s) {
3846 if (typeof s == 'undefined') {
3850 if ((t /= d / 2 ) < 1) {
3851 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3853 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3857 bounceIn: function (t, b, c, d) {
3858 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3862 bounceOut: function (t, b, c, d) {
3863 if ((t /= d) < (1 / 2.75)) {
3864 return c * (7.5625 * t * t) + b;
3865 } else if (t < (2 / 2.75)) {
3866 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3867 } else if (t < (2.5 / 2.75)) {
3868 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3870 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3874 bounceBoth: function (t, b, c, d) {
3876 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3878 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3881 * Portions of this file are based on pieces of Yahoo User Interface Library
3882 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3883 * YUI licensed under the BSD License:
3884 * http://developer.yahoo.net/yui/license.txt
3885 * <script type="text/javascript">
3889 Roo.lib.Motion = function(el, attributes, duration, method) {
3891 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3895 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3899 var superclass = Y.Motion.superclass;
3900 var proto = Y.Motion.prototype;
3902 proto.toString = function() {
3903 var el = this.getEl();
3904 var id = el.id || el.tagName;
3905 return ("Motion " + id);
3908 proto.patterns.points = /^points$/i;
3910 proto.setAttribute = function(attr, val, unit) {
3911 if (this.patterns.points.test(attr)) {
3912 unit = unit || 'px';
3913 superclass.setAttribute.call(this, 'left', val[0], unit);
3914 superclass.setAttribute.call(this, 'top', val[1], unit);
3916 superclass.setAttribute.call(this, attr, val, unit);
3920 proto.getAttribute = function(attr) {
3921 if (this.patterns.points.test(attr)) {
3923 superclass.getAttribute.call(this, 'left'),
3924 superclass.getAttribute.call(this, 'top')
3927 val = superclass.getAttribute.call(this, attr);
3933 proto.doMethod = function(attr, start, end) {
3936 if (this.patterns.points.test(attr)) {
3937 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3938 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3940 val = superclass.doMethod.call(this, attr, start, end);
3945 proto.setRuntimeAttribute = function(attr) {
3946 if (this.patterns.points.test(attr)) {
3947 var el = this.getEl();
3948 var attributes = this.attributes;
3950 var control = attributes['points']['control'] || [];
3954 if (control.length > 0 && !(control[0] instanceof Array)) {
3955 control = [control];
3958 for (i = 0,len = control.length; i < len; ++i) {
3959 tmp[i] = control[i];
3964 Roo.fly(el).position();
3966 if (isset(attributes['points']['from'])) {
3967 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3970 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3973 start = this.getAttribute('points');
3976 if (isset(attributes['points']['to'])) {
3977 end = translateValues.call(this, attributes['points']['to'], start);
3979 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3980 for (i = 0,len = control.length; i < len; ++i) {
3981 control[i] = translateValues.call(this, control[i], start);
3985 } else if (isset(attributes['points']['by'])) {
3986 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3988 for (i = 0,len = control.length; i < len; ++i) {
3989 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3993 this.runtimeAttributes[attr] = [start];
3995 if (control.length > 0) {
3996 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3999 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4002 superclass.setRuntimeAttribute.call(this, attr);
4006 var translateValues = function(val, start) {
4007 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4008 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4013 var isset = function(prop) {
4014 return (typeof prop !== 'undefined');
4018 * Portions of this file are based on pieces of Yahoo User Interface Library
4019 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4020 * YUI licensed under the BSD License:
4021 * http://developer.yahoo.net/yui/license.txt
4022 * <script type="text/javascript">
4026 Roo.lib.Scroll = function(el, attributes, duration, method) {
4028 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4032 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4036 var superclass = Y.Scroll.superclass;
4037 var proto = Y.Scroll.prototype;
4039 proto.toString = function() {
4040 var el = this.getEl();
4041 var id = el.id || el.tagName;
4042 return ("Scroll " + id);
4045 proto.doMethod = function(attr, start, end) {
4048 if (attr == 'scroll') {
4050 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4051 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4055 val = superclass.doMethod.call(this, attr, start, end);
4060 proto.getAttribute = function(attr) {
4062 var el = this.getEl();
4064 if (attr == 'scroll') {
4065 val = [ el.scrollLeft, el.scrollTop ];
4067 val = superclass.getAttribute.call(this, attr);
4073 proto.setAttribute = function(attr, val, unit) {
4074 var el = this.getEl();
4076 if (attr == 'scroll') {
4077 el.scrollLeft = val[0];
4078 el.scrollTop = val[1];
4080 superclass.setAttribute.call(this, attr, val, unit);
4086 * Ext JS Library 1.1.1
4087 * Copyright(c) 2006-2007, Ext JS, LLC.
4089 * Originally Released Under LGPL - original licence link has changed is not relivant.
4092 * <script type="text/javascript">
4096 // nasty IE9 hack - what a pile of crap that is..
4098 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4099 Range.prototype.createContextualFragment = function (html) {
4100 var doc = window.document;
4101 var container = doc.createElement("div");
4102 container.innerHTML = html;
4103 var frag = doc.createDocumentFragment(), n;
4104 while ((n = container.firstChild)) {
4105 frag.appendChild(n);
4112 * @class Roo.DomHelper
4113 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4114 * 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>.
4117 Roo.DomHelper = function(){
4118 var tempTableEl = null;
4119 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4120 var tableRe = /^table|tbody|tr|td$/i;
4122 // build as innerHTML where available
4124 var createHtml = function(o){
4125 if(typeof o == 'string'){
4134 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4135 if(attr == "style"){
4137 if(typeof s == "function"){
4140 if(typeof s == "string"){
4141 b += ' style="' + s + '"';
4142 }else if(typeof s == "object"){
4145 if(typeof s[key] != "function"){
4146 b += key + ":" + s[key] + ";";
4153 b += ' class="' + o["cls"] + '"';
4154 }else if(attr == "htmlFor"){
4155 b += ' for="' + o["htmlFor"] + '"';
4157 b += " " + attr + '="' + o[attr] + '"';
4161 if(emptyTags.test(o.tag)){
4165 var cn = o.children || o.cn;
4167 //http://bugs.kde.org/show_bug.cgi?id=71506
4168 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4169 for(var i = 0, len = cn.length; i < len; i++) {
4170 b += createHtml(cn[i], b);
4173 b += createHtml(cn, b);
4179 b += "</" + o.tag + ">";
4186 var createDom = function(o, parentNode){
4188 // defininition craeted..
4190 if (o.ns && o.ns != 'html') {
4192 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4193 xmlns[o.ns] = o.xmlns;
4196 if (typeof(xmlns[o.ns]) == 'undefined') {
4197 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4203 if (typeof(o) == 'string') {
4204 return parentNode.appendChild(document.createTextNode(o));
4206 o.tag = o.tag || div;
4207 if (o.ns && Roo.isIE) {
4209 o.tag = o.ns + ':' + o.tag;
4212 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4213 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4216 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4217 attr == "style" || typeof o[attr] == "function") continue;
4219 if(attr=="cls" && Roo.isIE){
4220 el.className = o["cls"];
4222 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4223 else el[attr] = o[attr];
4226 Roo.DomHelper.applyStyles(el, o.style);
4227 var cn = o.children || o.cn;
4229 //http://bugs.kde.org/show_bug.cgi?id=71506
4230 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4231 for(var i = 0, len = cn.length; i < len; i++) {
4232 createDom(cn[i], el);
4239 el.innerHTML = o.html;
4242 parentNode.appendChild(el);
4247 var ieTable = function(depth, s, h, e){
4248 tempTableEl.innerHTML = [s, h, e].join('');
4249 var i = -1, el = tempTableEl;
4256 // kill repeat to save bytes
4260 tbe = '</tbody>'+te,
4266 * Nasty code for IE's broken table implementation
4268 var insertIntoTable = function(tag, where, el, html){
4270 tempTableEl = document.createElement('div');
4275 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4278 if(where == 'beforebegin'){
4282 before = el.nextSibling;
4285 node = ieTable(4, trs, html, tre);
4287 else if(tag == 'tr'){
4288 if(where == 'beforebegin'){
4291 node = ieTable(3, tbs, html, tbe);
4292 } else if(where == 'afterend'){
4293 before = el.nextSibling;
4295 node = ieTable(3, tbs, html, tbe);
4296 } else{ // INTO a TR
4297 if(where == 'afterbegin'){
4298 before = el.firstChild;
4300 node = ieTable(4, trs, html, tre);
4302 } else if(tag == 'tbody'){
4303 if(where == 'beforebegin'){
4306 node = ieTable(2, ts, html, te);
4307 } else if(where == 'afterend'){
4308 before = el.nextSibling;
4310 node = ieTable(2, ts, html, te);
4312 if(where == 'afterbegin'){
4313 before = el.firstChild;
4315 node = ieTable(3, tbs, html, tbe);
4318 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4321 if(where == 'afterbegin'){
4322 before = el.firstChild;
4324 node = ieTable(2, ts, html, te);
4326 el.insertBefore(node, before);
4331 /** True to force the use of DOM instead of html fragments @type Boolean */
4335 * Returns the markup for the passed Element(s) config
4336 * @param {Object} o The Dom object spec (and children)
4339 markup : function(o){
4340 return createHtml(o);
4344 * Applies a style specification to an element
4345 * @param {String/HTMLElement} el The element to apply styles to
4346 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4347 * a function which returns such a specification.
4349 applyStyles : function(el, styles){
4352 if(typeof styles == "string"){
4353 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4355 while ((matches = re.exec(styles)) != null){
4356 el.setStyle(matches[1], matches[2]);
4358 }else if (typeof styles == "object"){
4359 for (var style in styles){
4360 el.setStyle(style, styles[style]);
4362 }else if (typeof styles == "function"){
4363 Roo.DomHelper.applyStyles(el, styles.call());
4369 * Inserts an HTML fragment into the Dom
4370 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4371 * @param {HTMLElement} el The context element
4372 * @param {String} html The HTML fragmenet
4373 * @return {HTMLElement} The new node
4375 insertHtml : function(where, el, html){
4376 where = where.toLowerCase();
4377 if(el.insertAdjacentHTML){
4378 if(tableRe.test(el.tagName)){
4380 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4386 el.insertAdjacentHTML('BeforeBegin', html);
4387 return el.previousSibling;
4389 el.insertAdjacentHTML('AfterBegin', html);
4390 return el.firstChild;
4392 el.insertAdjacentHTML('BeforeEnd', html);
4393 return el.lastChild;
4395 el.insertAdjacentHTML('AfterEnd', html);
4396 return el.nextSibling;
4398 throw 'Illegal insertion point -> "' + where + '"';
4400 var range = el.ownerDocument.createRange();
4404 range.setStartBefore(el);
4405 frag = range.createContextualFragment(html);
4406 el.parentNode.insertBefore(frag, el);
4407 return el.previousSibling;
4410 range.setStartBefore(el.firstChild);
4411 frag = range.createContextualFragment(html);
4412 el.insertBefore(frag, el.firstChild);
4413 return el.firstChild;
4415 el.innerHTML = html;
4416 return el.firstChild;
4420 range.setStartAfter(el.lastChild);
4421 frag = range.createContextualFragment(html);
4422 el.appendChild(frag);
4423 return el.lastChild;
4425 el.innerHTML = html;
4426 return el.lastChild;
4429 range.setStartAfter(el);
4430 frag = range.createContextualFragment(html);
4431 el.parentNode.insertBefore(frag, el.nextSibling);
4432 return el.nextSibling;
4434 throw 'Illegal insertion point -> "' + where + '"';
4438 * Creates new Dom element(s) and inserts them before el
4439 * @param {String/HTMLElement/Element} el The context element
4440 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4441 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4442 * @return {HTMLElement/Roo.Element} The new node
4444 insertBefore : function(el, o, returnElement){
4445 return this.doInsert(el, o, returnElement, "beforeBegin");
4449 * Creates new Dom element(s) and inserts them after el
4450 * @param {String/HTMLElement/Element} el The context element
4451 * @param {Object} o The Dom object spec (and children)
4452 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4453 * @return {HTMLElement/Roo.Element} The new node
4455 insertAfter : function(el, o, returnElement){
4456 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4460 * Creates new Dom element(s) and inserts them as the first child of el
4461 * @param {String/HTMLElement/Element} el The context element
4462 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4463 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464 * @return {HTMLElement/Roo.Element} The new node
4466 insertFirst : function(el, o, returnElement){
4467 return this.doInsert(el, o, returnElement, "afterBegin");
4471 doInsert : function(el, o, returnElement, pos, sibling){
4472 el = Roo.getDom(el);
4474 if(this.useDom || o.ns){
4475 newNode = createDom(o, null);
4476 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4478 var html = createHtml(o);
4479 newNode = this.insertHtml(pos, el, html);
4481 return returnElement ? Roo.get(newNode, true) : newNode;
4485 * Creates new Dom element(s) and appends them to el
4486 * @param {String/HTMLElement/Element} el The context element
4487 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4488 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4489 * @return {HTMLElement/Roo.Element} The new node
4491 append : function(el, o, returnElement){
4492 el = Roo.getDom(el);
4494 if(this.useDom || o.ns){
4495 newNode = createDom(o, null);
4496 el.appendChild(newNode);
4498 var html = createHtml(o);
4499 newNode = this.insertHtml("beforeEnd", el, html);
4501 return returnElement ? Roo.get(newNode, true) : newNode;
4505 * Creates new Dom element(s) and overwrites the contents of el with them
4506 * @param {String/HTMLElement/Element} el The context element
4507 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4508 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4509 * @return {HTMLElement/Roo.Element} The new node
4511 overwrite : function(el, o, returnElement){
4512 el = Roo.getDom(el);
4515 while (el.childNodes.length) {
4516 el.removeChild(el.firstChild);
4520 el.innerHTML = createHtml(o);
4523 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4527 * Creates a new Roo.DomHelper.Template from the Dom object spec
4528 * @param {Object} o The Dom object spec (and children)
4529 * @return {Roo.DomHelper.Template} The new template
4531 createTemplate : function(o){
4532 var html = createHtml(o);
4533 return new Roo.Template(html);
4539 * Ext JS Library 1.1.1
4540 * Copyright(c) 2006-2007, Ext JS, LLC.
4542 * Originally Released Under LGPL - original licence link has changed is not relivant.
4545 * <script type="text/javascript">
4549 * @class Roo.Template
4550 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4551 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4554 var t = new Roo.Template({
4555 html : '<div name="{id}">' +
4556 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4558 myformat: function (value, allValues) {
4559 return 'XX' + value;
4562 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4564 * For more information see this blog post with examples:
4565 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4566 - Create Elements using DOM, HTML fragments and Templates</a>.
4568 * @param {Object} cfg - Configuration object.
4570 Roo.Template = function(cfg){
4572 if(cfg instanceof Array){
4574 }else if(arguments.length > 1){
4575 cfg = Array.prototype.join.call(arguments, "");
4579 if (typeof(cfg) == 'object') {
4590 Roo.Template.prototype = {
4593 * @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..
4594 * it should be fixed so that template is observable...
4598 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4602 * Returns an HTML fragment of this template with the specified values applied.
4603 * @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'})
4604 * @return {String} The HTML fragment
4606 applyTemplate : function(values){
4610 return this.compiled(values);
4612 var useF = this.disableFormats !== true;
4613 var fm = Roo.util.Format, tpl = this;
4614 var fn = function(m, name, format, args){
4616 if(format.substr(0, 5) == "this."){
4617 return tpl.call(format.substr(5), values[name], values);
4620 // quoted values are required for strings in compiled templates,
4621 // but for non compiled we need to strip them
4622 // quoted reversed for jsmin
4623 var re = /^\s*['"](.*)["']\s*$/;
4624 args = args.split(',');
4625 for(var i = 0, len = args.length; i < len; i++){
4626 args[i] = args[i].replace(re, "$1");
4628 args = [values[name]].concat(args);
4630 args = [values[name]];
4632 return fm[format].apply(fm, args);
4635 return values[name] !== undefined ? values[name] : "";
4638 return this.html.replace(this.re, fn);
4656 this.loading = true;
4657 this.compiled = false;
4659 var cx = new Roo.data.Connection();
4663 success : function (response) {
4665 _t.html = response.responseText;
4669 failure : function(response) {
4670 Roo.log("Template failed to load from " + _t.url);
4677 * Sets the HTML used as the template and optionally compiles it.
4678 * @param {String} html
4679 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4680 * @return {Roo.Template} this
4682 set : function(html, compile){
4684 this.compiled = null;
4692 * True to disable format functions (defaults to false)
4695 disableFormats : false,
4698 * The regular expression used to match template variables
4702 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4705 * Compiles the template into an internal function, eliminating the RegEx overhead.
4706 * @return {Roo.Template} this
4708 compile : function(){
4709 var fm = Roo.util.Format;
4710 var useF = this.disableFormats !== true;
4711 var sep = Roo.isGecko ? "+" : ",";
4712 var fn = function(m, name, format, args){
4714 args = args ? ',' + args : "";
4715 if(format.substr(0, 5) != "this."){
4716 format = "fm." + format + '(';
4718 format = 'this.call("'+ format.substr(5) + '", ';
4722 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4724 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4727 // branched to use + in gecko and [].join() in others
4729 body = "this.compiled = function(values){ return '" +
4730 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4733 body = ["this.compiled = function(values){ return ['"];
4734 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4735 body.push("'].join('');};");
4736 body = body.join('');
4746 // private function used to call members
4747 call : function(fnName, value, allValues){
4748 return this[fnName](value, allValues);
4752 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4753 * @param {String/HTMLElement/Roo.Element} el The context element
4754 * @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'})
4755 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4756 * @return {HTMLElement/Roo.Element} The new node or Element
4758 insertFirst: function(el, values, returnElement){
4759 return this.doInsert('afterBegin', el, values, returnElement);
4763 * Applies the supplied values to the template and inserts the new node(s) before el.
4764 * @param {String/HTMLElement/Roo.Element} el The context element
4765 * @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'})
4766 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4767 * @return {HTMLElement/Roo.Element} The new node or Element
4769 insertBefore: function(el, values, returnElement){
4770 return this.doInsert('beforeBegin', el, values, returnElement);
4774 * Applies the supplied values to the template and inserts the new node(s) after el.
4775 * @param {String/HTMLElement/Roo.Element} el The context element
4776 * @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'})
4777 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778 * @return {HTMLElement/Roo.Element} The new node or Element
4780 insertAfter : function(el, values, returnElement){
4781 return this.doInsert('afterEnd', el, values, returnElement);
4785 * Applies the supplied values to the template and appends the new node(s) to el.
4786 * @param {String/HTMLElement/Roo.Element} el The context element
4787 * @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'})
4788 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789 * @return {HTMLElement/Roo.Element} The new node or Element
4791 append : function(el, values, returnElement){
4792 return this.doInsert('beforeEnd', el, values, returnElement);
4795 doInsert : function(where, el, values, returnEl){
4796 el = Roo.getDom(el);
4797 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4798 return returnEl ? Roo.get(newNode, true) : newNode;
4802 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4803 * @param {String/HTMLElement/Roo.Element} el The context element
4804 * @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'})
4805 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4806 * @return {HTMLElement/Roo.Element} The new node or Element
4808 overwrite : function(el, values, returnElement){
4809 el = Roo.getDom(el);
4810 el.innerHTML = this.applyTemplate(values);
4811 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4815 * Alias for {@link #applyTemplate}
4818 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4821 Roo.DomHelper.Template = Roo.Template;
4824 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4825 * @param {String/HTMLElement} el A DOM element or its id
4826 * @returns {Roo.Template} The created template
4829 Roo.Template.from = function(el){
4830 el = Roo.getDom(el);
4831 return new Roo.Template(el.value || el.innerHTML);
4834 * Ext JS Library 1.1.1
4835 * Copyright(c) 2006-2007, Ext JS, LLC.
4837 * Originally Released Under LGPL - original licence link has changed is not relivant.
4840 * <script type="text/javascript">
4845 * This is code is also distributed under MIT license for use
4846 * with jQuery and prototype JavaScript libraries.
4849 * @class Roo.DomQuery
4850 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).
4852 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>
4855 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.
4857 <h4>Element Selectors:</h4>
4859 <li> <b>*</b> any element</li>
4860 <li> <b>E</b> an element with the tag E</li>
4861 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4862 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4863 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4864 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4866 <h4>Attribute Selectors:</h4>
4867 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4869 <li> <b>E[foo]</b> has an attribute "foo"</li>
4870 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4871 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4872 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4873 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4874 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4875 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4877 <h4>Pseudo Classes:</h4>
4879 <li> <b>E:first-child</b> E is the first child of its parent</li>
4880 <li> <b>E:last-child</b> E is the last child of its parent</li>
4881 <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>
4882 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4883 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4884 <li> <b>E:only-child</b> E is the only child of its parent</li>
4885 <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>
4886 <li> <b>E:first</b> the first E in the resultset</li>
4887 <li> <b>E:last</b> the last E in the resultset</li>
4888 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4889 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4890 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4891 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4892 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4893 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4894 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4895 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4896 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4898 <h4>CSS Value Selectors:</h4>
4900 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4901 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4902 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4903 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4904 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4905 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4909 Roo.DomQuery = function(){
4910 var cache = {}, simpleCache = {}, valueCache = {};
4911 var nonSpace = /\S/;
4912 var trimRe = /^\s+|\s+$/g;
4913 var tplRe = /\{(\d+)\}/g;
4914 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4915 var tagTokenRe = /^(#)?([\w-\*]+)/;
4916 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4918 function child(p, index){
4920 var n = p.firstChild;
4922 if(n.nodeType == 1){
4933 while((n = n.nextSibling) && n.nodeType != 1);
4938 while((n = n.previousSibling) && n.nodeType != 1);
4942 function children(d){
4943 var n = d.firstChild, ni = -1;
4945 var nx = n.nextSibling;
4946 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4956 function byClassName(c, a, v){
4960 var r = [], ri = -1, cn;
4961 for(var i = 0, ci; ci = c[i]; i++){
4962 if((' '+ci.className+' ').indexOf(v) != -1){
4969 function attrValue(n, attr){
4970 if(!n.tagName && typeof n.length != "undefined"){
4979 if(attr == "class" || attr == "className"){
4982 return n.getAttribute(attr) || n[attr];
4986 function getNodes(ns, mode, tagName){
4987 var result = [], ri = -1, cs;
4991 tagName = tagName || "*";
4992 if(typeof ns.getElementsByTagName != "undefined"){
4996 for(var i = 0, ni; ni = ns[i]; i++){
4997 cs = ni.getElementsByTagName(tagName);
4998 for(var j = 0, ci; ci = cs[j]; j++){
5002 }else if(mode == "/" || mode == ">"){
5003 var utag = tagName.toUpperCase();
5004 for(var i = 0, ni, cn; ni = ns[i]; i++){
5005 cn = ni.children || ni.childNodes;
5006 for(var j = 0, cj; cj = cn[j]; j++){
5007 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5012 }else if(mode == "+"){
5013 var utag = tagName.toUpperCase();
5014 for(var i = 0, n; n = ns[i]; i++){
5015 while((n = n.nextSibling) && n.nodeType != 1);
5016 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5020 }else if(mode == "~"){
5021 for(var i = 0, n; n = ns[i]; i++){
5022 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5031 function concat(a, b){
5035 for(var i = 0, l = b.length; i < l; i++){
5041 function byTag(cs, tagName){
5042 if(cs.tagName || cs == document){
5048 var r = [], ri = -1;
5049 tagName = tagName.toLowerCase();
5050 for(var i = 0, ci; ci = cs[i]; i++){
5051 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5058 function byId(cs, attr, id){
5059 if(cs.tagName || cs == document){
5065 var r = [], ri = -1;
5066 for(var i = 0,ci; ci = cs[i]; i++){
5067 if(ci && ci.id == id){
5075 function byAttribute(cs, attr, value, op, custom){
5076 var r = [], ri = -1, st = custom=="{";
5077 var f = Roo.DomQuery.operators[op];
5078 for(var i = 0, ci; ci = cs[i]; i++){
5081 a = Roo.DomQuery.getStyle(ci, attr);
5083 else if(attr == "class" || attr == "className"){
5085 }else if(attr == "for"){
5087 }else if(attr == "href"){
5088 a = ci.getAttribute("href", 2);
5090 a = ci.getAttribute(attr);
5092 if((f && f(a, value)) || (!f && a)){
5099 function byPseudo(cs, name, value){
5100 return Roo.DomQuery.pseudos[name](cs, value);
5103 // This is for IE MSXML which does not support expandos.
5104 // IE runs the same speed using setAttribute, however FF slows way down
5105 // and Safari completely fails so they need to continue to use expandos.
5106 var isIE = window.ActiveXObject ? true : false;
5108 // this eval is stop the compressor from
5109 // renaming the variable to something shorter
5111 /** eval:var:batch */
5116 function nodupIEXml(cs){
5118 cs[0].setAttribute("_nodup", d);
5120 for(var i = 1, len = cs.length; i < len; i++){
5122 if(!c.getAttribute("_nodup") != d){
5123 c.setAttribute("_nodup", d);
5127 for(var i = 0, len = cs.length; i < len; i++){
5128 cs[i].removeAttribute("_nodup");
5137 var len = cs.length, c, i, r = cs, cj, ri = -1;
5138 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5141 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5142 return nodupIEXml(cs);
5146 for(i = 1; c = cs[i]; i++){
5151 for(var j = 0; j < i; j++){
5154 for(j = i+1; cj = cs[j]; j++){
5166 function quickDiffIEXml(c1, c2){
5168 for(var i = 0, len = c1.length; i < len; i++){
5169 c1[i].setAttribute("_qdiff", d);
5172 for(var i = 0, len = c2.length; i < len; i++){
5173 if(c2[i].getAttribute("_qdiff") != d){
5174 r[r.length] = c2[i];
5177 for(var i = 0, len = c1.length; i < len; i++){
5178 c1[i].removeAttribute("_qdiff");
5183 function quickDiff(c1, c2){
5184 var len1 = c1.length;
5188 if(isIE && c1[0].selectSingleNode){
5189 return quickDiffIEXml(c1, c2);
5192 for(var i = 0; i < len1; i++){
5196 for(var i = 0, len = c2.length; i < len; i++){
5197 if(c2[i]._qdiff != d){
5198 r[r.length] = c2[i];
5204 function quickId(ns, mode, root, id){
5206 var d = root.ownerDocument || root;
5207 return d.getElementById(id);
5209 ns = getNodes(ns, mode, "*");
5210 return byId(ns, null, id);
5214 getStyle : function(el, name){
5215 return Roo.fly(el).getStyle(name);
5218 * Compiles a selector/xpath query into a reusable function. The returned function
5219 * takes one parameter "root" (optional), which is the context node from where the query should start.
5220 * @param {String} selector The selector/xpath query
5221 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5222 * @return {Function}
5224 compile : function(path, type){
5225 type = type || "select";
5227 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5228 var q = path, mode, lq;
5229 var tk = Roo.DomQuery.matchers;
5230 var tklen = tk.length;
5233 // accept leading mode switch
5234 var lmode = q.match(modeRe);
5235 if(lmode && lmode[1]){
5236 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5237 q = q.replace(lmode[1], "");
5239 // strip leading slashes
5240 while(path.substr(0, 1)=="/"){
5241 path = path.substr(1);
5244 while(q && lq != q){
5246 var tm = q.match(tagTokenRe);
5247 if(type == "select"){
5250 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5252 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5254 q = q.replace(tm[0], "");
5255 }else if(q.substr(0, 1) != '@'){
5256 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5261 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5263 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5265 q = q.replace(tm[0], "");
5268 while(!(mm = q.match(modeRe))){
5269 var matched = false;
5270 for(var j = 0; j < tklen; j++){
5272 var m = q.match(t.re);
5274 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5277 q = q.replace(m[0], "");
5282 // prevent infinite loop on bad selector
5284 throw 'Error parsing selector, parsing failed at "' + q + '"';
5288 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5289 q = q.replace(mm[1], "");
5292 fn[fn.length] = "return nodup(n);\n}";
5295 * list of variables that need from compression as they are used by eval.
5305 * eval:var:byClassName
5307 * eval:var:byAttribute
5308 * eval:var:attrValue
5316 * Selects a group of elements.
5317 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5318 * @param {Node} root (optional) The start of the query (defaults to document).
5321 select : function(path, root, type){
5322 if(!root || root == document){
5325 if(typeof root == "string"){
5326 root = document.getElementById(root);
5328 var paths = path.split(",");
5330 for(var i = 0, len = paths.length; i < len; i++){
5331 var p = paths[i].replace(trimRe, "");
5333 cache[p] = Roo.DomQuery.compile(p);
5335 throw p + " is not a valid selector";
5338 var result = cache[p](root);
5339 if(result && result != document){
5340 results = results.concat(result);
5343 if(paths.length > 1){
5344 return nodup(results);
5350 * Selects a single element.
5351 * @param {String} selector The selector/xpath query
5352 * @param {Node} root (optional) The start of the query (defaults to document).
5355 selectNode : function(path, root){
5356 return Roo.DomQuery.select(path, root)[0];
5360 * Selects the value of a node, optionally replacing null with the defaultValue.
5361 * @param {String} selector The selector/xpath query
5362 * @param {Node} root (optional) The start of the query (defaults to document).
5363 * @param {String} defaultValue
5365 selectValue : function(path, root, defaultValue){
5366 path = path.replace(trimRe, "");
5367 if(!valueCache[path]){
5368 valueCache[path] = Roo.DomQuery.compile(path, "select");
5370 var n = valueCache[path](root);
5371 n = n[0] ? n[0] : n;
5372 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5373 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5377 * Selects the value of a node, parsing integers and floats.
5378 * @param {String} selector The selector/xpath query
5379 * @param {Node} root (optional) The start of the query (defaults to document).
5380 * @param {Number} defaultValue
5383 selectNumber : function(path, root, defaultValue){
5384 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5385 return parseFloat(v);
5389 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5390 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5391 * @param {String} selector The simple selector to test
5394 is : function(el, ss){
5395 if(typeof el == "string"){
5396 el = document.getElementById(el);
5398 var isArray = (el instanceof Array);
5399 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5400 return isArray ? (result.length == el.length) : (result.length > 0);
5404 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5405 * @param {Array} el An array of elements to filter
5406 * @param {String} selector The simple selector to test
5407 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5408 * the selector instead of the ones that match
5411 filter : function(els, ss, nonMatches){
5412 ss = ss.replace(trimRe, "");
5413 if(!simpleCache[ss]){
5414 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5416 var result = simpleCache[ss](els);
5417 return nonMatches ? quickDiff(result, els) : result;
5421 * Collection of matching regular expressions and code snippets.
5425 select: 'n = byClassName(n, null, " {1} ");'
5427 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5428 select: 'n = byPseudo(n, "{1}", "{2}");'
5430 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5431 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5434 select: 'n = byId(n, null, "{1}");'
5437 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5442 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5443 * 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, > <.
5446 "=" : function(a, v){
5449 "!=" : function(a, v){
5452 "^=" : function(a, v){
5453 return a && a.substr(0, v.length) == v;
5455 "$=" : function(a, v){
5456 return a && a.substr(a.length-v.length) == v;
5458 "*=" : function(a, v){
5459 return a && a.indexOf(v) !== -1;
5461 "%=" : function(a, v){
5462 return (a % v) == 0;
5464 "|=" : function(a, v){
5465 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5467 "~=" : function(a, v){
5468 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5473 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5474 * and the argument (if any) supplied in the selector.
5477 "first-child" : function(c){
5478 var r = [], ri = -1, n;
5479 for(var i = 0, ci; ci = n = c[i]; i++){
5480 while((n = n.previousSibling) && n.nodeType != 1);
5488 "last-child" : function(c){
5489 var r = [], ri = -1, n;
5490 for(var i = 0, ci; ci = n = c[i]; i++){
5491 while((n = n.nextSibling) && n.nodeType != 1);
5499 "nth-child" : function(c, a) {
5500 var r = [], ri = -1;
5501 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5502 var f = (m[1] || 1) - 0, l = m[2] - 0;
5503 for(var i = 0, n; n = c[i]; i++){
5504 var pn = n.parentNode;
5505 if (batch != pn._batch) {
5507 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5508 if(cn.nodeType == 1){
5515 if (l == 0 || n.nodeIndex == l){
5518 } else if ((n.nodeIndex + l) % f == 0){
5526 "only-child" : function(c){
5527 var r = [], ri = -1;;
5528 for(var i = 0, ci; ci = c[i]; i++){
5529 if(!prev(ci) && !next(ci)){
5536 "empty" : function(c){
5537 var r = [], ri = -1;
5538 for(var i = 0, ci; ci = c[i]; i++){
5539 var cns = ci.childNodes, j = 0, cn, empty = true;
5542 if(cn.nodeType == 1 || cn.nodeType == 3){
5554 "contains" : function(c, v){
5555 var r = [], ri = -1;
5556 for(var i = 0, ci; ci = c[i]; i++){
5557 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5564 "nodeValue" : function(c, v){
5565 var r = [], ri = -1;
5566 for(var i = 0, ci; ci = c[i]; i++){
5567 if(ci.firstChild && ci.firstChild.nodeValue == v){
5574 "checked" : function(c){
5575 var r = [], ri = -1;
5576 for(var i = 0, ci; ci = c[i]; i++){
5577 if(ci.checked == true){
5584 "not" : function(c, ss){
5585 return Roo.DomQuery.filter(c, ss, true);
5588 "odd" : function(c){
5589 return this["nth-child"](c, "odd");
5592 "even" : function(c){
5593 return this["nth-child"](c, "even");
5596 "nth" : function(c, a){
5597 return c[a-1] || [];
5600 "first" : function(c){
5604 "last" : function(c){
5605 return c[c.length-1] || [];
5608 "has" : function(c, ss){
5609 var s = Roo.DomQuery.select;
5610 var r = [], ri = -1;
5611 for(var i = 0, ci; ci = c[i]; i++){
5612 if(s(ss, ci).length > 0){
5619 "next" : function(c, ss){
5620 var is = Roo.DomQuery.is;
5621 var r = [], ri = -1;
5622 for(var i = 0, ci; ci = c[i]; i++){
5631 "prev" : function(c, ss){
5632 var is = Roo.DomQuery.is;
5633 var r = [], ri = -1;
5634 for(var i = 0, ci; ci = c[i]; i++){
5647 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5648 * @param {String} path The selector/xpath query
5649 * @param {Node} root (optional) The start of the query (defaults to document).
5654 Roo.query = Roo.DomQuery.select;
5657 * Ext JS Library 1.1.1
5658 * Copyright(c) 2006-2007, Ext JS, LLC.
5660 * Originally Released Under LGPL - original licence link has changed is not relivant.
5663 * <script type="text/javascript">
5667 * @class Roo.util.Observable
5668 * Base class that provides a common interface for publishing events. Subclasses are expected to
5669 * to have a property "events" with all the events defined.<br>
5672 Employee = function(name){
5679 Roo.extend(Employee, Roo.util.Observable);
5681 * @param {Object} config properties to use (incuding events / listeners)
5684 Roo.util.Observable = function(cfg){
5687 this.addEvents(cfg.events || {});
5689 delete cfg.events; // make sure
5692 Roo.apply(this, cfg);
5695 this.on(this.listeners);
5696 delete this.listeners;
5699 Roo.util.Observable.prototype = {
5701 * @cfg {Object} listeners list of events and functions to call for this object,
5705 'click' : function(e) {
5715 * Fires the specified event with the passed parameters (minus the event name).
5716 * @param {String} eventName
5717 * @param {Object...} args Variable number of parameters are passed to handlers
5718 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5720 fireEvent : function(){
5721 var ce = this.events[arguments[0].toLowerCase()];
5722 if(typeof ce == "object"){
5723 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5730 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5733 * Appends an event handler to this component
5734 * @param {String} eventName The type of event to listen for
5735 * @param {Function} handler The method the event invokes
5736 * @param {Object} scope (optional) The scope in which to execute the handler
5737 * function. The handler function's "this" context.
5738 * @param {Object} options (optional) An object containing handler configuration
5739 * properties. This may contain any of the following properties:<ul>
5740 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5741 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5742 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5743 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5744 * by the specified number of milliseconds. If the event fires again within that time, the original
5745 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5748 * <b>Combining Options</b><br>
5749 * Using the options argument, it is possible to combine different types of listeners:<br>
5751 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5753 el.on('click', this.onClick, this, {
5760 * <b>Attaching multiple handlers in 1 call</b><br>
5761 * The method also allows for a single argument to be passed which is a config object containing properties
5762 * which specify multiple handlers.
5771 fn: this.onMouseOver,
5775 fn: this.onMouseOut,
5781 * Or a shorthand syntax which passes the same scope object to all handlers:
5784 'click': this.onClick,
5785 'mouseover': this.onMouseOver,
5786 'mouseout': this.onMouseOut,
5791 addListener : function(eventName, fn, scope, o){
5792 if(typeof eventName == "object"){
5795 if(this.filterOptRe.test(e)){
5798 if(typeof o[e] == "function"){
5800 this.addListener(e, o[e], o.scope, o);
5802 // individual options
5803 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5808 o = (!o || typeof o == "boolean") ? {} : o;
5809 eventName = eventName.toLowerCase();
5810 var ce = this.events[eventName] || true;
5811 if(typeof ce == "boolean"){
5812 ce = new Roo.util.Event(this, eventName);
5813 this.events[eventName] = ce;
5815 ce.addListener(fn, scope, o);
5819 * Removes a listener
5820 * @param {String} eventName The type of event to listen for
5821 * @param {Function} handler The handler to remove
5822 * @param {Object} scope (optional) The scope (this object) for the handler
5824 removeListener : function(eventName, fn, scope){
5825 var ce = this.events[eventName.toLowerCase()];
5826 if(typeof ce == "object"){
5827 ce.removeListener(fn, scope);
5832 * Removes all listeners for this object
5834 purgeListeners : function(){
5835 for(var evt in this.events){
5836 if(typeof this.events[evt] == "object"){
5837 this.events[evt].clearListeners();
5842 relayEvents : function(o, events){
5843 var createHandler = function(ename){
5845 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5848 for(var i = 0, len = events.length; i < len; i++){
5849 var ename = events[i];
5850 if(!this.events[ename]){ this.events[ename] = true; };
5851 o.on(ename, createHandler(ename), this);
5856 * Used to define events on this Observable
5857 * @param {Object} object The object with the events defined
5859 addEvents : function(o){
5863 Roo.applyIf(this.events, o);
5867 * Checks to see if this object has any listeners for a specified event
5868 * @param {String} eventName The name of the event to check for
5869 * @return {Boolean} True if the event is being listened for, else false
5871 hasListener : function(eventName){
5872 var e = this.events[eventName];
5873 return typeof e == "object" && e.listeners.length > 0;
5877 * Appends an event handler to this element (shorthand for addListener)
5878 * @param {String} eventName The type of event to listen for
5879 * @param {Function} handler The method the event invokes
5880 * @param {Object} scope (optional) The scope in which to execute the handler
5881 * function. The handler function's "this" context.
5882 * @param {Object} options (optional)
5885 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5887 * Removes a listener (shorthand for removeListener)
5888 * @param {String} eventName The type of event to listen for
5889 * @param {Function} handler The handler to remove
5890 * @param {Object} scope (optional) The scope (this object) for the handler
5893 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5896 * Starts capture on the specified Observable. All events will be passed
5897 * to the supplied function with the event name + standard signature of the event
5898 * <b>before</b> the event is fired. If the supplied function returns false,
5899 * the event will not fire.
5900 * @param {Observable} o The Observable to capture
5901 * @param {Function} fn The function to call
5902 * @param {Object} scope (optional) The scope (this object) for the fn
5905 Roo.util.Observable.capture = function(o, fn, scope){
5906 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5910 * Removes <b>all</b> added captures from the Observable.
5911 * @param {Observable} o The Observable to release
5914 Roo.util.Observable.releaseCapture = function(o){
5915 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5920 var createBuffered = function(h, o, scope){
5921 var task = new Roo.util.DelayedTask();
5923 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5927 var createSingle = function(h, e, fn, scope){
5929 e.removeListener(fn, scope);
5930 return h.apply(scope, arguments);
5934 var createDelayed = function(h, o, scope){
5936 var args = Array.prototype.slice.call(arguments, 0);
5937 setTimeout(function(){
5938 h.apply(scope, args);
5943 Roo.util.Event = function(obj, name){
5946 this.listeners = [];
5949 Roo.util.Event.prototype = {
5950 addListener : function(fn, scope, options){
5951 var o = options || {};
5952 scope = scope || this.obj;
5953 if(!this.isListening(fn, scope)){
5954 var l = {fn: fn, scope: scope, options: o};
5957 h = createDelayed(h, o, scope);
5960 h = createSingle(h, this, fn, scope);
5963 h = createBuffered(h, o, scope);
5966 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5967 this.listeners.push(l);
5969 this.listeners = this.listeners.slice(0);
5970 this.listeners.push(l);
5975 findListener : function(fn, scope){
5976 scope = scope || this.obj;
5977 var ls = this.listeners;
5978 for(var i = 0, len = ls.length; i < len; i++){
5980 if(l.fn == fn && l.scope == scope){
5987 isListening : function(fn, scope){
5988 return this.findListener(fn, scope) != -1;
5991 removeListener : function(fn, scope){
5993 if((index = this.findListener(fn, scope)) != -1){
5995 this.listeners.splice(index, 1);
5997 this.listeners = this.listeners.slice(0);
5998 this.listeners.splice(index, 1);
6005 clearListeners : function(){
6006 this.listeners = [];
6010 var ls = this.listeners, scope, len = ls.length;
6013 var args = Array.prototype.slice.call(arguments, 0);
6014 for(var i = 0; i < len; i++){
6016 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6017 this.firing = false;
6021 this.firing = false;
6028 * Ext JS Library 1.1.1
6029 * Copyright(c) 2006-2007, Ext JS, LLC.
6031 * Originally Released Under LGPL - original licence link has changed is not relivant.
6034 * <script type="text/javascript">
6038 * @class Roo.EventManager
6039 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6040 * several useful events directly.
6041 * See {@link Roo.EventObject} for more details on normalized event objects.
6044 Roo.EventManager = function(){
6045 var docReadyEvent, docReadyProcId, docReadyState = false;
6046 var resizeEvent, resizeTask, textEvent, textSize;
6047 var E = Roo.lib.Event;
6048 var D = Roo.lib.Dom;
6053 var fireDocReady = function(){
6055 docReadyState = true;
6058 clearInterval(docReadyProcId);
6060 if(Roo.isGecko || Roo.isOpera) {
6061 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6064 var defer = document.getElementById("ie-deferred-loader");
6066 defer.onreadystatechange = null;
6067 defer.parentNode.removeChild(defer);
6071 docReadyEvent.fire();
6072 docReadyEvent.clearListeners();
6077 var initDocReady = function(){
6078 docReadyEvent = new Roo.util.Event();
6079 if(Roo.isGecko || Roo.isOpera) {
6080 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6082 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6083 var defer = document.getElementById("ie-deferred-loader");
6084 defer.onreadystatechange = function(){
6085 if(this.readyState == "complete"){
6089 }else if(Roo.isSafari){
6090 docReadyProcId = setInterval(function(){
6091 var rs = document.readyState;
6092 if(rs == "complete") {
6097 // no matter what, make sure it fires on load
6098 E.on(window, "load", fireDocReady);
6101 var createBuffered = function(h, o){
6102 var task = new Roo.util.DelayedTask(h);
6104 // create new event object impl so new events don't wipe out properties
6105 e = new Roo.EventObjectImpl(e);
6106 task.delay(o.buffer, h, null, [e]);
6110 var createSingle = function(h, el, ename, fn){
6112 Roo.EventManager.removeListener(el, ename, fn);
6117 var createDelayed = function(h, o){
6119 // create new event object impl so new events don't wipe out properties
6120 e = new Roo.EventObjectImpl(e);
6121 setTimeout(function(){
6126 var transitionEndVal = false;
6128 var transitionEnd = function()
6130 if (transitionEndVal) {
6131 return transitionEndVal;
6133 var el = document.createElement('div');
6135 var transEndEventNames = {
6136 WebkitTransition : 'webkitTransitionEnd',
6137 MozTransition : 'transitionend',
6138 OTransition : 'oTransitionEnd otransitionend',
6139 transition : 'transitionend'
6142 for (var name in transEndEventNames) {
6143 if (el.style[name] !== undefined) {
6144 transitionEndVal = transEndEventNames[name];
6145 return transitionEndVal ;
6151 var listen = function(element, ename, opt, fn, scope){
6152 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6153 fn = fn || o.fn; scope = scope || o.scope;
6154 var el = Roo.getDom(element);
6158 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6161 if (ename == 'transitionend') {
6162 ename = transitionEnd();
6164 var h = function(e){
6165 e = Roo.EventObject.setEvent(e);
6168 t = e.getTarget(o.delegate, el);
6175 if(o.stopEvent === true){
6178 if(o.preventDefault === true){
6181 if(o.stopPropagation === true){
6182 e.stopPropagation();
6185 if(o.normalized === false){
6189 fn.call(scope || el, e, t, o);
6192 h = createDelayed(h, o);
6195 h = createSingle(h, el, ename, fn);
6198 h = createBuffered(h, o);
6200 fn._handlers = fn._handlers || [];
6203 fn._handlers.push([Roo.id(el), ename, h]);
6208 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6209 el.addEventListener("DOMMouseScroll", h, false);
6210 E.on(window, 'unload', function(){
6211 el.removeEventListener("DOMMouseScroll", h, false);
6214 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6215 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6220 var stopListening = function(el, ename, fn){
6221 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6223 for(var i = 0, len = hds.length; i < len; i++){
6225 if(h[0] == id && h[1] == ename){
6232 E.un(el, ename, hd);
6233 el = Roo.getDom(el);
6234 if(ename == "mousewheel" && el.addEventListener){
6235 el.removeEventListener("DOMMouseScroll", hd, false);
6237 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6238 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6242 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6249 * @scope Roo.EventManager
6254 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6255 * object with a Roo.EventObject
6256 * @param {Function} fn The method the event invokes
6257 * @param {Object} scope An object that becomes the scope of the handler
6258 * @param {boolean} override If true, the obj passed in becomes
6259 * the execution scope of the listener
6260 * @return {Function} The wrapped function
6263 wrap : function(fn, scope, override){
6265 Roo.EventObject.setEvent(e);
6266 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6271 * Appends an event handler to an element (shorthand for addListener)
6272 * @param {String/HTMLElement} element The html element or id to assign the
6273 * @param {String} eventName The type of event to listen for
6274 * @param {Function} handler The method the event invokes
6275 * @param {Object} scope (optional) The scope in which to execute the handler
6276 * function. The handler function's "this" context.
6277 * @param {Object} options (optional) An object containing handler configuration
6278 * properties. This may contain any of the following properties:<ul>
6279 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6280 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6281 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6282 * <li>preventDefault {Boolean} True to prevent the default action</li>
6283 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6284 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6285 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6286 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6287 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6288 * by the specified number of milliseconds. If the event fires again within that time, the original
6289 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6292 * <b>Combining Options</b><br>
6293 * Using the options argument, it is possible to combine different types of listeners:<br>
6295 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6297 el.on('click', this.onClick, this, {
6304 * <b>Attaching multiple handlers in 1 call</b><br>
6305 * The method also allows for a single argument to be passed which is a config object containing properties
6306 * which specify multiple handlers.
6316 fn: this.onMouseOver
6325 * Or a shorthand syntax:<br>
6328 'click' : this.onClick,
6329 'mouseover' : this.onMouseOver,
6330 'mouseout' : this.onMouseOut
6334 addListener : function(element, eventName, fn, scope, options){
6335 if(typeof eventName == "object"){
6341 if(typeof o[e] == "function"){
6343 listen(element, e, o, o[e], o.scope);
6345 // individual options
6346 listen(element, e, o[e]);
6351 return listen(element, eventName, options, fn, scope);
6355 * Removes an event handler
6357 * @param {String/HTMLElement} element The id or html element to remove the
6359 * @param {String} eventName The type of event
6360 * @param {Function} fn
6361 * @return {Boolean} True if a listener was actually removed
6363 removeListener : function(element, eventName, fn){
6364 return stopListening(element, eventName, fn);
6368 * Fires when the document is ready (before onload and before images are loaded). Can be
6369 * accessed shorthanded Roo.onReady().
6370 * @param {Function} fn The method the event invokes
6371 * @param {Object} scope An object that becomes the scope of the handler
6372 * @param {boolean} options
6374 onDocumentReady : function(fn, scope, options){
6375 if(docReadyState){ // if it already fired
6376 docReadyEvent.addListener(fn, scope, options);
6377 docReadyEvent.fire();
6378 docReadyEvent.clearListeners();
6384 docReadyEvent.addListener(fn, scope, options);
6388 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6389 * @param {Function} fn The method the event invokes
6390 * @param {Object} scope An object that becomes the scope of the handler
6391 * @param {boolean} options
6393 onWindowResize : function(fn, scope, options){
6395 resizeEvent = new Roo.util.Event();
6396 resizeTask = new Roo.util.DelayedTask(function(){
6397 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6399 E.on(window, "resize", function(){
6401 resizeTask.delay(50);
6403 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6407 resizeEvent.addListener(fn, scope, options);
6411 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6412 * @param {Function} fn The method the event invokes
6413 * @param {Object} scope An object that becomes the scope of the handler
6414 * @param {boolean} options
6416 onTextResize : function(fn, scope, options){
6418 textEvent = new Roo.util.Event();
6419 var textEl = new Roo.Element(document.createElement('div'));
6420 textEl.dom.className = 'x-text-resize';
6421 textEl.dom.innerHTML = 'X';
6422 textEl.appendTo(document.body);
6423 textSize = textEl.dom.offsetHeight;
6424 setInterval(function(){
6425 if(textEl.dom.offsetHeight != textSize){
6426 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6428 }, this.textResizeInterval);
6430 textEvent.addListener(fn, scope, options);
6434 * Removes the passed window resize listener.
6435 * @param {Function} fn The method the event invokes
6436 * @param {Object} scope The scope of handler
6438 removeResizeListener : function(fn, scope){
6440 resizeEvent.removeListener(fn, scope);
6445 fireResize : function(){
6447 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6451 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6455 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6457 textResizeInterval : 50
6462 * @scopeAlias pub=Roo.EventManager
6466 * Appends an event handler to an element (shorthand for addListener)
6467 * @param {String/HTMLElement} element The html element or id to assign the
6468 * @param {String} eventName The type of event to listen for
6469 * @param {Function} handler The method the event invokes
6470 * @param {Object} scope (optional) The scope in which to execute the handler
6471 * function. The handler function's "this" context.
6472 * @param {Object} options (optional) An object containing handler configuration
6473 * properties. This may contain any of the following properties:<ul>
6474 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6475 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6476 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6477 * <li>preventDefault {Boolean} True to prevent the default action</li>
6478 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6479 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6480 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6481 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6482 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6483 * by the specified number of milliseconds. If the event fires again within that time, the original
6484 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6487 * <b>Combining Options</b><br>
6488 * Using the options argument, it is possible to combine different types of listeners:<br>
6490 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6492 el.on('click', this.onClick, this, {
6499 * <b>Attaching multiple handlers in 1 call</b><br>
6500 * The method also allows for a single argument to be passed which is a config object containing properties
6501 * which specify multiple handlers.
6511 fn: this.onMouseOver
6520 * Or a shorthand syntax:<br>
6523 'click' : this.onClick,
6524 'mouseover' : this.onMouseOver,
6525 'mouseout' : this.onMouseOut
6529 pub.on = pub.addListener;
6530 pub.un = pub.removeListener;
6532 pub.stoppedMouseDownEvent = new Roo.util.Event();
6536 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6537 * @param {Function} fn The method the event invokes
6538 * @param {Object} scope An object that becomes the scope of the handler
6539 * @param {boolean} override If true, the obj passed in becomes
6540 * the execution scope of the listener
6544 Roo.onReady = Roo.EventManager.onDocumentReady;
6546 Roo.onReady(function(){
6547 var bd = Roo.get(document.body);
6552 : Roo.isGecko ? "roo-gecko"
6553 : Roo.isOpera ? "roo-opera"
6554 : Roo.isSafari ? "roo-safari" : ""];
6557 cls.push("roo-mac");
6560 cls.push("roo-linux");
6562 if(Roo.isBorderBox){
6563 cls.push('roo-border-box');
6565 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6566 var p = bd.dom.parentNode;
6568 p.className += ' roo-strict';
6571 bd.addClass(cls.join(' '));
6575 * @class Roo.EventObject
6576 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6577 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6580 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6582 var target = e.getTarget();
6585 var myDiv = Roo.get("myDiv");
6586 myDiv.on("click", handleClick);
6588 Roo.EventManager.on("myDiv", 'click', handleClick);
6589 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6593 Roo.EventObject = function(){
6595 var E = Roo.lib.Event;
6597 // safari keypress events for special keys return bad keycodes
6600 63235 : 39, // right
6603 63276 : 33, // page up
6604 63277 : 34, // page down
6605 63272 : 46, // delete
6610 // normalize button clicks
6611 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6612 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6614 Roo.EventObjectImpl = function(e){
6616 this.setEvent(e.browserEvent || e);
6619 Roo.EventObjectImpl.prototype = {
6621 * Used to fix doc tools.
6622 * @scope Roo.EventObject.prototype
6628 /** The normal browser event */
6629 browserEvent : null,
6630 /** The button pressed in a mouse event */
6632 /** True if the shift key was down during the event */
6634 /** True if the control key was down during the event */
6636 /** True if the alt key was down during the event */
6695 setEvent : function(e){
6696 if(e == this || (e && e.browserEvent)){ // already wrapped
6699 this.browserEvent = e;
6701 // normalize buttons
6702 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6703 if(e.type == 'click' && this.button == -1){
6707 this.shiftKey = e.shiftKey;
6708 // mac metaKey behaves like ctrlKey
6709 this.ctrlKey = e.ctrlKey || e.metaKey;
6710 this.altKey = e.altKey;
6711 // in getKey these will be normalized for the mac
6712 this.keyCode = e.keyCode;
6713 // keyup warnings on firefox.
6714 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6715 // cache the target for the delayed and or buffered events
6716 this.target = E.getTarget(e);
6718 this.xy = E.getXY(e);
6721 this.shiftKey = false;
6722 this.ctrlKey = false;
6723 this.altKey = false;
6733 * Stop the event (preventDefault and stopPropagation)
6735 stopEvent : function(){
6736 if(this.browserEvent){
6737 if(this.browserEvent.type == 'mousedown'){
6738 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6740 E.stopEvent(this.browserEvent);
6745 * Prevents the browsers default handling of the event.
6747 preventDefault : function(){
6748 if(this.browserEvent){
6749 E.preventDefault(this.browserEvent);
6754 isNavKeyPress : function(){
6755 var k = this.keyCode;
6756 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6757 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6760 isSpecialKey : function(){
6761 var k = this.keyCode;
6762 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6763 (k == 16) || (k == 17) ||
6764 (k >= 18 && k <= 20) ||
6765 (k >= 33 && k <= 35) ||
6766 (k >= 36 && k <= 39) ||
6767 (k >= 44 && k <= 45);
6770 * Cancels bubbling of the event.
6772 stopPropagation : function(){
6773 if(this.browserEvent){
6774 if(this.type == 'mousedown'){
6775 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6777 E.stopPropagation(this.browserEvent);
6782 * Gets the key code for the event.
6785 getCharCode : function(){
6786 return this.charCode || this.keyCode;
6790 * Returns a normalized keyCode for the event.
6791 * @return {Number} The key code
6793 getKey : function(){
6794 var k = this.keyCode || this.charCode;
6795 return Roo.isSafari ? (safariKeys[k] || k) : k;
6799 * Gets the x coordinate of the event.
6802 getPageX : function(){
6807 * Gets the y coordinate of the event.
6810 getPageY : function(){
6815 * Gets the time of the event.
6818 getTime : function(){
6819 if(this.browserEvent){
6820 return E.getTime(this.browserEvent);
6826 * Gets the page coordinates of the event.
6827 * @return {Array} The xy values like [x, y]
6834 * Gets the target for the event.
6835 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6836 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6837 search as a number or element (defaults to 10 || document.body)
6838 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6839 * @return {HTMLelement}
6841 getTarget : function(selector, maxDepth, returnEl){
6842 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6845 * Gets the related target.
6846 * @return {HTMLElement}
6848 getRelatedTarget : function(){
6849 if(this.browserEvent){
6850 return E.getRelatedTarget(this.browserEvent);
6856 * Normalizes mouse wheel delta across browsers
6857 * @return {Number} The delta
6859 getWheelDelta : function(){
6860 var e = this.browserEvent;
6862 if(e.wheelDelta){ /* IE/Opera. */
6863 delta = e.wheelDelta/120;
6864 }else if(e.detail){ /* Mozilla case. */
6865 delta = -e.detail/3;
6871 * Returns true if the control, meta, shift or alt key was pressed during this event.
6874 hasModifier : function(){
6875 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6879 * Returns true if the target of this event equals el or is a child of el
6880 * @param {String/HTMLElement/Element} el
6881 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6884 within : function(el, related){
6885 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6886 return t && Roo.fly(el).contains(t);
6889 getPoint : function(){
6890 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6894 return new Roo.EventObjectImpl();
6899 * Ext JS Library 1.1.1
6900 * Copyright(c) 2006-2007, Ext JS, LLC.
6902 * Originally Released Under LGPL - original licence link has changed is not relivant.
6905 * <script type="text/javascript">
6909 // was in Composite Element!??!?!
6912 var D = Roo.lib.Dom;
6913 var E = Roo.lib.Event;
6914 var A = Roo.lib.Anim;
6916 // local style camelizing for speed
6918 var camelRe = /(-[a-z])/gi;
6919 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6920 var view = document.defaultView;
6923 * @class Roo.Element
6924 * Represents an Element in the DOM.<br><br>
6927 var el = Roo.get("my-div");
6930 var el = getEl("my-div");
6932 // or with a DOM element
6933 var el = Roo.get(myDivElement);
6935 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6936 * each call instead of constructing a new one.<br><br>
6937 * <b>Animations</b><br />
6938 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6939 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6941 Option Default Description
6942 --------- -------- ---------------------------------------------
6943 duration .35 The duration of the animation in seconds
6944 easing easeOut The YUI easing method
6945 callback none A function to execute when the anim completes
6946 scope this The scope (this) of the callback function
6948 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6949 * manipulate the animation. Here's an example:
6951 var el = Roo.get("my-div");
6956 // default animation
6957 el.setWidth(100, true);
6959 // animation with some options set
6966 // using the "anim" property to get the Anim object
6972 el.setWidth(100, opt);
6974 if(opt.anim.isAnimated()){
6978 * <b> Composite (Collections of) Elements</b><br />
6979 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6980 * @constructor Create a new Element directly.
6981 * @param {String/HTMLElement} element
6982 * @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).
6984 Roo.Element = function(element, forceNew){
6985 var dom = typeof element == "string" ?
6986 document.getElementById(element) : element;
6987 if(!dom){ // invalid id/element
6991 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6992 return Roo.Element.cache[id];
7002 * The DOM element ID
7005 this.id = id || Roo.id(dom);
7008 var El = Roo.Element;
7012 * The element's default display mode (defaults to "")
7015 originalDisplay : "",
7019 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7024 * Sets the element's visibility mode. When setVisible() is called it
7025 * will use this to determine whether to set the visibility or the display property.
7026 * @param visMode Element.VISIBILITY or Element.DISPLAY
7027 * @return {Roo.Element} this
7029 setVisibilityMode : function(visMode){
7030 this.visibilityMode = visMode;
7034 * Convenience method for setVisibilityMode(Element.DISPLAY)
7035 * @param {String} display (optional) What to set display to when visible
7036 * @return {Roo.Element} this
7038 enableDisplayMode : function(display){
7039 this.setVisibilityMode(El.DISPLAY);
7040 if(typeof display != "undefined") this.originalDisplay = display;
7045 * 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)
7046 * @param {String} selector The simple selector to test
7047 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7048 search as a number or element (defaults to 10 || document.body)
7049 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7050 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7052 findParent : function(simpleSelector, maxDepth, returnEl){
7053 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7054 maxDepth = maxDepth || 50;
7055 if(typeof maxDepth != "number"){
7056 stopEl = Roo.getDom(maxDepth);
7059 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7060 if(dq.is(p, simpleSelector)){
7061 return returnEl ? Roo.get(p) : p;
7071 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7072 * @param {String} selector The simple selector to test
7073 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7074 search as a number or element (defaults to 10 || document.body)
7075 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7076 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7078 findParentNode : function(simpleSelector, maxDepth, returnEl){
7079 var p = Roo.fly(this.dom.parentNode, '_internal');
7080 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7084 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7085 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7086 * @param {String} selector The simple selector to test
7087 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7088 search as a number or element (defaults to 10 || document.body)
7089 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7091 up : function(simpleSelector, maxDepth){
7092 return this.findParentNode(simpleSelector, maxDepth, true);
7098 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7099 * @param {String} selector The simple selector to test
7100 * @return {Boolean} True if this element matches the selector, else false
7102 is : function(simpleSelector){
7103 return Roo.DomQuery.is(this.dom, simpleSelector);
7107 * Perform animation on this element.
7108 * @param {Object} args The YUI animation control args
7109 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7110 * @param {Function} onComplete (optional) Function to call when animation completes
7111 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7112 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7113 * @return {Roo.Element} this
7115 animate : function(args, duration, onComplete, easing, animType){
7116 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7121 * @private Internal animation call
7123 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7124 animType = animType || 'run';
7126 var anim = Roo.lib.Anim[animType](
7128 (opt.duration || defaultDur) || .35,
7129 (opt.easing || defaultEase) || 'easeOut',
7131 Roo.callback(cb, this);
7132 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7140 // private legacy anim prep
7141 preanim : function(a, i){
7142 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7146 * Removes worthless text nodes
7147 * @param {Boolean} forceReclean (optional) By default the element
7148 * keeps track if it has been cleaned already so
7149 * you can call this over and over. However, if you update the element and
7150 * need to force a reclean, you can pass true.
7152 clean : function(forceReclean){
7153 if(this.isCleaned && forceReclean !== true){
7157 var d = this.dom, n = d.firstChild, ni = -1;
7159 var nx = n.nextSibling;
7160 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7167 this.isCleaned = true;
7172 calcOffsetsTo : function(el){
7175 var restorePos = false;
7176 if(el.getStyle('position') == 'static'){
7177 el.position('relative');
7182 while(op && op != d && op.tagName != 'HTML'){
7185 op = op.offsetParent;
7188 el.position('static');
7194 * Scrolls this element into view within the passed container.
7195 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7196 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7197 * @return {Roo.Element} this
7199 scrollIntoView : function(container, hscroll){
7200 var c = Roo.getDom(container) || document.body;
7203 var o = this.calcOffsetsTo(c),
7206 b = t+el.offsetHeight,
7207 r = l+el.offsetWidth;
7209 var ch = c.clientHeight;
7210 var ct = parseInt(c.scrollTop, 10);
7211 var cl = parseInt(c.scrollLeft, 10);
7213 var cr = cl + c.clientWidth;
7221 if(hscroll !== false){
7225 c.scrollLeft = r-c.clientWidth;
7232 scrollChildIntoView : function(child, hscroll){
7233 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7237 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7238 * the new height may not be available immediately.
7239 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7240 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7241 * @param {Function} onComplete (optional) Function to call when animation completes
7242 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7243 * @return {Roo.Element} this
7245 autoHeight : function(animate, duration, onComplete, easing){
7246 var oldHeight = this.getHeight();
7248 this.setHeight(1); // force clipping
7249 setTimeout(function(){
7250 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7252 this.setHeight(height);
7254 if(typeof onComplete == "function"){
7258 this.setHeight(oldHeight); // restore original height
7259 this.setHeight(height, animate, duration, function(){
7261 if(typeof onComplete == "function") onComplete();
7262 }.createDelegate(this), easing);
7264 }.createDelegate(this), 0);
7269 * Returns true if this element is an ancestor of the passed element
7270 * @param {HTMLElement/String} el The element to check
7271 * @return {Boolean} True if this element is an ancestor of el, else false
7273 contains : function(el){
7274 if(!el){return false;}
7275 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7279 * Checks whether the element is currently visible using both visibility and display properties.
7280 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7281 * @return {Boolean} True if the element is currently visible, else false
7283 isVisible : function(deep) {
7284 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7285 if(deep !== true || !vis){
7288 var p = this.dom.parentNode;
7289 while(p && p.tagName.toLowerCase() != "body"){
7290 if(!Roo.fly(p, '_isVisible').isVisible()){
7299 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7300 * @param {String} selector The CSS selector
7301 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7302 * @return {CompositeElement/CompositeElementLite} The composite element
7304 select : function(selector, unique){
7305 return El.select(selector, unique, this.dom);
7309 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7310 * @param {String} selector The CSS selector
7311 * @return {Array} An array of the matched nodes
7313 query : function(selector, unique){
7314 return Roo.DomQuery.select(selector, this.dom);
7318 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7319 * @param {String} selector The CSS selector
7320 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7321 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7323 child : function(selector, returnDom){
7324 var n = Roo.DomQuery.selectNode(selector, this.dom);
7325 return returnDom ? n : Roo.get(n);
7329 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7330 * @param {String} selector The CSS selector
7331 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7332 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7334 down : function(selector, returnDom){
7335 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7336 return returnDom ? n : Roo.get(n);
7340 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7341 * @param {String} group The group the DD object is member of
7342 * @param {Object} config The DD config object
7343 * @param {Object} overrides An object containing methods to override/implement on the DD object
7344 * @return {Roo.dd.DD} The DD object
7346 initDD : function(group, config, overrides){
7347 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7348 return Roo.apply(dd, overrides);
7352 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7353 * @param {String} group The group the DDProxy object is member of
7354 * @param {Object} config The DDProxy config object
7355 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7356 * @return {Roo.dd.DDProxy} The DDProxy object
7358 initDDProxy : function(group, config, overrides){
7359 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7360 return Roo.apply(dd, overrides);
7364 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7365 * @param {String} group The group the DDTarget object is member of
7366 * @param {Object} config The DDTarget config object
7367 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7368 * @return {Roo.dd.DDTarget} The DDTarget object
7370 initDDTarget : function(group, config, overrides){
7371 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7372 return Roo.apply(dd, overrides);
7376 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7377 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7378 * @param {Boolean} visible Whether the element is visible
7379 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7380 * @return {Roo.Element} this
7382 setVisible : function(visible, animate){
7384 if(this.visibilityMode == El.DISPLAY){
7385 this.setDisplayed(visible);
7388 this.dom.style.visibility = visible ? "visible" : "hidden";
7391 // closure for composites
7393 var visMode = this.visibilityMode;
7395 this.setOpacity(.01);
7396 this.setVisible(true);
7398 this.anim({opacity: { to: (visible?1:0) }},
7399 this.preanim(arguments, 1),
7400 null, .35, 'easeIn', function(){
7402 if(visMode == El.DISPLAY){
7403 dom.style.display = "none";
7405 dom.style.visibility = "hidden";
7407 Roo.get(dom).setOpacity(1);
7415 * Returns true if display is not "none"
7418 isDisplayed : function() {
7419 return this.getStyle("display") != "none";
7423 * Toggles the element's visibility or display, depending on visibility mode.
7424 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7425 * @return {Roo.Element} this
7427 toggle : function(animate){
7428 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7433 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7434 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7435 * @return {Roo.Element} this
7437 setDisplayed : function(value) {
7438 if(typeof value == "boolean"){
7439 value = value ? this.originalDisplay : "none";
7441 this.setStyle("display", value);
7446 * Tries to focus the element. Any exceptions are caught and ignored.
7447 * @return {Roo.Element} this
7449 focus : function() {
7457 * Tries to blur the element. Any exceptions are caught and ignored.
7458 * @return {Roo.Element} this
7468 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7469 * @param {String/Array} className The CSS class to add, or an array of classes
7470 * @return {Roo.Element} this
7472 addClass : function(className){
7473 if(className instanceof Array){
7474 for(var i = 0, len = className.length; i < len; i++) {
7475 this.addClass(className[i]);
7478 if(className && !this.hasClass(className)){
7479 this.dom.className = this.dom.className + " " + className;
7486 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7487 * @param {String/Array} className The CSS class to add, or an array of classes
7488 * @return {Roo.Element} this
7490 radioClass : function(className){
7491 var siblings = this.dom.parentNode.childNodes;
7492 for(var i = 0; i < siblings.length; i++) {
7493 var s = siblings[i];
7494 if(s.nodeType == 1){
7495 Roo.get(s).removeClass(className);
7498 this.addClass(className);
7503 * Removes one or more CSS classes from the element.
7504 * @param {String/Array} className The CSS class to remove, or an array of classes
7505 * @return {Roo.Element} this
7507 removeClass : function(className){
7508 if(!className || !this.dom.className){
7511 if(className instanceof Array){
7512 for(var i = 0, len = className.length; i < len; i++) {
7513 this.removeClass(className[i]);
7516 if(this.hasClass(className)){
7517 var re = this.classReCache[className];
7519 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7520 this.classReCache[className] = re;
7522 this.dom.className =
7523 this.dom.className.replace(re, " ");
7533 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7534 * @param {String} className The CSS class to toggle
7535 * @return {Roo.Element} this
7537 toggleClass : function(className){
7538 if(this.hasClass(className)){
7539 this.removeClass(className);
7541 this.addClass(className);
7547 * Checks if the specified CSS class exists on this element's DOM node.
7548 * @param {String} className The CSS class to check for
7549 * @return {Boolean} True if the class exists, else false
7551 hasClass : function(className){
7552 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7556 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7557 * @param {String} oldClassName The CSS class to replace
7558 * @param {String} newClassName The replacement CSS class
7559 * @return {Roo.Element} this
7561 replaceClass : function(oldClassName, newClassName){
7562 this.removeClass(oldClassName);
7563 this.addClass(newClassName);
7568 * Returns an object with properties matching the styles requested.
7569 * For example, el.getStyles('color', 'font-size', 'width') might return
7570 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7571 * @param {String} style1 A style name
7572 * @param {String} style2 A style name
7573 * @param {String} etc.
7574 * @return {Object} The style object
7576 getStyles : function(){
7577 var a = arguments, len = a.length, r = {};
7578 for(var i = 0; i < len; i++){
7579 r[a[i]] = this.getStyle(a[i]);
7585 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7586 * @param {String} property The style property whose value is returned.
7587 * @return {String} The current value of the style property for this element.
7589 getStyle : function(){
7590 return view && view.getComputedStyle ?
7592 var el = this.dom, v, cs, camel;
7593 if(prop == 'float'){
7596 if(el.style && (v = el.style[prop])){
7599 if(cs = view.getComputedStyle(el, "")){
7600 if(!(camel = propCache[prop])){
7601 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7608 var el = this.dom, v, cs, camel;
7609 if(prop == 'opacity'){
7610 if(typeof el.style.filter == 'string'){
7611 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7613 var fv = parseFloat(m[1]);
7615 return fv ? fv / 100 : 0;
7620 }else if(prop == 'float'){
7621 prop = "styleFloat";
7623 if(!(camel = propCache[prop])){
7624 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7626 if(v = el.style[camel]){
7629 if(cs = el.currentStyle){
7637 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7638 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7639 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7640 * @return {Roo.Element} this
7642 setStyle : function(prop, value){
7643 if(typeof prop == "string"){
7645 if (prop == 'float') {
7646 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7651 if(!(camel = propCache[prop])){
7652 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7655 if(camel == 'opacity') {
7656 this.setOpacity(value);
7658 this.dom.style[camel] = value;
7661 for(var style in prop){
7662 if(typeof prop[style] != "function"){
7663 this.setStyle(style, prop[style]);
7671 * More flexible version of {@link #setStyle} for setting style properties.
7672 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7673 * a function which returns such a specification.
7674 * @return {Roo.Element} this
7676 applyStyles : function(style){
7677 Roo.DomHelper.applyStyles(this.dom, style);
7682 * 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).
7683 * @return {Number} The X position of the element
7686 return D.getX(this.dom);
7690 * 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).
7691 * @return {Number} The Y position of the element
7694 return D.getY(this.dom);
7698 * 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).
7699 * @return {Array} The XY position of the element
7702 return D.getXY(this.dom);
7706 * 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).
7707 * @param {Number} The X position of the element
7708 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7709 * @return {Roo.Element} this
7711 setX : function(x, animate){
7713 D.setX(this.dom, x);
7715 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7721 * 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).
7722 * @param {Number} The Y position of the element
7723 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7724 * @return {Roo.Element} this
7726 setY : function(y, animate){
7728 D.setY(this.dom, y);
7730 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7736 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7737 * @param {String} left The left CSS property value
7738 * @return {Roo.Element} this
7740 setLeft : function(left){
7741 this.setStyle("left", this.addUnits(left));
7746 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7747 * @param {String} top The top CSS property value
7748 * @return {Roo.Element} this
7750 setTop : function(top){
7751 this.setStyle("top", this.addUnits(top));
7756 * Sets the element's CSS right style.
7757 * @param {String} right The right CSS property value
7758 * @return {Roo.Element} this
7760 setRight : function(right){
7761 this.setStyle("right", this.addUnits(right));
7766 * Sets the element's CSS bottom style.
7767 * @param {String} bottom The bottom CSS property value
7768 * @return {Roo.Element} this
7770 setBottom : function(bottom){
7771 this.setStyle("bottom", this.addUnits(bottom));
7776 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7777 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7778 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7779 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7780 * @return {Roo.Element} this
7782 setXY : function(pos, animate){
7784 D.setXY(this.dom, pos);
7786 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7792 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7793 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7794 * @param {Number} x X value for new position (coordinates are page-based)
7795 * @param {Number} y Y value for new position (coordinates are page-based)
7796 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7797 * @return {Roo.Element} this
7799 setLocation : function(x, y, animate){
7800 this.setXY([x, y], this.preanim(arguments, 2));
7805 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7806 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7807 * @param {Number} x X value for new position (coordinates are page-based)
7808 * @param {Number} y Y value for new position (coordinates are page-based)
7809 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7810 * @return {Roo.Element} this
7812 moveTo : function(x, y, animate){
7813 this.setXY([x, y], this.preanim(arguments, 2));
7818 * Returns the region of the given element.
7819 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7820 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7822 getRegion : function(){
7823 return D.getRegion(this.dom);
7827 * Returns the offset height of the element
7828 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7829 * @return {Number} The element's height
7831 getHeight : function(contentHeight){
7832 var h = this.dom.offsetHeight || 0;
7833 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7837 * Returns the offset width of the element
7838 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7839 * @return {Number} The element's width
7841 getWidth : function(contentWidth){
7842 var w = this.dom.offsetWidth || 0;
7843 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7847 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7848 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7849 * if a height has not been set using CSS.
7852 getComputedHeight : function(){
7853 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7855 h = parseInt(this.getStyle('height'), 10) || 0;
7856 if(!this.isBorderBox()){
7857 h += this.getFrameWidth('tb');
7864 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7865 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7866 * if a width has not been set using CSS.
7869 getComputedWidth : function(){
7870 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7872 w = parseInt(this.getStyle('width'), 10) || 0;
7873 if(!this.isBorderBox()){
7874 w += this.getFrameWidth('lr');
7881 * Returns the size of the element.
7882 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7883 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7885 getSize : function(contentSize){
7886 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7890 * Returns the width and height of the viewport.
7891 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7893 getViewSize : function(){
7894 var d = this.dom, doc = document, aw = 0, ah = 0;
7895 if(d == doc || d == doc.body){
7896 return {width : D.getViewWidth(), height: D.getViewHeight()};
7899 width : d.clientWidth,
7900 height: d.clientHeight
7906 * Returns the value of the "value" attribute
7907 * @param {Boolean} asNumber true to parse the value as a number
7908 * @return {String/Number}
7910 getValue : function(asNumber){
7911 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7915 adjustWidth : function(width){
7916 if(typeof width == "number"){
7917 if(this.autoBoxAdjust && !this.isBorderBox()){
7918 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7928 adjustHeight : function(height){
7929 if(typeof height == "number"){
7930 if(this.autoBoxAdjust && !this.isBorderBox()){
7931 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7941 * Set the width of the element
7942 * @param {Number} width The new width
7943 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7944 * @return {Roo.Element} this
7946 setWidth : function(width, animate){
7947 width = this.adjustWidth(width);
7949 this.dom.style.width = this.addUnits(width);
7951 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7957 * Set the height of the element
7958 * @param {Number} height The new height
7959 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7960 * @return {Roo.Element} this
7962 setHeight : function(height, animate){
7963 height = this.adjustHeight(height);
7965 this.dom.style.height = this.addUnits(height);
7967 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7973 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7974 * @param {Number} width The new width
7975 * @param {Number} height The new height
7976 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7977 * @return {Roo.Element} this
7979 setSize : function(width, height, animate){
7980 if(typeof width == "object"){ // in case of object from getSize()
7981 height = width.height; width = width.width;
7983 width = this.adjustWidth(width); height = this.adjustHeight(height);
7985 this.dom.style.width = this.addUnits(width);
7986 this.dom.style.height = this.addUnits(height);
7988 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7994 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7995 * @param {Number} x X value for new position (coordinates are page-based)
7996 * @param {Number} y Y value for new position (coordinates are page-based)
7997 * @param {Number} width The new width
7998 * @param {Number} height The new height
7999 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8000 * @return {Roo.Element} this
8002 setBounds : function(x, y, width, height, animate){
8004 this.setSize(width, height);
8005 this.setLocation(x, y);
8007 width = this.adjustWidth(width); height = this.adjustHeight(height);
8008 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8009 this.preanim(arguments, 4), 'motion');
8015 * 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.
8016 * @param {Roo.lib.Region} region The region to fill
8017 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8018 * @return {Roo.Element} this
8020 setRegion : function(region, animate){
8021 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8026 * Appends an event handler
8028 * @param {String} eventName The type of event to append
8029 * @param {Function} fn The method the event invokes
8030 * @param {Object} scope (optional) The scope (this object) of the fn
8031 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8033 addListener : function(eventName, fn, scope, options){
8035 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8040 * Removes an event handler from this element
8041 * @param {String} eventName the type of event to remove
8042 * @param {Function} fn the method the event invokes
8043 * @return {Roo.Element} this
8045 removeListener : function(eventName, fn){
8046 Roo.EventManager.removeListener(this.dom, eventName, fn);
8051 * Removes all previous added listeners from this element
8052 * @return {Roo.Element} this
8054 removeAllListeners : function(){
8055 E.purgeElement(this.dom);
8059 relayEvent : function(eventName, observable){
8060 this.on(eventName, function(e){
8061 observable.fireEvent(eventName, e);
8066 * Set the opacity of the element
8067 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8068 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8069 * @return {Roo.Element} this
8071 setOpacity : function(opacity, animate){
8073 var s = this.dom.style;
8076 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8077 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8079 s.opacity = opacity;
8082 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8088 * Gets the left X coordinate
8089 * @param {Boolean} local True to get the local css position instead of page coordinate
8092 getLeft : function(local){
8096 return parseInt(this.getStyle("left"), 10) || 0;
8101 * Gets the right X coordinate of the element (element X position + element width)
8102 * @param {Boolean} local True to get the local css position instead of page coordinate
8105 getRight : function(local){
8107 return this.getX() + this.getWidth();
8109 return (this.getLeft(true) + this.getWidth()) || 0;
8114 * Gets the top Y coordinate
8115 * @param {Boolean} local True to get the local css position instead of page coordinate
8118 getTop : function(local) {
8122 return parseInt(this.getStyle("top"), 10) || 0;
8127 * Gets the bottom Y coordinate of the element (element Y position + element height)
8128 * @param {Boolean} local True to get the local css position instead of page coordinate
8131 getBottom : function(local){
8133 return this.getY() + this.getHeight();
8135 return (this.getTop(true) + this.getHeight()) || 0;
8140 * Initializes positioning on this element. If a desired position is not passed, it will make the
8141 * the element positioned relative IF it is not already positioned.
8142 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8143 * @param {Number} zIndex (optional) The zIndex to apply
8144 * @param {Number} x (optional) Set the page X position
8145 * @param {Number} y (optional) Set the page Y position
8147 position : function(pos, zIndex, x, y){
8149 if(this.getStyle('position') == 'static'){
8150 this.setStyle('position', 'relative');
8153 this.setStyle("position", pos);
8156 this.setStyle("z-index", zIndex);
8158 if(x !== undefined && y !== undefined){
8160 }else if(x !== undefined){
8162 }else if(y !== undefined){
8168 * Clear positioning back to the default when the document was loaded
8169 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8170 * @return {Roo.Element} this
8172 clearPositioning : function(value){
8180 "position" : "static"
8186 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8187 * snapshot before performing an update and then restoring the element.
8190 getPositioning : function(){
8191 var l = this.getStyle("left");
8192 var t = this.getStyle("top");
8194 "position" : this.getStyle("position"),
8196 "right" : l ? "" : this.getStyle("right"),
8198 "bottom" : t ? "" : this.getStyle("bottom"),
8199 "z-index" : this.getStyle("z-index")
8204 * Gets the width of the border(s) for the specified side(s)
8205 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8206 * passing lr would get the border (l)eft width + the border (r)ight width.
8207 * @return {Number} The width of the sides passed added together
8209 getBorderWidth : function(side){
8210 return this.addStyles(side, El.borders);
8214 * Gets the width of the padding(s) for the specified side(s)
8215 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8216 * passing lr would get the padding (l)eft + the padding (r)ight.
8217 * @return {Number} The padding of the sides passed added together
8219 getPadding : function(side){
8220 return this.addStyles(side, El.paddings);
8224 * Set positioning with an object returned by getPositioning().
8225 * @param {Object} posCfg
8226 * @return {Roo.Element} this
8228 setPositioning : function(pc){
8229 this.applyStyles(pc);
8230 if(pc.right == "auto"){
8231 this.dom.style.right = "";
8233 if(pc.bottom == "auto"){
8234 this.dom.style.bottom = "";
8240 fixDisplay : function(){
8241 if(this.getStyle("display") == "none"){
8242 this.setStyle("visibility", "hidden");
8243 this.setStyle("display", this.originalDisplay); // first try reverting to default
8244 if(this.getStyle("display") == "none"){ // if that fails, default to block
8245 this.setStyle("display", "block");
8251 * Quick set left and top adding default units
8252 * @param {String} left The left CSS property value
8253 * @param {String} top The top CSS property value
8254 * @return {Roo.Element} this
8256 setLeftTop : function(left, top){
8257 this.dom.style.left = this.addUnits(left);
8258 this.dom.style.top = this.addUnits(top);
8263 * Move this element relative to its current position.
8264 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8265 * @param {Number} distance How far to move the element in pixels
8266 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8267 * @return {Roo.Element} this
8269 move : function(direction, distance, animate){
8270 var xy = this.getXY();
8271 direction = direction.toLowerCase();
8275 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8279 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8284 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8289 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8296 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8297 * @return {Roo.Element} this
8300 if(!this.isClipped){
8301 this.isClipped = true;
8302 this.originalClip = {
8303 "o": this.getStyle("overflow"),
8304 "x": this.getStyle("overflow-x"),
8305 "y": this.getStyle("overflow-y")
8307 this.setStyle("overflow", "hidden");
8308 this.setStyle("overflow-x", "hidden");
8309 this.setStyle("overflow-y", "hidden");
8315 * Return clipping (overflow) to original clipping before clip() was called
8316 * @return {Roo.Element} this
8318 unclip : function(){
8320 this.isClipped = false;
8321 var o = this.originalClip;
8322 if(o.o){this.setStyle("overflow", o.o);}
8323 if(o.x){this.setStyle("overflow-x", o.x);}
8324 if(o.y){this.setStyle("overflow-y", o.y);}
8331 * Gets the x,y coordinates specified by the anchor position on the element.
8332 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8333 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8334 * {width: (target width), height: (target height)} (defaults to the element's current size)
8335 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8336 * @return {Array} [x, y] An array containing the element's x and y coordinates
8338 getAnchorXY : function(anchor, local, s){
8339 //Passing a different size is useful for pre-calculating anchors,
8340 //especially for anchored animations that change the el size.
8342 var w, h, vp = false;
8345 if(d == document.body || d == document){
8347 w = D.getViewWidth(); h = D.getViewHeight();
8349 w = this.getWidth(); h = this.getHeight();
8352 w = s.width; h = s.height;
8354 var x = 0, y = 0, r = Math.round;
8355 switch((anchor || "tl").toLowerCase()){
8397 var sc = this.getScroll();
8398 return [x + sc.left, y + sc.top];
8400 //Add the element's offset xy
8401 var o = this.getXY();
8402 return [x+o[0], y+o[1]];
8406 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8407 * supported position values.
8408 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8409 * @param {String} position The position to align to.
8410 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8411 * @return {Array} [x, y]
8413 getAlignToXY : function(el, p, o){
8417 throw "Element.alignTo with an element that doesn't exist";
8419 var c = false; //constrain to viewport
8420 var p1 = "", p2 = "";
8427 }else if(p.indexOf("-") == -1){
8430 p = p.toLowerCase();
8431 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8433 throw "Element.alignTo with an invalid alignment " + p;
8435 p1 = m[1]; p2 = m[2]; c = !!m[3];
8437 //Subtract the aligned el's internal xy from the target's offset xy
8438 //plus custom offset to get the aligned el's new offset xy
8439 var a1 = this.getAnchorXY(p1, true);
8440 var a2 = el.getAnchorXY(p2, false);
8441 var x = a2[0] - a1[0] + o[0];
8442 var y = a2[1] - a1[1] + o[1];
8444 //constrain the aligned el to viewport if necessary
8445 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8446 // 5px of margin for ie
8447 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8449 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8450 //perpendicular to the vp border, allow the aligned el to slide on that border,
8451 //otherwise swap the aligned el to the opposite border of the target.
8452 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8453 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8454 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8455 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8458 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8459 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8461 if((x+w) > dw + scrollX){
8462 x = swapX ? r.left-w : dw+scrollX-w;
8465 x = swapX ? r.right : scrollX;
8467 if((y+h) > dh + scrollY){
8468 y = swapY ? r.top-h : dh+scrollY-h;
8471 y = swapY ? r.bottom : scrollY;
8478 getConstrainToXY : function(){
8479 var os = {top:0, left:0, bottom:0, right: 0};
8481 return function(el, local, offsets, proposedXY){
8483 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8485 var vw, vh, vx = 0, vy = 0;
8486 if(el.dom == document.body || el.dom == document){
8487 vw = Roo.lib.Dom.getViewWidth();
8488 vh = Roo.lib.Dom.getViewHeight();
8490 vw = el.dom.clientWidth;
8491 vh = el.dom.clientHeight;
8493 var vxy = el.getXY();
8499 var s = el.getScroll();
8501 vx += offsets.left + s.left;
8502 vy += offsets.top + s.top;
8504 vw -= offsets.right;
8505 vh -= offsets.bottom;
8510 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8511 var x = xy[0], y = xy[1];
8512 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8514 // only move it if it needs it
8517 // first validate right/bottom
8526 // then make sure top/left isn't negative
8535 return moved ? [x, y] : false;
8540 adjustForConstraints : function(xy, parent, offsets){
8541 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8545 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8546 * document it aligns it to the viewport.
8547 * The position parameter is optional, and can be specified in any one of the following formats:
8549 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8550 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8551 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8552 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8553 * <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
8554 * element's anchor point, and the second value is used as the target's anchor point.</li>
8556 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8557 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8558 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8559 * that specified in order to enforce the viewport constraints.
8560 * Following are all of the supported anchor positions:
8563 ----- -----------------------------
8564 tl The top left corner (default)
8565 t The center of the top edge
8566 tr The top right corner
8567 l The center of the left edge
8568 c In the center of the element
8569 r The center of the right edge
8570 bl The bottom left corner
8571 b The center of the bottom edge
8572 br The bottom right corner
8576 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8577 el.alignTo("other-el");
8579 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8580 el.alignTo("other-el", "tr?");
8582 // align the bottom right corner of el with the center left edge of other-el
8583 el.alignTo("other-el", "br-l?");
8585 // align the center of el with the bottom left corner of other-el and
8586 // adjust the x position by -6 pixels (and the y position by 0)
8587 el.alignTo("other-el", "c-bl", [-6, 0]);
8589 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8590 * @param {String} position The position to align to.
8591 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8592 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8593 * @return {Roo.Element} this
8595 alignTo : function(element, position, offsets, animate){
8596 var xy = this.getAlignToXY(element, position, offsets);
8597 this.setXY(xy, this.preanim(arguments, 3));
8602 * Anchors an element to another element and realigns it when the window is resized.
8603 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8604 * @param {String} position The position to align to.
8605 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8606 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8607 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8608 * is a number, it is used as the buffer delay (defaults to 50ms).
8609 * @param {Function} callback The function to call after the animation finishes
8610 * @return {Roo.Element} this
8612 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8613 var action = function(){
8614 this.alignTo(el, alignment, offsets, animate);
8615 Roo.callback(callback, this);
8617 Roo.EventManager.onWindowResize(action, this);
8618 var tm = typeof monitorScroll;
8619 if(tm != 'undefined'){
8620 Roo.EventManager.on(window, 'scroll', action, this,
8621 {buffer: tm == 'number' ? monitorScroll : 50});
8623 action.call(this); // align immediately
8627 * Clears any opacity settings from this element. Required in some cases for IE.
8628 * @return {Roo.Element} this
8630 clearOpacity : function(){
8631 if (window.ActiveXObject) {
8632 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8633 this.dom.style.filter = "";
8636 this.dom.style.opacity = "";
8637 this.dom.style["-moz-opacity"] = "";
8638 this.dom.style["-khtml-opacity"] = "";
8644 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8645 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8646 * @return {Roo.Element} this
8648 hide : function(animate){
8649 this.setVisible(false, this.preanim(arguments, 0));
8654 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8655 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8656 * @return {Roo.Element} this
8658 show : function(animate){
8659 this.setVisible(true, this.preanim(arguments, 0));
8664 * @private Test if size has a unit, otherwise appends the default
8666 addUnits : function(size){
8667 return Roo.Element.addUnits(size, this.defaultUnit);
8671 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8672 * @return {Roo.Element} this
8674 beginMeasure : function(){
8676 if(el.offsetWidth || el.offsetHeight){
8677 return this; // offsets work already
8680 var p = this.dom, b = document.body; // start with this element
8681 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8682 var pe = Roo.get(p);
8683 if(pe.getStyle('display') == 'none'){
8684 changed.push({el: p, visibility: pe.getStyle("visibility")});
8685 p.style.visibility = "hidden";
8686 p.style.display = "block";
8690 this._measureChanged = changed;
8696 * Restores displays to before beginMeasure was called
8697 * @return {Roo.Element} this
8699 endMeasure : function(){
8700 var changed = this._measureChanged;
8702 for(var i = 0, len = changed.length; i < len; i++) {
8704 r.el.style.visibility = r.visibility;
8705 r.el.style.display = "none";
8707 this._measureChanged = null;
8713 * Update the innerHTML of this element, optionally searching for and processing scripts
8714 * @param {String} html The new HTML
8715 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8716 * @param {Function} callback For async script loading you can be noticed when the update completes
8717 * @return {Roo.Element} this
8719 update : function(html, loadScripts, callback){
8720 if(typeof html == "undefined"){
8723 if(loadScripts !== true){
8724 this.dom.innerHTML = html;
8725 if(typeof callback == "function"){
8733 html += '<span id="' + id + '"></span>';
8735 E.onAvailable(id, function(){
8736 var hd = document.getElementsByTagName("head")[0];
8737 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8738 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8739 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8742 while(match = re.exec(html)){
8743 var attrs = match[1];
8744 var srcMatch = attrs ? attrs.match(srcRe) : false;
8745 if(srcMatch && srcMatch[2]){
8746 var s = document.createElement("script");
8747 s.src = srcMatch[2];
8748 var typeMatch = attrs.match(typeRe);
8749 if(typeMatch && typeMatch[2]){
8750 s.type = typeMatch[2];
8753 }else if(match[2] && match[2].length > 0){
8754 if(window.execScript) {
8755 window.execScript(match[2]);
8763 window.eval(match[2]);
8767 var el = document.getElementById(id);
8768 if(el){el.parentNode.removeChild(el);}
8769 if(typeof callback == "function"){
8773 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8778 * Direct access to the UpdateManager update() method (takes the same parameters).
8779 * @param {String/Function} url The url for this request or a function to call to get the url
8780 * @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}
8781 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8782 * @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.
8783 * @return {Roo.Element} this
8786 var um = this.getUpdateManager();
8787 um.update.apply(um, arguments);
8792 * Gets this element's UpdateManager
8793 * @return {Roo.UpdateManager} The UpdateManager
8795 getUpdateManager : function(){
8796 if(!this.updateManager){
8797 this.updateManager = new Roo.UpdateManager(this);
8799 return this.updateManager;
8803 * Disables text selection for this element (normalized across browsers)
8804 * @return {Roo.Element} this
8806 unselectable : function(){
8807 this.dom.unselectable = "on";
8808 this.swallowEvent("selectstart", true);
8809 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8810 this.addClass("x-unselectable");
8815 * Calculates the x, y to center this element on the screen
8816 * @return {Array} The x, y values [x, y]
8818 getCenterXY : function(){
8819 return this.getAlignToXY(document, 'c-c');
8823 * Centers the Element in either the viewport, or another Element.
8824 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8826 center : function(centerIn){
8827 this.alignTo(centerIn || document, 'c-c');
8832 * Tests various css rules/browsers to determine if this element uses a border box
8835 isBorderBox : function(){
8836 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8840 * Return a box {x, y, width, height} that can be used to set another elements
8841 * size/location to match this element.
8842 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8843 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8844 * @return {Object} box An object in the format {x, y, width, height}
8846 getBox : function(contentBox, local){
8851 var left = parseInt(this.getStyle("left"), 10) || 0;
8852 var top = parseInt(this.getStyle("top"), 10) || 0;
8855 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8857 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8859 var l = this.getBorderWidth("l")+this.getPadding("l");
8860 var r = this.getBorderWidth("r")+this.getPadding("r");
8861 var t = this.getBorderWidth("t")+this.getPadding("t");
8862 var b = this.getBorderWidth("b")+this.getPadding("b");
8863 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)};
8865 bx.right = bx.x + bx.width;
8866 bx.bottom = bx.y + bx.height;
8871 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8872 for more information about the sides.
8873 * @param {String} sides
8876 getFrameWidth : function(sides, onlyContentBox){
8877 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8881 * 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.
8882 * @param {Object} box The box to fill {x, y, width, height}
8883 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8884 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8885 * @return {Roo.Element} this
8887 setBox : function(box, adjust, animate){
8888 var w = box.width, h = box.height;
8889 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8890 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8891 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8893 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8898 * Forces the browser to repaint this element
8899 * @return {Roo.Element} this
8901 repaint : function(){
8903 this.addClass("x-repaint");
8904 setTimeout(function(){
8905 Roo.get(dom).removeClass("x-repaint");
8911 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8912 * then it returns the calculated width of the sides (see getPadding)
8913 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8914 * @return {Object/Number}
8916 getMargins : function(side){
8919 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8920 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8921 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8922 right: parseInt(this.getStyle("margin-right"), 10) || 0
8925 return this.addStyles(side, El.margins);
8930 addStyles : function(sides, styles){
8932 for(var i = 0, len = sides.length; i < len; i++){
8933 v = this.getStyle(styles[sides.charAt(i)]);
8935 w = parseInt(v, 10);
8943 * Creates a proxy element of this element
8944 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8945 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8946 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8947 * @return {Roo.Element} The new proxy element
8949 createProxy : function(config, renderTo, matchBox){
8951 renderTo = Roo.getDom(renderTo);
8953 renderTo = document.body;
8955 config = typeof config == "object" ?
8956 config : {tag : "div", cls: config};
8957 var proxy = Roo.DomHelper.append(renderTo, config, true);
8959 proxy.setBox(this.getBox());
8965 * Puts a mask over this element to disable user interaction. Requires core.css.
8966 * This method can only be applied to elements which accept child nodes.
8967 * @param {String} msg (optional) A message to display in the mask
8968 * @param {String} msgCls (optional) A css class to apply to the msg element
8969 * @return {Element} The mask element
8971 mask : function(msg, msgCls)
8973 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8974 this.setStyle("position", "relative");
8977 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8979 this.addClass("x-masked");
8980 this._mask.setDisplayed(true);
8985 while (dom && dom.style) {
8986 if (!isNaN(parseInt(dom.style.zIndex))) {
8987 z = Math.max(z, parseInt(dom.style.zIndex));
8989 dom = dom.parentNode;
8991 // if we are masking the body - then it hides everything..
8992 if (this.dom == document.body) {
8994 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8995 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8998 if(typeof msg == 'string'){
9000 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9002 var mm = this._maskMsg;
9003 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9004 mm.dom.firstChild.innerHTML = msg;
9005 mm.setDisplayed(true);
9007 mm.setStyle('z-index', z + 102);
9009 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9010 this._mask.setHeight(this.getHeight());
9012 this._mask.setStyle('z-index', z + 100);
9018 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9019 * it is cached for reuse.
9021 unmask : function(removeEl){
9023 if(removeEl === true){
9024 this._mask.remove();
9027 this._maskMsg.remove();
9028 delete this._maskMsg;
9031 this._mask.setDisplayed(false);
9033 this._maskMsg.setDisplayed(false);
9037 this.removeClass("x-masked");
9041 * Returns true if this element is masked
9044 isMasked : function(){
9045 return this._mask && this._mask.isVisible();
9049 * Creates an iframe shim for this element to keep selects and other windowed objects from
9051 * @return {Roo.Element} The new shim element
9053 createShim : function(){
9054 var el = document.createElement('iframe');
9055 el.frameBorder = 'no';
9056 el.className = 'roo-shim';
9057 if(Roo.isIE && Roo.isSecure){
9058 el.src = Roo.SSL_SECURE_URL;
9060 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9061 shim.autoBoxAdjust = false;
9066 * Removes this element from the DOM and deletes it from the cache
9068 remove : function(){
9069 if(this.dom.parentNode){
9070 this.dom.parentNode.removeChild(this.dom);
9072 delete El.cache[this.dom.id];
9076 * Sets up event handlers to add and remove a css class when the mouse is over this element
9077 * @param {String} className
9078 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9079 * mouseout events for children elements
9080 * @return {Roo.Element} this
9082 addClassOnOver : function(className, preventFlicker){
9083 this.on("mouseover", function(){
9084 Roo.fly(this, '_internal').addClass(className);
9086 var removeFn = function(e){
9087 if(preventFlicker !== true || !e.within(this, true)){
9088 Roo.fly(this, '_internal').removeClass(className);
9091 this.on("mouseout", removeFn, this.dom);
9096 * Sets up event handlers to add and remove a css class when this element has the focus
9097 * @param {String} className
9098 * @return {Roo.Element} this
9100 addClassOnFocus : function(className){
9101 this.on("focus", function(){
9102 Roo.fly(this, '_internal').addClass(className);
9104 this.on("blur", function(){
9105 Roo.fly(this, '_internal').removeClass(className);
9110 * 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)
9111 * @param {String} className
9112 * @return {Roo.Element} this
9114 addClassOnClick : function(className){
9116 this.on("mousedown", function(){
9117 Roo.fly(dom, '_internal').addClass(className);
9118 var d = Roo.get(document);
9119 var fn = function(){
9120 Roo.fly(dom, '_internal').removeClass(className);
9121 d.removeListener("mouseup", fn);
9123 d.on("mouseup", fn);
9129 * Stops the specified event from bubbling and optionally prevents the default action
9130 * @param {String} eventName
9131 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9132 * @return {Roo.Element} this
9134 swallowEvent : function(eventName, preventDefault){
9135 var fn = function(e){
9136 e.stopPropagation();
9141 if(eventName instanceof Array){
9142 for(var i = 0, len = eventName.length; i < len; i++){
9143 this.on(eventName[i], fn);
9147 this.on(eventName, fn);
9154 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9157 * Sizes this element to its parent element's dimensions performing
9158 * neccessary box adjustments.
9159 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9160 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9161 * @return {Roo.Element} this
9163 fitToParent : function(monitorResize, targetParent) {
9164 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9165 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9166 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9169 var p = Roo.get(targetParent || this.dom.parentNode);
9170 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9171 if (monitorResize === true) {
9172 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9173 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9179 * Gets the next sibling, skipping text nodes
9180 * @return {HTMLElement} The next sibling or null
9182 getNextSibling : function(){
9183 var n = this.dom.nextSibling;
9184 while(n && n.nodeType != 1){
9191 * Gets the previous sibling, skipping text nodes
9192 * @return {HTMLElement} The previous sibling or null
9194 getPrevSibling : function(){
9195 var n = this.dom.previousSibling;
9196 while(n && n.nodeType != 1){
9197 n = n.previousSibling;
9204 * Appends the passed element(s) to this element
9205 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9206 * @return {Roo.Element} this
9208 appendChild: function(el){
9215 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9216 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9217 * automatically generated with the specified attributes.
9218 * @param {HTMLElement} insertBefore (optional) a child element of this element
9219 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9220 * @return {Roo.Element} The new child element
9222 createChild: function(config, insertBefore, returnDom){
9223 config = config || {tag:'div'};
9225 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9227 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9231 * Appends this element to the passed element
9232 * @param {String/HTMLElement/Element} el The new parent element
9233 * @return {Roo.Element} this
9235 appendTo: function(el){
9236 el = Roo.getDom(el);
9237 el.appendChild(this.dom);
9242 * Inserts this element before the passed element in the DOM
9243 * @param {String/HTMLElement/Element} el The element to insert before
9244 * @return {Roo.Element} this
9246 insertBefore: function(el){
9247 el = Roo.getDom(el);
9248 el.parentNode.insertBefore(this.dom, el);
9253 * Inserts this element after the passed element in the DOM
9254 * @param {String/HTMLElement/Element} el The element to insert after
9255 * @return {Roo.Element} this
9257 insertAfter: function(el){
9258 el = Roo.getDom(el);
9259 el.parentNode.insertBefore(this.dom, el.nextSibling);
9264 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9265 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9266 * @return {Roo.Element} The new child
9268 insertFirst: function(el, returnDom){
9270 if(typeof el == 'object' && !el.nodeType){ // dh config
9271 return this.createChild(el, this.dom.firstChild, returnDom);
9273 el = Roo.getDom(el);
9274 this.dom.insertBefore(el, this.dom.firstChild);
9275 return !returnDom ? Roo.get(el) : el;
9280 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9281 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9282 * @param {String} where (optional) 'before' or 'after' defaults to before
9283 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9284 * @return {Roo.Element} the inserted Element
9286 insertSibling: function(el, where, returnDom){
9287 where = where ? where.toLowerCase() : 'before';
9289 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9291 if(typeof el == 'object' && !el.nodeType){ // dh config
9292 if(where == 'after' && !this.dom.nextSibling){
9293 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9295 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9299 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9300 where == 'before' ? this.dom : this.dom.nextSibling);
9309 * Creates and wraps this element with another element
9310 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9311 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9312 * @return {HTMLElement/Element} The newly created wrapper element
9314 wrap: function(config, returnDom){
9316 config = {tag: "div"};
9318 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9319 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9324 * Replaces the passed element with this element
9325 * @param {String/HTMLElement/Element} el The element to replace
9326 * @return {Roo.Element} this
9328 replace: function(el){
9330 this.insertBefore(el);
9336 * Inserts an html fragment into this element
9337 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9338 * @param {String} html The HTML fragment
9339 * @param {Boolean} returnEl True to return an Roo.Element
9340 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9342 insertHtml : function(where, html, returnEl){
9343 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9344 return returnEl ? Roo.get(el) : el;
9348 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9349 * @param {Object} o The object with the attributes
9350 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9351 * @return {Roo.Element} this
9353 set : function(o, useSet){
9355 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9357 if(attr == "style" || typeof o[attr] == "function") continue;
9359 el.className = o["cls"];
9361 if(useSet) el.setAttribute(attr, o[attr]);
9362 else el[attr] = o[attr];
9366 Roo.DomHelper.applyStyles(el, o.style);
9372 * Convenience method for constructing a KeyMap
9373 * @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:
9374 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9375 * @param {Function} fn The function to call
9376 * @param {Object} scope (optional) The scope of the function
9377 * @return {Roo.KeyMap} The KeyMap created
9379 addKeyListener : function(key, fn, scope){
9381 if(typeof key != "object" || key instanceof Array){
9397 return new Roo.KeyMap(this, config);
9401 * Creates a KeyMap for this element
9402 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9403 * @return {Roo.KeyMap} The KeyMap created
9405 addKeyMap : function(config){
9406 return new Roo.KeyMap(this, config);
9410 * Returns true if this element is scrollable.
9413 isScrollable : function(){
9415 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9419 * 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().
9420 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9421 * @param {Number} value The new scroll value
9422 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9423 * @return {Element} this
9426 scrollTo : function(side, value, animate){
9427 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9429 this.dom[prop] = value;
9431 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9432 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9438 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9439 * within this element's scrollable range.
9440 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9441 * @param {Number} distance How far to scroll the element in pixels
9442 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9443 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9444 * was scrolled as far as it could go.
9446 scroll : function(direction, distance, animate){
9447 if(!this.isScrollable()){
9451 var l = el.scrollLeft, t = el.scrollTop;
9452 var w = el.scrollWidth, h = el.scrollHeight;
9453 var cw = el.clientWidth, ch = el.clientHeight;
9454 direction = direction.toLowerCase();
9455 var scrolled = false;
9456 var a = this.preanim(arguments, 2);
9461 var v = Math.min(l + distance, w-cw);
9462 this.scrollTo("left", v, a);
9469 var v = Math.max(l - distance, 0);
9470 this.scrollTo("left", v, a);
9478 var v = Math.max(t - distance, 0);
9479 this.scrollTo("top", v, a);
9487 var v = Math.min(t + distance, h-ch);
9488 this.scrollTo("top", v, a);
9497 * Translates the passed page coordinates into left/top css values for this element
9498 * @param {Number/Array} x The page x or an array containing [x, y]
9499 * @param {Number} y The page y
9500 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9502 translatePoints : function(x, y){
9503 if(typeof x == 'object' || x instanceof Array){
9506 var p = this.getStyle('position');
9507 var o = this.getXY();
9509 var l = parseInt(this.getStyle('left'), 10);
9510 var t = parseInt(this.getStyle('top'), 10);
9513 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9516 t = (p == "relative") ? 0 : this.dom.offsetTop;
9519 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9523 * Returns the current scroll position of the element.
9524 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9526 getScroll : function(){
9527 var d = this.dom, doc = document;
9528 if(d == doc || d == doc.body){
9529 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9530 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9531 return {left: l, top: t};
9533 return {left: d.scrollLeft, top: d.scrollTop};
9538 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9539 * are convert to standard 6 digit hex color.
9540 * @param {String} attr The css attribute
9541 * @param {String} defaultValue The default value to use when a valid color isn't found
9542 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9545 getColor : function(attr, defaultValue, prefix){
9546 var v = this.getStyle(attr);
9547 if(!v || v == "transparent" || v == "inherit") {
9548 return defaultValue;
9550 var color = typeof prefix == "undefined" ? "#" : prefix;
9551 if(v.substr(0, 4) == "rgb("){
9552 var rvs = v.slice(4, v.length -1).split(",");
9553 for(var i = 0; i < 3; i++){
9554 var h = parseInt(rvs[i]).toString(16);
9561 if(v.substr(0, 1) == "#"){
9563 for(var i = 1; i < 4; i++){
9564 var c = v.charAt(i);
9567 }else if(v.length == 7){
9568 color += v.substr(1);
9572 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9576 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9577 * gradient background, rounded corners and a 4-way shadow.
9578 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9579 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9580 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9581 * @return {Roo.Element} this
9583 boxWrap : function(cls){
9584 cls = cls || 'x-box';
9585 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9586 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9591 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9592 * @param {String} namespace The namespace in which to look for the attribute
9593 * @param {String} name The attribute name
9594 * @return {String} The attribute value
9596 getAttributeNS : Roo.isIE ? function(ns, name){
9598 var type = typeof d[ns+":"+name];
9599 if(type != 'undefined' && type != 'unknown'){
9600 return d[ns+":"+name];
9603 } : function(ns, name){
9605 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9610 * Sets or Returns the value the dom attribute value
9611 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9612 * @param {String} value (optional) The value to set the attribute to
9613 * @return {String} The attribute value
9615 attr : function(name){
9616 if (arguments.length > 1) {
9617 this.dom.setAttribute(name, arguments[1]);
9618 return arguments[1];
9620 if (typeof(name) == 'object') {
9621 for(var i in name) {
9622 this.attr(i, name[i]);
9628 if (!this.dom.hasAttribute(name)) {
9631 return this.dom.getAttribute(name);
9638 var ep = El.prototype;
9641 * Appends an event handler (Shorthand for addListener)
9642 * @param {String} eventName The type of event to append
9643 * @param {Function} fn The method the event invokes
9644 * @param {Object} scope (optional) The scope (this object) of the fn
9645 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9648 ep.on = ep.addListener;
9650 ep.mon = ep.addListener;
9653 * Removes an event handler from this element (shorthand for removeListener)
9654 * @param {String} eventName the type of event to remove
9655 * @param {Function} fn the method the event invokes
9656 * @return {Roo.Element} this
9659 ep.un = ep.removeListener;
9662 * true to automatically adjust width and height settings for box-model issues (default to true)
9664 ep.autoBoxAdjust = true;
9667 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9670 El.addUnits = function(v, defaultUnit){
9671 if(v === "" || v == "auto"){
9674 if(v === undefined){
9677 if(typeof v == "number" || !El.unitPattern.test(v)){
9678 return v + (defaultUnit || 'px');
9683 // special markup used throughout Roo when box wrapping elements
9684 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>';
9686 * Visibility mode constant - Use visibility to hide element
9692 * Visibility mode constant - Use display to hide element
9698 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9699 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9700 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9712 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9713 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9714 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9715 * @return {Element} The Element object
9718 El.get = function(el){
9720 if(!el){ return null; }
9721 if(typeof el == "string"){ // element id
9722 if(!(elm = document.getElementById(el))){
9725 if(ex = El.cache[el]){
9728 ex = El.cache[el] = new El(elm);
9731 }else if(el.tagName){ // dom element
9735 if(ex = El.cache[id]){
9738 ex = El.cache[id] = new El(el);
9741 }else if(el instanceof El){
9743 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9744 // catch case where it hasn't been appended
9745 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9748 }else if(el.isComposite){
9750 }else if(el instanceof Array){
9751 return El.select(el);
9752 }else if(el == document){
9753 // create a bogus element object representing the document object
9755 var f = function(){};
9756 f.prototype = El.prototype;
9758 docEl.dom = document;
9766 El.uncache = function(el){
9767 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9769 delete El.cache[a[i].id || a[i]];
9775 // Garbage collection - uncache elements/purge listeners on orphaned elements
9776 // so we don't hold a reference and cause the browser to retain them
9777 El.garbageCollect = function(){
9778 if(!Roo.enableGarbageCollector){
9779 clearInterval(El.collectorThread);
9782 for(var eid in El.cache){
9783 var el = El.cache[eid], d = el.dom;
9784 // -------------------------------------------------------
9785 // Determining what is garbage:
9786 // -------------------------------------------------------
9788 // dom node is null, definitely garbage
9789 // -------------------------------------------------------
9791 // no parentNode == direct orphan, definitely garbage
9792 // -------------------------------------------------------
9793 // !d.offsetParent && !document.getElementById(eid)
9794 // display none elements have no offsetParent so we will
9795 // also try to look it up by it's id. However, check
9796 // offsetParent first so we don't do unneeded lookups.
9797 // This enables collection of elements that are not orphans
9798 // directly, but somewhere up the line they have an orphan
9800 // -------------------------------------------------------
9801 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9802 delete El.cache[eid];
9803 if(d && Roo.enableListenerCollection){
9809 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9813 El.Flyweight = function(dom){
9816 El.Flyweight.prototype = El.prototype;
9818 El._flyweights = {};
9820 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9821 * the dom node can be overwritten by other code.
9822 * @param {String/HTMLElement} el The dom node or id
9823 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9824 * prevent conflicts (e.g. internally Roo uses "_internal")
9826 * @return {Element} The shared Element object
9828 El.fly = function(el, named){
9829 named = named || '_global';
9830 el = Roo.getDom(el);
9834 if(!El._flyweights[named]){
9835 El._flyweights[named] = new El.Flyweight();
9837 El._flyweights[named].dom = el;
9838 return El._flyweights[named];
9842 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9843 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9844 * Shorthand of {@link Roo.Element#get}
9845 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9846 * @return {Element} The Element object
9852 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9853 * the dom node can be overwritten by other code.
9854 * Shorthand of {@link Roo.Element#fly}
9855 * @param {String/HTMLElement} el The dom node or id
9856 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9857 * prevent conflicts (e.g. internally Roo uses "_internal")
9859 * @return {Element} The shared Element object
9865 // speedy lookup for elements never to box adjust
9866 var noBoxAdjust = Roo.isStrict ? {
9869 input:1, select:1, textarea:1
9871 if(Roo.isIE || Roo.isGecko){
9872 noBoxAdjust['button'] = 1;
9876 Roo.EventManager.on(window, 'unload', function(){
9878 delete El._flyweights;
9886 Roo.Element.selectorFunction = Roo.DomQuery.select;
9889 Roo.Element.select = function(selector, unique, root){
9891 if(typeof selector == "string"){
9892 els = Roo.Element.selectorFunction(selector, root);
9893 }else if(selector.length !== undefined){
9896 throw "Invalid selector";
9898 if(unique === true){
9899 return new Roo.CompositeElement(els);
9901 return new Roo.CompositeElementLite(els);
9905 * Selects elements based on the passed CSS selector to enable working on them as 1.
9906 * @param {String/Array} selector The CSS selector or an array of elements
9907 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9908 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9909 * @return {CompositeElementLite/CompositeElement}
9913 Roo.select = Roo.Element.select;
9930 * Ext JS Library 1.1.1
9931 * Copyright(c) 2006-2007, Ext JS, LLC.
9933 * Originally Released Under LGPL - original licence link has changed is not relivant.
9936 * <script type="text/javascript">
9941 //Notifies Element that fx methods are available
9942 Roo.enableFx = true;
9946 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9947 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9948 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9949 * Element effects to work.</p><br/>
9951 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9952 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9953 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9954 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9955 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9956 * expected results and should be done with care.</p><br/>
9958 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9959 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9962 ----- -----------------------------
9963 tl The top left corner
9964 t The center of the top edge
9965 tr The top right corner
9966 l The center of the left edge
9967 r The center of the right edge
9968 bl The bottom left corner
9969 b The center of the bottom edge
9970 br The bottom right corner
9972 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9973 * below are common options that can be passed to any Fx method.</b>
9974 * @cfg {Function} callback A function called when the effect is finished
9975 * @cfg {Object} scope The scope of the effect function
9976 * @cfg {String} easing A valid Easing value for the effect
9977 * @cfg {String} afterCls A css class to apply after the effect
9978 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9979 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9980 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9981 * effects that end with the element being visually hidden, ignored otherwise)
9982 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9983 * a function which returns such a specification that will be applied to the Element after the effect finishes
9984 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9985 * @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
9986 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9990 * Slides the element into view. An anchor point can be optionally passed to set the point of
9991 * origin for the slide effect. This function automatically handles wrapping the element with
9992 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9995 // default: slide the element in from the top
9998 // custom: slide the element in from the right with a 2-second duration
9999 el.slideIn('r', { duration: 2 });
10001 // common config options shown with default values
10007 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10008 * @param {Object} options (optional) Object literal with any of the Fx config options
10009 * @return {Roo.Element} The Element
10011 slideIn : function(anchor, o){
10012 var el = this.getFxEl();
10015 el.queueFx(o, function(){
10017 anchor = anchor || "t";
10019 // fix display to visibility
10022 // restore values after effect
10023 var r = this.getFxRestore();
10024 var b = this.getBox();
10025 // fixed size for slide
10029 var wrap = this.fxWrap(r.pos, o, "hidden");
10031 var st = this.dom.style;
10032 st.visibility = "visible";
10033 st.position = "absolute";
10035 // clear out temp styles after slide and unwrap
10036 var after = function(){
10037 el.fxUnwrap(wrap, r.pos, o);
10038 st.width = r.width;
10039 st.height = r.height;
10042 // time to calc the positions
10043 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10045 switch(anchor.toLowerCase()){
10047 wrap.setSize(b.width, 0);
10048 st.left = st.bottom = "0";
10052 wrap.setSize(0, b.height);
10053 st.right = st.top = "0";
10057 wrap.setSize(0, b.height);
10058 wrap.setX(b.right);
10059 st.left = st.top = "0";
10060 a = {width: bw, points: pt};
10063 wrap.setSize(b.width, 0);
10064 wrap.setY(b.bottom);
10065 st.left = st.top = "0";
10066 a = {height: bh, points: pt};
10069 wrap.setSize(0, 0);
10070 st.right = st.bottom = "0";
10071 a = {width: bw, height: bh};
10074 wrap.setSize(0, 0);
10075 wrap.setY(b.y+b.height);
10076 st.right = st.top = "0";
10077 a = {width: bw, height: bh, points: pt};
10080 wrap.setSize(0, 0);
10081 wrap.setXY([b.right, b.bottom]);
10082 st.left = st.top = "0";
10083 a = {width: bw, height: bh, points: pt};
10086 wrap.setSize(0, 0);
10087 wrap.setX(b.x+b.width);
10088 st.left = st.bottom = "0";
10089 a = {width: bw, height: bh, points: pt};
10092 this.dom.style.visibility = "visible";
10095 arguments.callee.anim = wrap.fxanim(a,
10105 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10106 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10107 * 'hidden') but block elements will still take up space in the document. The element must be removed
10108 * from the DOM using the 'remove' config option if desired. This function automatically handles
10109 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10112 // default: slide the element out to the top
10115 // custom: slide the element out to the right with a 2-second duration
10116 el.slideOut('r', { duration: 2 });
10118 // common config options shown with default values
10126 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10127 * @param {Object} options (optional) Object literal with any of the Fx config options
10128 * @return {Roo.Element} The Element
10130 slideOut : function(anchor, o){
10131 var el = this.getFxEl();
10134 el.queueFx(o, function(){
10136 anchor = anchor || "t";
10138 // restore values after effect
10139 var r = this.getFxRestore();
10141 var b = this.getBox();
10142 // fixed size for slide
10146 var wrap = this.fxWrap(r.pos, o, "visible");
10148 var st = this.dom.style;
10149 st.visibility = "visible";
10150 st.position = "absolute";
10154 var after = function(){
10156 el.setDisplayed(false);
10161 el.fxUnwrap(wrap, r.pos, o);
10163 st.width = r.width;
10164 st.height = r.height;
10169 var a, zero = {to: 0};
10170 switch(anchor.toLowerCase()){
10172 st.left = st.bottom = "0";
10173 a = {height: zero};
10176 st.right = st.top = "0";
10180 st.left = st.top = "0";
10181 a = {width: zero, points: {to:[b.right, b.y]}};
10184 st.left = st.top = "0";
10185 a = {height: zero, points: {to:[b.x, b.bottom]}};
10188 st.right = st.bottom = "0";
10189 a = {width: zero, height: zero};
10192 st.right = st.top = "0";
10193 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10196 st.left = st.top = "0";
10197 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10200 st.left = st.bottom = "0";
10201 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10205 arguments.callee.anim = wrap.fxanim(a,
10215 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10216 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10217 * The element must be removed from the DOM using the 'remove' config option if desired.
10223 // common config options shown with default values
10231 * @param {Object} options (optional) Object literal with any of the Fx config options
10232 * @return {Roo.Element} The Element
10234 puff : function(o){
10235 var el = this.getFxEl();
10238 el.queueFx(o, function(){
10239 this.clearOpacity();
10242 // restore values after effect
10243 var r = this.getFxRestore();
10244 var st = this.dom.style;
10246 var after = function(){
10248 el.setDisplayed(false);
10255 el.setPositioning(r.pos);
10256 st.width = r.width;
10257 st.height = r.height;
10262 var width = this.getWidth();
10263 var height = this.getHeight();
10265 arguments.callee.anim = this.fxanim({
10266 width : {to: this.adjustWidth(width * 2)},
10267 height : {to: this.adjustHeight(height * 2)},
10268 points : {by: [-(width * .5), -(height * .5)]},
10270 fontSize: {to:200, unit: "%"}
10281 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10282 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10283 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10289 // all config options shown with default values
10297 * @param {Object} options (optional) Object literal with any of the Fx config options
10298 * @return {Roo.Element} The Element
10300 switchOff : function(o){
10301 var el = this.getFxEl();
10304 el.queueFx(o, function(){
10305 this.clearOpacity();
10308 // restore values after effect
10309 var r = this.getFxRestore();
10310 var st = this.dom.style;
10312 var after = function(){
10314 el.setDisplayed(false);
10320 el.setPositioning(r.pos);
10321 st.width = r.width;
10322 st.height = r.height;
10327 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10328 this.clearOpacity();
10332 points:{by:[0, this.getHeight() * .5]}
10333 }, o, 'motion', 0.3, 'easeIn', after);
10334 }).defer(100, this);
10341 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10342 * changed using the "attr" config option) and then fading back to the original color. If no original
10343 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10346 // default: highlight background to yellow
10349 // custom: highlight foreground text to blue for 2 seconds
10350 el.highlight("0000ff", { attr: 'color', duration: 2 });
10352 // common config options shown with default values
10353 el.highlight("ffff9c", {
10354 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10355 endColor: (current color) or "ffffff",
10360 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10361 * @param {Object} options (optional) Object literal with any of the Fx config options
10362 * @return {Roo.Element} The Element
10364 highlight : function(color, o){
10365 var el = this.getFxEl();
10368 el.queueFx(o, function(){
10369 color = color || "ffff9c";
10370 attr = o.attr || "backgroundColor";
10372 this.clearOpacity();
10375 var origColor = this.getColor(attr);
10376 var restoreColor = this.dom.style[attr];
10377 endColor = (o.endColor || origColor) || "ffffff";
10379 var after = function(){
10380 el.dom.style[attr] = restoreColor;
10385 a[attr] = {from: color, to: endColor};
10386 arguments.callee.anim = this.fxanim(a,
10396 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10399 // default: a single light blue ripple
10402 // custom: 3 red ripples lasting 3 seconds total
10403 el.frame("ff0000", 3, { duration: 3 });
10405 // common config options shown with default values
10406 el.frame("C3DAF9", 1, {
10407 duration: 1 //duration of entire animation (not each individual ripple)
10408 // Note: Easing is not configurable and will be ignored if included
10411 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10412 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10413 * @param {Object} options (optional) Object literal with any of the Fx config options
10414 * @return {Roo.Element} The Element
10416 frame : function(color, count, o){
10417 var el = this.getFxEl();
10420 el.queueFx(o, function(){
10421 color = color || "#C3DAF9";
10422 if(color.length == 6){
10423 color = "#" + color;
10425 count = count || 1;
10426 duration = o.duration || 1;
10429 var b = this.getBox();
10430 var animFn = function(){
10431 var proxy = this.createProxy({
10434 visbility:"hidden",
10435 position:"absolute",
10436 "z-index":"35000", // yee haw
10437 border:"0px solid " + color
10440 var scale = Roo.isBorderBox ? 2 : 1;
10442 top:{from:b.y, to:b.y - 20},
10443 left:{from:b.x, to:b.x - 20},
10444 borderWidth:{from:0, to:10},
10445 opacity:{from:1, to:0},
10446 height:{from:b.height, to:(b.height + (20*scale))},
10447 width:{from:b.width, to:(b.width + (20*scale))}
10448 }, duration, function(){
10452 animFn.defer((duration/2)*1000, this);
10463 * Creates a pause before any subsequent queued effects begin. If there are
10464 * no effects queued after the pause it will have no effect.
10469 * @param {Number} seconds The length of time to pause (in seconds)
10470 * @return {Roo.Element} The Element
10472 pause : function(seconds){
10473 var el = this.getFxEl();
10476 el.queueFx(o, function(){
10477 setTimeout(function(){
10479 }, seconds * 1000);
10485 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10486 * using the "endOpacity" config option.
10489 // default: fade in from opacity 0 to 100%
10492 // custom: fade in from opacity 0 to 75% over 2 seconds
10493 el.fadeIn({ endOpacity: .75, duration: 2});
10495 // common config options shown with default values
10497 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10502 * @param {Object} options (optional) Object literal with any of the Fx config options
10503 * @return {Roo.Element} The Element
10505 fadeIn : function(o){
10506 var el = this.getFxEl();
10508 el.queueFx(o, function(){
10509 this.setOpacity(0);
10511 this.dom.style.visibility = 'visible';
10512 var to = o.endOpacity || 1;
10513 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10514 o, null, .5, "easeOut", function(){
10516 this.clearOpacity();
10525 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10526 * using the "endOpacity" config option.
10529 // default: fade out from the element's current opacity to 0
10532 // custom: fade out from the element's current opacity to 25% over 2 seconds
10533 el.fadeOut({ endOpacity: .25, duration: 2});
10535 // common config options shown with default values
10537 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10544 * @param {Object} options (optional) Object literal with any of the Fx config options
10545 * @return {Roo.Element} The Element
10547 fadeOut : function(o){
10548 var el = this.getFxEl();
10550 el.queueFx(o, function(){
10551 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10552 o, null, .5, "easeOut", function(){
10553 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10554 this.dom.style.display = "none";
10556 this.dom.style.visibility = "hidden";
10558 this.clearOpacity();
10566 * Animates the transition of an element's dimensions from a starting height/width
10567 * to an ending height/width.
10570 // change height and width to 100x100 pixels
10571 el.scale(100, 100);
10573 // common config options shown with default values. The height and width will default to
10574 // the element's existing values if passed as null.
10577 [element's height], {
10582 * @param {Number} width The new width (pass undefined to keep the original width)
10583 * @param {Number} height The new height (pass undefined to keep the original height)
10584 * @param {Object} options (optional) Object literal with any of the Fx config options
10585 * @return {Roo.Element} The Element
10587 scale : function(w, h, o){
10588 this.shift(Roo.apply({}, o, {
10596 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10597 * Any of these properties not specified in the config object will not be changed. This effect
10598 * requires that at least one new dimension, position or opacity setting must be passed in on
10599 * the config object in order for the function to have any effect.
10602 // slide the element horizontally to x position 200 while changing the height and opacity
10603 el.shift({ x: 200, height: 50, opacity: .8 });
10605 // common config options shown with default values.
10607 width: [element's width],
10608 height: [element's height],
10609 x: [element's x position],
10610 y: [element's y position],
10611 opacity: [element's opacity],
10616 * @param {Object} options Object literal with any of the Fx config options
10617 * @return {Roo.Element} The Element
10619 shift : function(o){
10620 var el = this.getFxEl();
10622 el.queueFx(o, function(){
10623 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10624 if(w !== undefined){
10625 a.width = {to: this.adjustWidth(w)};
10627 if(h !== undefined){
10628 a.height = {to: this.adjustHeight(h)};
10630 if(x !== undefined || y !== undefined){
10632 x !== undefined ? x : this.getX(),
10633 y !== undefined ? y : this.getY()
10636 if(op !== undefined){
10637 a.opacity = {to: op};
10639 if(o.xy !== undefined){
10640 a.points = {to: o.xy};
10642 arguments.callee.anim = this.fxanim(a,
10643 o, 'motion', .35, "easeOut", function(){
10651 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10652 * ending point of the effect.
10655 // default: slide the element downward while fading out
10658 // custom: slide the element out to the right with a 2-second duration
10659 el.ghost('r', { duration: 2 });
10661 // common config options shown with default values
10669 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10670 * @param {Object} options (optional) Object literal with any of the Fx config options
10671 * @return {Roo.Element} The Element
10673 ghost : function(anchor, o){
10674 var el = this.getFxEl();
10677 el.queueFx(o, function(){
10678 anchor = anchor || "b";
10680 // restore values after effect
10681 var r = this.getFxRestore();
10682 var w = this.getWidth(),
10683 h = this.getHeight();
10685 var st = this.dom.style;
10687 var after = function(){
10689 el.setDisplayed(false);
10695 el.setPositioning(r.pos);
10696 st.width = r.width;
10697 st.height = r.height;
10702 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10703 switch(anchor.toLowerCase()){
10730 arguments.callee.anim = this.fxanim(a,
10740 * Ensures that all effects queued after syncFx is called on the element are
10741 * run concurrently. This is the opposite of {@link #sequenceFx}.
10742 * @return {Roo.Element} The Element
10744 syncFx : function(){
10745 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10754 * Ensures that all effects queued after sequenceFx is called on the element are
10755 * run in sequence. This is the opposite of {@link #syncFx}.
10756 * @return {Roo.Element} The Element
10758 sequenceFx : function(){
10759 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10761 concurrent : false,
10768 nextFx : function(){
10769 var ef = this.fxQueue[0];
10776 * Returns true if the element has any effects actively running or queued, else returns false.
10777 * @return {Boolean} True if element has active effects, else false
10779 hasActiveFx : function(){
10780 return this.fxQueue && this.fxQueue[0];
10784 * Stops any running effects and clears the element's internal effects queue if it contains
10785 * any additional effects that haven't started yet.
10786 * @return {Roo.Element} The Element
10788 stopFx : function(){
10789 if(this.hasActiveFx()){
10790 var cur = this.fxQueue[0];
10791 if(cur && cur.anim && cur.anim.isAnimated()){
10792 this.fxQueue = [cur]; // clear out others
10793 cur.anim.stop(true);
10800 beforeFx : function(o){
10801 if(this.hasActiveFx() && !o.concurrent){
10812 * Returns true if the element is currently blocking so that no other effect can be queued
10813 * until this effect is finished, else returns false if blocking is not set. This is commonly
10814 * used to ensure that an effect initiated by a user action runs to completion prior to the
10815 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10816 * @return {Boolean} True if blocking, else false
10818 hasFxBlock : function(){
10819 var q = this.fxQueue;
10820 return q && q[0] && q[0].block;
10824 queueFx : function(o, fn){
10828 if(!this.hasFxBlock()){
10829 Roo.applyIf(o, this.fxDefaults);
10831 var run = this.beforeFx(o);
10832 fn.block = o.block;
10833 this.fxQueue.push(fn);
10845 fxWrap : function(pos, o, vis){
10847 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10850 wrapXY = this.getXY();
10852 var div = document.createElement("div");
10853 div.style.visibility = vis;
10854 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10855 wrap.setPositioning(pos);
10856 if(wrap.getStyle("position") == "static"){
10857 wrap.position("relative");
10859 this.clearPositioning('auto');
10861 wrap.dom.appendChild(this.dom);
10863 wrap.setXY(wrapXY);
10870 fxUnwrap : function(wrap, pos, o){
10871 this.clearPositioning();
10872 this.setPositioning(pos);
10874 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10880 getFxRestore : function(){
10881 var st = this.dom.style;
10882 return {pos: this.getPositioning(), width: st.width, height : st.height};
10886 afterFx : function(o){
10888 this.applyStyles(o.afterStyle);
10891 this.addClass(o.afterCls);
10893 if(o.remove === true){
10896 Roo.callback(o.callback, o.scope, [this]);
10898 this.fxQueue.shift();
10904 getFxEl : function(){ // support for composite element fx
10905 return Roo.get(this.dom);
10909 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10910 animType = animType || 'run';
10912 var anim = Roo.lib.Anim[animType](
10914 (opt.duration || defaultDur) || .35,
10915 (opt.easing || defaultEase) || 'easeOut',
10917 Roo.callback(cb, this);
10926 // backwords compat
10927 Roo.Fx.resize = Roo.Fx.scale;
10929 //When included, Roo.Fx is automatically applied to Element so that all basic
10930 //effects are available directly via the Element API
10931 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10933 * Ext JS Library 1.1.1
10934 * Copyright(c) 2006-2007, Ext JS, LLC.
10936 * Originally Released Under LGPL - original licence link has changed is not relivant.
10939 * <script type="text/javascript">
10944 * @class Roo.CompositeElement
10945 * Standard composite class. Creates a Roo.Element for every element in the collection.
10947 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10948 * actions will be performed on all the elements in this collection.</b>
10950 * All methods return <i>this</i> and can be chained.
10952 var els = Roo.select("#some-el div.some-class", true);
10953 // or select directly from an existing element
10954 var el = Roo.get('some-el');
10955 el.select('div.some-class', true);
10957 els.setWidth(100); // all elements become 100 width
10958 els.hide(true); // all elements fade out and hide
10960 els.setWidth(100).hide(true);
10963 Roo.CompositeElement = function(els){
10964 this.elements = [];
10965 this.addElements(els);
10967 Roo.CompositeElement.prototype = {
10969 addElements : function(els){
10970 if(!els) return this;
10971 if(typeof els == "string"){
10972 els = Roo.Element.selectorFunction(els);
10974 var yels = this.elements;
10975 var index = yels.length-1;
10976 for(var i = 0, len = els.length; i < len; i++) {
10977 yels[++index] = Roo.get(els[i]);
10983 * Clears this composite and adds the elements returned by the passed selector.
10984 * @param {String/Array} els A string CSS selector, an array of elements or an element
10985 * @return {CompositeElement} this
10987 fill : function(els){
10988 this.elements = [];
10994 * Filters this composite to only elements that match the passed selector.
10995 * @param {String} selector A string CSS selector
10996 * @param {Boolean} inverse return inverse filter (not matches)
10997 * @return {CompositeElement} this
10999 filter : function(selector, inverse){
11001 inverse = inverse || false;
11002 this.each(function(el){
11003 var match = inverse ? !el.is(selector) : el.is(selector);
11005 els[els.length] = el.dom;
11012 invoke : function(fn, args){
11013 var els = this.elements;
11014 for(var i = 0, len = els.length; i < len; i++) {
11015 Roo.Element.prototype[fn].apply(els[i], args);
11020 * Adds elements to this composite.
11021 * @param {String/Array} els A string CSS selector, an array of elements or an element
11022 * @return {CompositeElement} this
11024 add : function(els){
11025 if(typeof els == "string"){
11026 this.addElements(Roo.Element.selectorFunction(els));
11027 }else if(els.length !== undefined){
11028 this.addElements(els);
11030 this.addElements([els]);
11035 * Calls the passed function passing (el, this, index) for each element in this composite.
11036 * @param {Function} fn The function to call
11037 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11038 * @return {CompositeElement} this
11040 each : function(fn, scope){
11041 var els = this.elements;
11042 for(var i = 0, len = els.length; i < len; i++){
11043 if(fn.call(scope || els[i], els[i], this, i) === false) {
11051 * Returns the Element object at the specified index
11052 * @param {Number} index
11053 * @return {Roo.Element}
11055 item : function(index){
11056 return this.elements[index] || null;
11060 * Returns the first Element
11061 * @return {Roo.Element}
11063 first : function(){
11064 return this.item(0);
11068 * Returns the last Element
11069 * @return {Roo.Element}
11072 return this.item(this.elements.length-1);
11076 * Returns the number of elements in this composite
11079 getCount : function(){
11080 return this.elements.length;
11084 * Returns true if this composite contains the passed element
11087 contains : function(el){
11088 return this.indexOf(el) !== -1;
11092 * Returns true if this composite contains the passed element
11095 indexOf : function(el){
11096 return this.elements.indexOf(Roo.get(el));
11101 * Removes the specified element(s).
11102 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11103 * or an array of any of those.
11104 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11105 * @return {CompositeElement} this
11107 removeElement : function(el, removeDom){
11108 if(el instanceof Array){
11109 for(var i = 0, len = el.length; i < len; i++){
11110 this.removeElement(el[i]);
11114 var index = typeof el == 'number' ? el : this.indexOf(el);
11117 var d = this.elements[index];
11121 d.parentNode.removeChild(d);
11124 this.elements.splice(index, 1);
11130 * Replaces the specified element with the passed element.
11131 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11133 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11134 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11135 * @return {CompositeElement} this
11137 replaceElement : function(el, replacement, domReplace){
11138 var index = typeof el == 'number' ? el : this.indexOf(el);
11141 this.elements[index].replaceWith(replacement);
11143 this.elements.splice(index, 1, Roo.get(replacement))
11150 * Removes all elements.
11152 clear : function(){
11153 this.elements = [];
11157 Roo.CompositeElement.createCall = function(proto, fnName){
11158 if(!proto[fnName]){
11159 proto[fnName] = function(){
11160 return this.invoke(fnName, arguments);
11164 for(var fnName in Roo.Element.prototype){
11165 if(typeof Roo.Element.prototype[fnName] == "function"){
11166 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11172 * Ext JS Library 1.1.1
11173 * Copyright(c) 2006-2007, Ext JS, LLC.
11175 * Originally Released Under LGPL - original licence link has changed is not relivant.
11178 * <script type="text/javascript">
11182 * @class Roo.CompositeElementLite
11183 * @extends Roo.CompositeElement
11184 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11186 var els = Roo.select("#some-el div.some-class");
11187 // or select directly from an existing element
11188 var el = Roo.get('some-el');
11189 el.select('div.some-class');
11191 els.setWidth(100); // all elements become 100 width
11192 els.hide(true); // all elements fade out and hide
11194 els.setWidth(100).hide(true);
11195 </code></pre><br><br>
11196 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11197 * actions will be performed on all the elements in this collection.</b>
11199 Roo.CompositeElementLite = function(els){
11200 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11201 this.el = new Roo.Element.Flyweight();
11203 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11204 addElements : function(els){
11206 if(els instanceof Array){
11207 this.elements = this.elements.concat(els);
11209 var yels = this.elements;
11210 var index = yels.length-1;
11211 for(var i = 0, len = els.length; i < len; i++) {
11212 yels[++index] = els[i];
11218 invoke : function(fn, args){
11219 var els = this.elements;
11221 for(var i = 0, len = els.length; i < len; i++) {
11223 Roo.Element.prototype[fn].apply(el, args);
11228 * Returns a flyweight Element of the dom element object at the specified index
11229 * @param {Number} index
11230 * @return {Roo.Element}
11232 item : function(index){
11233 if(!this.elements[index]){
11236 this.el.dom = this.elements[index];
11240 // fixes scope with flyweight
11241 addListener : function(eventName, handler, scope, opt){
11242 var els = this.elements;
11243 for(var i = 0, len = els.length; i < len; i++) {
11244 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11250 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11251 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11252 * a reference to the dom node, use el.dom.</b>
11253 * @param {Function} fn The function to call
11254 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11255 * @return {CompositeElement} this
11257 each : function(fn, scope){
11258 var els = this.elements;
11260 for(var i = 0, len = els.length; i < len; i++){
11262 if(fn.call(scope || el, el, this, i) === false){
11269 indexOf : function(el){
11270 return this.elements.indexOf(Roo.getDom(el));
11273 replaceElement : function(el, replacement, domReplace){
11274 var index = typeof el == 'number' ? el : this.indexOf(el);
11276 replacement = Roo.getDom(replacement);
11278 var d = this.elements[index];
11279 d.parentNode.insertBefore(replacement, d);
11280 d.parentNode.removeChild(d);
11282 this.elements.splice(index, 1, replacement);
11287 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11291 * Ext JS Library 1.1.1
11292 * Copyright(c) 2006-2007, Ext JS, LLC.
11294 * Originally Released Under LGPL - original licence link has changed is not relivant.
11297 * <script type="text/javascript">
11303 * @class Roo.data.Connection
11304 * @extends Roo.util.Observable
11305 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11306 * either to a configured URL, or to a URL specified at request time.<br><br>
11308 * Requests made by this class are asynchronous, and will return immediately. No data from
11309 * the server will be available to the statement immediately following the {@link #request} call.
11310 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11312 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11313 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11314 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11315 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11316 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11317 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11318 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11319 * standard DOM methods.
11321 * @param {Object} config a configuration object.
11323 Roo.data.Connection = function(config){
11324 Roo.apply(this, config);
11327 * @event beforerequest
11328 * Fires before a network request is made to retrieve a data object.
11329 * @param {Connection} conn This Connection object.
11330 * @param {Object} options The options config object passed to the {@link #request} method.
11332 "beforerequest" : true,
11334 * @event requestcomplete
11335 * Fires if the request was successfully completed.
11336 * @param {Connection} conn This Connection object.
11337 * @param {Object} response The XHR object containing the response data.
11338 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11339 * @param {Object} options The options config object passed to the {@link #request} method.
11341 "requestcomplete" : true,
11343 * @event requestexception
11344 * Fires if an error HTTP status was returned from the server.
11345 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11346 * @param {Connection} conn This Connection object.
11347 * @param {Object} response The XHR object containing the response data.
11348 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11349 * @param {Object} options The options config object passed to the {@link #request} method.
11351 "requestexception" : true
11353 Roo.data.Connection.superclass.constructor.call(this);
11356 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11358 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11361 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11362 * extra parameters to each request made by this object. (defaults to undefined)
11365 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11366 * to each request made by this object. (defaults to undefined)
11369 * @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)
11372 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11376 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11382 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11385 disableCaching: true,
11388 * Sends an HTTP request to a remote server.
11389 * @param {Object} options An object which may contain the following properties:<ul>
11390 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11391 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11392 * request, a url encoded string or a function to call to get either.</li>
11393 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11394 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11395 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11396 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11397 * <li>options {Object} The parameter to the request call.</li>
11398 * <li>success {Boolean} True if the request succeeded.</li>
11399 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11401 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11402 * The callback is passed the following parameters:<ul>
11403 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11404 * <li>options {Object} The parameter to the request call.</li>
11406 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11407 * The callback is passed the following parameters:<ul>
11408 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11409 * <li>options {Object} The parameter to the request call.</li>
11411 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11412 * for the callback function. Defaults to the browser window.</li>
11413 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11414 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11415 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11416 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11417 * params for the post data. Any params will be appended to the URL.</li>
11418 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11420 * @return {Number} transactionId
11422 request : function(o){
11423 if(this.fireEvent("beforerequest", this, o) !== false){
11426 if(typeof p == "function"){
11427 p = p.call(o.scope||window, o);
11429 if(typeof p == "object"){
11430 p = Roo.urlEncode(o.params);
11432 if(this.extraParams){
11433 var extras = Roo.urlEncode(this.extraParams);
11434 p = p ? (p + '&' + extras) : extras;
11437 var url = o.url || this.url;
11438 if(typeof url == 'function'){
11439 url = url.call(o.scope||window, o);
11443 var form = Roo.getDom(o.form);
11444 url = url || form.action;
11446 var enctype = form.getAttribute("enctype");
11447 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11448 return this.doFormUpload(o, p, url);
11450 var f = Roo.lib.Ajax.serializeForm(form);
11451 p = p ? (p + '&' + f) : f;
11454 var hs = o.headers;
11455 if(this.defaultHeaders){
11456 hs = Roo.apply(hs || {}, this.defaultHeaders);
11463 success: this.handleResponse,
11464 failure: this.handleFailure,
11466 argument: {options: o},
11467 timeout : o.timeout || this.timeout
11470 var method = o.method||this.method||(p ? "POST" : "GET");
11472 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11473 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11476 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11480 }else if(this.autoAbort !== false){
11484 if((method == 'GET' && p) || o.xmlData){
11485 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11488 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11489 return this.transId;
11491 Roo.callback(o.callback, o.scope, [o, null, null]);
11497 * Determine whether this object has a request outstanding.
11498 * @param {Number} transactionId (Optional) defaults to the last transaction
11499 * @return {Boolean} True if there is an outstanding request.
11501 isLoading : function(transId){
11503 return Roo.lib.Ajax.isCallInProgress(transId);
11505 return this.transId ? true : false;
11510 * Aborts any outstanding request.
11511 * @param {Number} transactionId (Optional) defaults to the last transaction
11513 abort : function(transId){
11514 if(transId || this.isLoading()){
11515 Roo.lib.Ajax.abort(transId || this.transId);
11520 handleResponse : function(response){
11521 this.transId = false;
11522 var options = response.argument.options;
11523 response.argument = options ? options.argument : null;
11524 this.fireEvent("requestcomplete", this, response, options);
11525 Roo.callback(options.success, options.scope, [response, options]);
11526 Roo.callback(options.callback, options.scope, [options, true, response]);
11530 handleFailure : function(response, e){
11531 this.transId = false;
11532 var options = response.argument.options;
11533 response.argument = options ? options.argument : null;
11534 this.fireEvent("requestexception", this, response, options, e);
11535 Roo.callback(options.failure, options.scope, [response, options]);
11536 Roo.callback(options.callback, options.scope, [options, false, response]);
11540 doFormUpload : function(o, ps, url){
11542 var frame = document.createElement('iframe');
11545 frame.className = 'x-hidden';
11547 frame.src = Roo.SSL_SECURE_URL;
11549 document.body.appendChild(frame);
11552 document.frames[id].name = id;
11555 var form = Roo.getDom(o.form);
11557 form.method = 'POST';
11558 form.enctype = form.encoding = 'multipart/form-data';
11564 if(ps){ // add dynamic params
11566 ps = Roo.urlDecode(ps, false);
11568 if(ps.hasOwnProperty(k)){
11569 hd = document.createElement('input');
11570 hd.type = 'hidden';
11573 form.appendChild(hd);
11580 var r = { // bogus response object
11585 r.argument = o ? o.argument : null;
11590 doc = frame.contentWindow.document;
11592 doc = (frame.contentDocument || window.frames[id].document);
11594 if(doc && doc.body){
11595 r.responseText = doc.body.innerHTML;
11597 if(doc && doc.XMLDocument){
11598 r.responseXML = doc.XMLDocument;
11600 r.responseXML = doc;
11607 Roo.EventManager.removeListener(frame, 'load', cb, this);
11609 this.fireEvent("requestcomplete", this, r, o);
11610 Roo.callback(o.success, o.scope, [r, o]);
11611 Roo.callback(o.callback, o.scope, [o, true, r]);
11613 setTimeout(function(){document.body.removeChild(frame);}, 100);
11616 Roo.EventManager.on(frame, 'load', cb, this);
11619 if(hiddens){ // remove dynamic params
11620 for(var i = 0, len = hiddens.length; i < len; i++){
11621 form.removeChild(hiddens[i]);
11628 * Ext JS Library 1.1.1
11629 * Copyright(c) 2006-2007, Ext JS, LLC.
11631 * Originally Released Under LGPL - original licence link has changed is not relivant.
11634 * <script type="text/javascript">
11638 * Global Ajax request class.
11641 * @extends Roo.data.Connection
11644 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11645 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11646 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11647 * @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)
11648 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11649 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11650 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11652 Roo.Ajax = new Roo.data.Connection({
11661 * Serialize the passed form into a url encoded string
11663 * @param {String/HTMLElement} form
11666 serializeForm : function(form){
11667 return Roo.lib.Ajax.serializeForm(form);
11671 * Ext JS Library 1.1.1
11672 * Copyright(c) 2006-2007, Ext JS, LLC.
11674 * Originally Released Under LGPL - original licence link has changed is not relivant.
11677 * <script type="text/javascript">
11682 * @class Roo.UpdateManager
11683 * @extends Roo.util.Observable
11684 * Provides AJAX-style update for Element object.<br><br>
11687 * // Get it from a Roo.Element object
11688 * var el = Roo.get("foo");
11689 * var mgr = el.getUpdateManager();
11690 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11692 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11694 * // or directly (returns the same UpdateManager instance)
11695 * var mgr = new Roo.UpdateManager("myElementId");
11696 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11697 * mgr.on("update", myFcnNeedsToKnow);
11699 // short handed call directly from the element object
11700 Roo.get("foo").load({
11704 text: "Loading Foo..."
11708 * Create new UpdateManager directly.
11709 * @param {String/HTMLElement/Roo.Element} el The element to update
11710 * @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).
11712 Roo.UpdateManager = function(el, forceNew){
11714 if(!forceNew && el.updateManager){
11715 return el.updateManager;
11718 * The Element object
11719 * @type Roo.Element
11723 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11726 this.defaultUrl = null;
11730 * @event beforeupdate
11731 * Fired before an update is made, return false from your handler and the update is cancelled.
11732 * @param {Roo.Element} el
11733 * @param {String/Object/Function} url
11734 * @param {String/Object} params
11736 "beforeupdate": true,
11739 * Fired after successful update is made.
11740 * @param {Roo.Element} el
11741 * @param {Object} oResponseObject The response Object
11746 * Fired on update failure.
11747 * @param {Roo.Element} el
11748 * @param {Object} oResponseObject The response Object
11752 var d = Roo.UpdateManager.defaults;
11754 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11757 this.sslBlankUrl = d.sslBlankUrl;
11759 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11762 this.disableCaching = d.disableCaching;
11764 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11767 this.indicatorText = d.indicatorText;
11769 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11772 this.showLoadIndicator = d.showLoadIndicator;
11774 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11777 this.timeout = d.timeout;
11780 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11783 this.loadScripts = d.loadScripts;
11786 * Transaction object of current executing transaction
11788 this.transaction = null;
11793 this.autoRefreshProcId = null;
11795 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11798 this.refreshDelegate = this.refresh.createDelegate(this);
11800 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11803 this.updateDelegate = this.update.createDelegate(this);
11805 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11808 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11812 this.successDelegate = this.processSuccess.createDelegate(this);
11816 this.failureDelegate = this.processFailure.createDelegate(this);
11818 if(!this.renderer){
11820 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11822 this.renderer = new Roo.UpdateManager.BasicRenderer();
11825 Roo.UpdateManager.superclass.constructor.call(this);
11828 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11830 * Get the Element this UpdateManager is bound to
11831 * @return {Roo.Element} The element
11833 getEl : function(){
11837 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11838 * @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:
11841 url: "your-url.php",<br/>
11842 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11843 callback: yourFunction,<br/>
11844 scope: yourObject, //(optional scope) <br/>
11845 discardUrl: false, <br/>
11846 nocache: false,<br/>
11847 text: "Loading...",<br/>
11849 scripts: false<br/>
11852 * The only required property is url. The optional properties nocache, text and scripts
11853 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11854 * @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}
11855 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11856 * @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.
11858 update : function(url, params, callback, discardUrl){
11859 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11860 var method = this.method,
11862 if(typeof url == "object"){ // must be config object
11865 params = params || cfg.params;
11866 callback = callback || cfg.callback;
11867 discardUrl = discardUrl || cfg.discardUrl;
11868 if(callback && cfg.scope){
11869 callback = callback.createDelegate(cfg.scope);
11871 if(typeof cfg.method != "undefined"){method = cfg.method;};
11872 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11873 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11874 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11875 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11877 this.showLoading();
11879 this.defaultUrl = url;
11881 if(typeof url == "function"){
11882 url = url.call(this);
11885 method = method || (params ? "POST" : "GET");
11886 if(method == "GET"){
11887 url = this.prepareUrl(url);
11890 var o = Roo.apply(cfg ||{}, {
11893 success: this.successDelegate,
11894 failure: this.failureDelegate,
11895 callback: undefined,
11896 timeout: (this.timeout*1000),
11897 argument: {"url": url, "form": null, "callback": callback, "params": params}
11899 Roo.log("updated manager called with timeout of " + o.timeout);
11900 this.transaction = Roo.Ajax.request(o);
11905 * 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.
11906 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11907 * @param {String/HTMLElement} form The form Id or form element
11908 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11909 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11910 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11912 formUpdate : function(form, url, reset, callback){
11913 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11914 if(typeof url == "function"){
11915 url = url.call(this);
11917 form = Roo.getDom(form);
11918 this.transaction = Roo.Ajax.request({
11921 success: this.successDelegate,
11922 failure: this.failureDelegate,
11923 timeout: (this.timeout*1000),
11924 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11926 this.showLoading.defer(1, this);
11931 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11932 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11934 refresh : function(callback){
11935 if(this.defaultUrl == null){
11938 this.update(this.defaultUrl, null, callback, true);
11942 * Set this element to auto refresh.
11943 * @param {Number} interval How often to update (in seconds).
11944 * @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)
11945 * @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}
11946 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11947 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11949 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11951 this.update(url || this.defaultUrl, params, callback, true);
11953 if(this.autoRefreshProcId){
11954 clearInterval(this.autoRefreshProcId);
11956 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11960 * Stop auto refresh on this element.
11962 stopAutoRefresh : function(){
11963 if(this.autoRefreshProcId){
11964 clearInterval(this.autoRefreshProcId);
11965 delete this.autoRefreshProcId;
11969 isAutoRefreshing : function(){
11970 return this.autoRefreshProcId ? true : false;
11973 * Called to update the element to "Loading" state. Override to perform custom action.
11975 showLoading : function(){
11976 if(this.showLoadIndicator){
11977 this.el.update(this.indicatorText);
11982 * Adds unique parameter to query string if disableCaching = true
11985 prepareUrl : function(url){
11986 if(this.disableCaching){
11987 var append = "_dc=" + (new Date().getTime());
11988 if(url.indexOf("?") !== -1){
11989 url += "&" + append;
11991 url += "?" + append;
12000 processSuccess : function(response){
12001 this.transaction = null;
12002 if(response.argument.form && response.argument.reset){
12003 try{ // put in try/catch since some older FF releases had problems with this
12004 response.argument.form.reset();
12007 if(this.loadScripts){
12008 this.renderer.render(this.el, response, this,
12009 this.updateComplete.createDelegate(this, [response]));
12011 this.renderer.render(this.el, response, this);
12012 this.updateComplete(response);
12016 updateComplete : function(response){
12017 this.fireEvent("update", this.el, response);
12018 if(typeof response.argument.callback == "function"){
12019 response.argument.callback(this.el, true, response);
12026 processFailure : function(response){
12027 this.transaction = null;
12028 this.fireEvent("failure", this.el, response);
12029 if(typeof response.argument.callback == "function"){
12030 response.argument.callback(this.el, false, response);
12035 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12036 * @param {Object} renderer The object implementing the render() method
12038 setRenderer : function(renderer){
12039 this.renderer = renderer;
12042 getRenderer : function(){
12043 return this.renderer;
12047 * Set the defaultUrl used for updates
12048 * @param {String/Function} defaultUrl The url or a function to call to get the url
12050 setDefaultUrl : function(defaultUrl){
12051 this.defaultUrl = defaultUrl;
12055 * Aborts the executing transaction
12057 abort : function(){
12058 if(this.transaction){
12059 Roo.Ajax.abort(this.transaction);
12064 * Returns true if an update is in progress
12065 * @return {Boolean}
12067 isUpdating : function(){
12068 if(this.transaction){
12069 return Roo.Ajax.isLoading(this.transaction);
12076 * @class Roo.UpdateManager.defaults
12077 * @static (not really - but it helps the doc tool)
12078 * The defaults collection enables customizing the default properties of UpdateManager
12080 Roo.UpdateManager.defaults = {
12082 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12088 * True to process scripts by default (Defaults to false).
12091 loadScripts : false,
12094 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12097 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12099 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12102 disableCaching : false,
12104 * Whether to show indicatorText when loading (Defaults to true).
12107 showLoadIndicator : true,
12109 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12112 indicatorText : '<div class="loading-indicator">Loading...</div>'
12116 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12118 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12119 * @param {String/HTMLElement/Roo.Element} el The element to update
12120 * @param {String} url The url
12121 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12122 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12125 * @member Roo.UpdateManager
12127 Roo.UpdateManager.updateElement = function(el, url, params, options){
12128 var um = Roo.get(el, true).getUpdateManager();
12129 Roo.apply(um, options);
12130 um.update(url, params, options ? options.callback : null);
12132 // alias for backwards compat
12133 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12135 * @class Roo.UpdateManager.BasicRenderer
12136 * Default Content renderer. Updates the elements innerHTML with the responseText.
12138 Roo.UpdateManager.BasicRenderer = function(){};
12140 Roo.UpdateManager.BasicRenderer.prototype = {
12142 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12143 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12144 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12145 * @param {Roo.Element} el The element being rendered
12146 * @param {Object} response The YUI Connect response object
12147 * @param {UpdateManager} updateManager The calling update manager
12148 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12150 render : function(el, response, updateManager, callback){
12151 el.update(response.responseText, updateManager.loadScripts, callback);
12157 * (c)) Alan Knowles
12163 * @class Roo.DomTemplate
12164 * @extends Roo.Template
12165 * An effort at a dom based template engine..
12167 * Similar to XTemplate, except it uses dom parsing to create the template..
12169 * Supported features:
12174 {a_variable} - output encoded.
12175 {a_variable.format:("Y-m-d")} - call a method on the variable
12176 {a_variable:raw} - unencoded output
12177 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12178 {a_variable:this.method_on_template(...)} - call a method on the template object.
12183 <div roo-for="a_variable or condition.."></div>
12184 <div roo-if="a_variable or condition"></div>
12185 <div roo-exec="some javascript"></div>
12186 <div roo-name="named_template"></div>
12191 Roo.DomTemplate = function()
12193 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12200 Roo.extend(Roo.DomTemplate, Roo.Template, {
12202 * id counter for sub templates.
12206 * flag to indicate if dom parser is inside a pre,
12207 * it will strip whitespace if not.
12212 * The various sub templates
12220 * basic tag replacing syntax
12223 * // you can fake an object call by doing this
12227 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12228 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12230 iterChild : function (node, method) {
12232 var oldPre = this.inPre;
12233 if (node.tagName == 'PRE') {
12236 for( var i = 0; i < node.childNodes.length; i++) {
12237 method.call(this, node.childNodes[i]);
12239 this.inPre = oldPre;
12245 * compile the template
12247 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12250 compile: function()
12254 // covert the html into DOM...
12258 doc = document.implementation.createHTMLDocument("");
12259 doc.documentElement.innerHTML = this.html ;
12260 div = doc.documentElement;
12262 // old IE... - nasty -- it causes all sorts of issues.. with
12263 // images getting pulled from server..
12264 div = document.createElement('div');
12265 div.innerHTML = this.html;
12267 //doc.documentElement.innerHTML = htmlBody
12273 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12275 var tpls = this.tpls;
12277 // create a top level template from the snippet..
12279 //Roo.log(div.innerHTML);
12286 body : div.innerHTML,
12299 Roo.each(tpls, function(tp){
12300 this.compileTpl(tp);
12301 this.tpls[tp.id] = tp;
12304 this.master = tpls[0];
12310 compileNode : function(node, istop) {
12315 // skip anything not a tag..
12316 if (node.nodeType != 1) {
12317 if (node.nodeType == 3 && !this.inPre) {
12318 // reduce white space..
12319 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12342 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12343 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12344 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12345 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12351 // just itterate children..
12352 this.iterChild(node,this.compileNode);
12355 tpl.uid = this.id++;
12356 tpl.value = node.getAttribute('roo-' + tpl.attr);
12357 node.removeAttribute('roo-'+ tpl.attr);
12358 if (tpl.attr != 'name') {
12359 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12360 node.parentNode.replaceChild(placeholder, node);
12363 var placeholder = document.createElement('span');
12364 placeholder.className = 'roo-tpl-' + tpl.value;
12365 node.parentNode.replaceChild(placeholder, node);
12368 // parent now sees '{domtplXXXX}
12369 this.iterChild(node,this.compileNode);
12371 // we should now have node body...
12372 var div = document.createElement('div');
12373 div.appendChild(node);
12375 // this has the unfortunate side effect of converting tagged attributes
12376 // eg. href="{...}" into %7C...%7D
12377 // this has been fixed by searching for those combo's although it's a bit hacky..
12380 tpl.body = div.innerHTML;
12387 switch (tpl.value) {
12388 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12389 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12390 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12395 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12399 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12403 tpl.id = tpl.value; // replace non characters???
12409 this.tpls.push(tpl);
12419 * Compile a segment of the template into a 'sub-template'
12425 compileTpl : function(tpl)
12427 var fm = Roo.util.Format;
12428 var useF = this.disableFormats !== true;
12430 var sep = Roo.isGecko ? "+\n" : ",\n";
12432 var undef = function(str) {
12433 Roo.debug && Roo.log("Property not found :" + str);
12437 //Roo.log(tpl.body);
12441 var fn = function(m, lbrace, name, format, args)
12444 //Roo.log(arguments);
12445 args = args ? args.replace(/\\'/g,"'") : args;
12446 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12447 if (typeof(format) == 'undefined') {
12448 format = 'htmlEncode';
12450 if (format == 'raw' ) {
12454 if(name.substr(0, 6) == 'domtpl'){
12455 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12458 // build an array of options to determine if value is undefined..
12460 // basically get 'xxxx.yyyy' then do
12461 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12462 // (function () { Roo.log("Property not found"); return ''; })() :
12467 Roo.each(name.split('.'), function(st) {
12468 lookfor += (lookfor.length ? '.': '') + st;
12469 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12472 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12475 if(format && useF){
12477 args = args ? ',' + args : "";
12479 if(format.substr(0, 5) != "this."){
12480 format = "fm." + format + '(';
12482 format = 'this.call("'+ format.substr(5) + '", ';
12486 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12489 if (args && args.length) {
12490 // called with xxyx.yuu:(test,test)
12492 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12494 // raw.. - :raw modifier..
12495 return "'"+ sep + udef_st + name + ")"+sep+"'";
12499 // branched to use + in gecko and [].join() in others
12501 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12502 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12505 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12506 body.push(tpl.body.replace(/(\r\n|\n)/g,
12507 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12508 body.push("'].join('');};};");
12509 body = body.join('');
12512 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12514 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12521 * same as applyTemplate, except it's done to one of the subTemplates
12522 * when using named templates, you can do:
12524 * var str = pl.applySubTemplate('your-name', values);
12527 * @param {Number} id of the template
12528 * @param {Object} values to apply to template
12529 * @param {Object} parent (normaly the instance of this object)
12531 applySubTemplate : function(id, values, parent)
12535 var t = this.tpls[id];
12539 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12540 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12544 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12551 if(t.execCall && t.execCall.call(this, values, parent)){
12555 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12561 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12562 parent = t.target ? values : parent;
12563 if(t.forCall && vs instanceof Array){
12565 for(var i = 0, len = vs.length; i < len; i++){
12567 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12569 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12571 //Roo.log(t.compiled);
12575 return buf.join('');
12578 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12583 return t.compiled.call(this, vs, parent);
12585 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12587 //Roo.log(t.compiled);
12595 applyTemplate : function(values){
12596 return this.master.compiled.call(this, values, {});
12597 //var s = this.subs;
12600 apply : function(){
12601 return this.applyTemplate.apply(this, arguments);
12606 Roo.DomTemplate.from = function(el){
12607 el = Roo.getDom(el);
12608 return new Roo.Domtemplate(el.value || el.innerHTML);
12611 * Ext JS Library 1.1.1
12612 * Copyright(c) 2006-2007, Ext JS, LLC.
12614 * Originally Released Under LGPL - original licence link has changed is not relivant.
12617 * <script type="text/javascript">
12621 * @class Roo.util.DelayedTask
12622 * Provides a convenient method of performing setTimeout where a new
12623 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12624 * You can use this class to buffer
12625 * the keypress events for a certain number of milliseconds, and perform only if they stop
12626 * for that amount of time.
12627 * @constructor The parameters to this constructor serve as defaults and are not required.
12628 * @param {Function} fn (optional) The default function to timeout
12629 * @param {Object} scope (optional) The default scope of that timeout
12630 * @param {Array} args (optional) The default Array of arguments
12632 Roo.util.DelayedTask = function(fn, scope, args){
12633 var id = null, d, t;
12635 var call = function(){
12636 var now = new Date().getTime();
12640 fn.apply(scope, args || []);
12644 * Cancels any pending timeout and queues a new one
12645 * @param {Number} delay The milliseconds to delay
12646 * @param {Function} newFn (optional) Overrides function passed to constructor
12647 * @param {Object} newScope (optional) Overrides scope passed to constructor
12648 * @param {Array} newArgs (optional) Overrides args passed to constructor
12650 this.delay = function(delay, newFn, newScope, newArgs){
12651 if(id && delay != d){
12655 t = new Date().getTime();
12657 scope = newScope || scope;
12658 args = newArgs || args;
12660 id = setInterval(call, d);
12665 * Cancel the last queued timeout
12667 this.cancel = function(){
12675 * Ext JS Library 1.1.1
12676 * Copyright(c) 2006-2007, Ext JS, LLC.
12678 * Originally Released Under LGPL - original licence link has changed is not relivant.
12681 * <script type="text/javascript">
12685 Roo.util.TaskRunner = function(interval){
12686 interval = interval || 10;
12687 var tasks = [], removeQueue = [];
12689 var running = false;
12691 var stopThread = function(){
12697 var startThread = function(){
12700 id = setInterval(runTasks, interval);
12704 var removeTask = function(task){
12705 removeQueue.push(task);
12711 var runTasks = function(){
12712 if(removeQueue.length > 0){
12713 for(var i = 0, len = removeQueue.length; i < len; i++){
12714 tasks.remove(removeQueue[i]);
12717 if(tasks.length < 1){
12722 var now = new Date().getTime();
12723 for(var i = 0, len = tasks.length; i < len; ++i){
12725 var itime = now - t.taskRunTime;
12726 if(t.interval <= itime){
12727 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12728 t.taskRunTime = now;
12729 if(rt === false || t.taskRunCount === t.repeat){
12734 if(t.duration && t.duration <= (now - t.taskStartTime)){
12741 * Queues a new task.
12742 * @param {Object} task
12744 this.start = function(task){
12746 task.taskStartTime = new Date().getTime();
12747 task.taskRunTime = 0;
12748 task.taskRunCount = 0;
12753 this.stop = function(task){
12758 this.stopAll = function(){
12760 for(var i = 0, len = tasks.length; i < len; i++){
12761 if(tasks[i].onStop){
12770 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12772 * Ext JS Library 1.1.1
12773 * Copyright(c) 2006-2007, Ext JS, LLC.
12775 * Originally Released Under LGPL - original licence link has changed is not relivant.
12778 * <script type="text/javascript">
12783 * @class Roo.util.MixedCollection
12784 * @extends Roo.util.Observable
12785 * A Collection class that maintains both numeric indexes and keys and exposes events.
12787 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12788 * collection (defaults to false)
12789 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12790 * and return the key value for that item. This is used when available to look up the key on items that
12791 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12792 * equivalent to providing an implementation for the {@link #getKey} method.
12794 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12802 * Fires when the collection is cleared.
12807 * Fires when an item is added to the collection.
12808 * @param {Number} index The index at which the item was added.
12809 * @param {Object} o The item added.
12810 * @param {String} key The key associated with the added item.
12815 * Fires when an item is replaced in the collection.
12816 * @param {String} key he key associated with the new added.
12817 * @param {Object} old The item being replaced.
12818 * @param {Object} new The new item.
12823 * Fires when an item is removed from the collection.
12824 * @param {Object} o The item being removed.
12825 * @param {String} key (optional) The key associated with the removed item.
12830 this.allowFunctions = allowFunctions === true;
12832 this.getKey = keyFn;
12834 Roo.util.MixedCollection.superclass.constructor.call(this);
12837 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12838 allowFunctions : false,
12841 * Adds an item to the collection.
12842 * @param {String} key The key to associate with the item
12843 * @param {Object} o The item to add.
12844 * @return {Object} The item added.
12846 add : function(key, o){
12847 if(arguments.length == 1){
12849 key = this.getKey(o);
12851 if(typeof key == "undefined" || key === null){
12853 this.items.push(o);
12854 this.keys.push(null);
12856 var old = this.map[key];
12858 return this.replace(key, o);
12861 this.items.push(o);
12863 this.keys.push(key);
12865 this.fireEvent("add", this.length-1, o, key);
12870 * MixedCollection has a generic way to fetch keys if you implement getKey.
12873 var mc = new Roo.util.MixedCollection();
12874 mc.add(someEl.dom.id, someEl);
12875 mc.add(otherEl.dom.id, otherEl);
12879 var mc = new Roo.util.MixedCollection();
12880 mc.getKey = function(el){
12886 // or via the constructor
12887 var mc = new Roo.util.MixedCollection(false, function(el){
12893 * @param o {Object} The item for which to find the key.
12894 * @return {Object} The key for the passed item.
12896 getKey : function(o){
12901 * Replaces an item in the collection.
12902 * @param {String} key The key associated with the item to replace, or the item to replace.
12903 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12904 * @return {Object} The new item.
12906 replace : function(key, o){
12907 if(arguments.length == 1){
12909 key = this.getKey(o);
12911 var old = this.item(key);
12912 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12913 return this.add(key, o);
12915 var index = this.indexOfKey(key);
12916 this.items[index] = o;
12918 this.fireEvent("replace", key, old, o);
12923 * Adds all elements of an Array or an Object to the collection.
12924 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12925 * an Array of values, each of which are added to the collection.
12927 addAll : function(objs){
12928 if(arguments.length > 1 || objs instanceof Array){
12929 var args = arguments.length > 1 ? arguments : objs;
12930 for(var i = 0, len = args.length; i < len; i++){
12934 for(var key in objs){
12935 if(this.allowFunctions || typeof objs[key] != "function"){
12936 this.add(key, objs[key]);
12943 * Executes the specified function once for every item in the collection, passing each
12944 * item as the first and only parameter. returning false from the function will stop the iteration.
12945 * @param {Function} fn The function to execute for each item.
12946 * @param {Object} scope (optional) The scope in which to execute the function.
12948 each : function(fn, scope){
12949 var items = [].concat(this.items); // each safe for removal
12950 for(var i = 0, len = items.length; i < len; i++){
12951 if(fn.call(scope || items[i], items[i], i, len) === false){
12958 * Executes the specified function once for every key in the collection, passing each
12959 * key, and its associated item as the first two parameters.
12960 * @param {Function} fn The function to execute for each item.
12961 * @param {Object} scope (optional) The scope in which to execute the function.
12963 eachKey : function(fn, scope){
12964 for(var i = 0, len = this.keys.length; i < len; i++){
12965 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12970 * Returns the first item in the collection which elicits a true return value from the
12971 * passed selection function.
12972 * @param {Function} fn The selection function to execute for each item.
12973 * @param {Object} scope (optional) The scope in which to execute the function.
12974 * @return {Object} The first item in the collection which returned true from the selection function.
12976 find : function(fn, scope){
12977 for(var i = 0, len = this.items.length; i < len; i++){
12978 if(fn.call(scope || window, this.items[i], this.keys[i])){
12979 return this.items[i];
12986 * Inserts an item at the specified index in the collection.
12987 * @param {Number} index The index to insert the item at.
12988 * @param {String} key The key to associate with the new item, or the item itself.
12989 * @param {Object} o (optional) If the second parameter was a key, the new item.
12990 * @return {Object} The item inserted.
12992 insert : function(index, key, o){
12993 if(arguments.length == 2){
12995 key = this.getKey(o);
12997 if(index >= this.length){
12998 return this.add(key, o);
13001 this.items.splice(index, 0, o);
13002 if(typeof key != "undefined" && key != null){
13005 this.keys.splice(index, 0, key);
13006 this.fireEvent("add", index, o, key);
13011 * Removed an item from the collection.
13012 * @param {Object} o The item to remove.
13013 * @return {Object} The item removed.
13015 remove : function(o){
13016 return this.removeAt(this.indexOf(o));
13020 * Remove an item from a specified index in the collection.
13021 * @param {Number} index The index within the collection of the item to remove.
13023 removeAt : function(index){
13024 if(index < this.length && index >= 0){
13026 var o = this.items[index];
13027 this.items.splice(index, 1);
13028 var key = this.keys[index];
13029 if(typeof key != "undefined"){
13030 delete this.map[key];
13032 this.keys.splice(index, 1);
13033 this.fireEvent("remove", o, key);
13038 * Removed an item associated with the passed key fom the collection.
13039 * @param {String} key The key of the item to remove.
13041 removeKey : function(key){
13042 return this.removeAt(this.indexOfKey(key));
13046 * Returns the number of items in the collection.
13047 * @return {Number} the number of items in the collection.
13049 getCount : function(){
13050 return this.length;
13054 * Returns index within the collection of the passed Object.
13055 * @param {Object} o The item to find the index of.
13056 * @return {Number} index of the item.
13058 indexOf : function(o){
13059 if(!this.items.indexOf){
13060 for(var i = 0, len = this.items.length; i < len; i++){
13061 if(this.items[i] == o) return i;
13065 return this.items.indexOf(o);
13070 * Returns index within the collection of the passed key.
13071 * @param {String} key The key to find the index of.
13072 * @return {Number} index of the key.
13074 indexOfKey : function(key){
13075 if(!this.keys.indexOf){
13076 for(var i = 0, len = this.keys.length; i < len; i++){
13077 if(this.keys[i] == key) return i;
13081 return this.keys.indexOf(key);
13086 * Returns the item associated with the passed key OR index. Key has priority over index.
13087 * @param {String/Number} key The key or index of the item.
13088 * @return {Object} The item associated with the passed key.
13090 item : function(key){
13091 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13092 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13096 * Returns the item at the specified index.
13097 * @param {Number} index The index of the item.
13100 itemAt : function(index){
13101 return this.items[index];
13105 * Returns the item associated with the passed key.
13106 * @param {String/Number} key The key of the item.
13107 * @return {Object} The item associated with the passed key.
13109 key : function(key){
13110 return this.map[key];
13114 * Returns true if the collection contains the passed Object as an item.
13115 * @param {Object} o The Object to look for in the collection.
13116 * @return {Boolean} True if the collection contains the Object as an item.
13118 contains : function(o){
13119 return this.indexOf(o) != -1;
13123 * Returns true if the collection contains the passed Object as a key.
13124 * @param {String} key The key to look for in the collection.
13125 * @return {Boolean} True if the collection contains the Object as a key.
13127 containsKey : function(key){
13128 return typeof this.map[key] != "undefined";
13132 * Removes all items from the collection.
13134 clear : function(){
13139 this.fireEvent("clear");
13143 * Returns the first item in the collection.
13144 * @return {Object} the first item in the collection..
13146 first : function(){
13147 return this.items[0];
13151 * Returns the last item in the collection.
13152 * @return {Object} the last item in the collection..
13155 return this.items[this.length-1];
13158 _sort : function(property, dir, fn){
13159 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13160 fn = fn || function(a, b){
13163 var c = [], k = this.keys, items = this.items;
13164 for(var i = 0, len = items.length; i < len; i++){
13165 c[c.length] = {key: k[i], value: items[i], index: i};
13167 c.sort(function(a, b){
13168 var v = fn(a[property], b[property]) * dsc;
13170 v = (a.index < b.index ? -1 : 1);
13174 for(var i = 0, len = c.length; i < len; i++){
13175 items[i] = c[i].value;
13178 this.fireEvent("sort", this);
13182 * Sorts this collection with the passed comparison function
13183 * @param {String} direction (optional) "ASC" or "DESC"
13184 * @param {Function} fn (optional) comparison function
13186 sort : function(dir, fn){
13187 this._sort("value", dir, fn);
13191 * Sorts this collection by keys
13192 * @param {String} direction (optional) "ASC" or "DESC"
13193 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13195 keySort : function(dir, fn){
13196 this._sort("key", dir, fn || function(a, b){
13197 return String(a).toUpperCase()-String(b).toUpperCase();
13202 * Returns a range of items in this collection
13203 * @param {Number} startIndex (optional) defaults to 0
13204 * @param {Number} endIndex (optional) default to the last item
13205 * @return {Array} An array of items
13207 getRange : function(start, end){
13208 var items = this.items;
13209 if(items.length < 1){
13212 start = start || 0;
13213 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13216 for(var i = start; i <= end; i++) {
13217 r[r.length] = items[i];
13220 for(var i = start; i >= end; i--) {
13221 r[r.length] = items[i];
13228 * Filter the <i>objects</i> in this collection by a specific property.
13229 * Returns a new collection that has been filtered.
13230 * @param {String} property A property on your objects
13231 * @param {String/RegExp} value Either string that the property values
13232 * should start with or a RegExp to test against the property
13233 * @return {MixedCollection} The new filtered collection
13235 filter : function(property, value){
13236 if(!value.exec){ // not a regex
13237 value = String(value);
13238 if(value.length == 0){
13239 return this.clone();
13241 value = new RegExp("^" + Roo.escapeRe(value), "i");
13243 return this.filterBy(function(o){
13244 return o && value.test(o[property]);
13249 * Filter by a function. * Returns a new collection that has been filtered.
13250 * The passed function will be called with each
13251 * object in the collection. If the function returns true, the value is included
13252 * otherwise it is filtered.
13253 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13254 * @param {Object} scope (optional) The scope of the function (defaults to this)
13255 * @return {MixedCollection} The new filtered collection
13257 filterBy : function(fn, scope){
13258 var r = new Roo.util.MixedCollection();
13259 r.getKey = this.getKey;
13260 var k = this.keys, it = this.items;
13261 for(var i = 0, len = it.length; i < len; i++){
13262 if(fn.call(scope||this, it[i], k[i])){
13263 r.add(k[i], it[i]);
13270 * Creates a duplicate of this collection
13271 * @return {MixedCollection}
13273 clone : function(){
13274 var r = new Roo.util.MixedCollection();
13275 var k = this.keys, it = this.items;
13276 for(var i = 0, len = it.length; i < len; i++){
13277 r.add(k[i], it[i]);
13279 r.getKey = this.getKey;
13284 * Returns the item associated with the passed key or index.
13286 * @param {String/Number} key The key or index of the item.
13287 * @return {Object} The item associated with the passed key.
13289 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13291 * Ext JS Library 1.1.1
13292 * Copyright(c) 2006-2007, Ext JS, LLC.
13294 * Originally Released Under LGPL - original licence link has changed is not relivant.
13297 * <script type="text/javascript">
13300 * @class Roo.util.JSON
13301 * Modified version of Douglas Crockford"s json.js that doesn"t
13302 * mess with the Object prototype
13303 * http://www.json.org/js.html
13306 Roo.util.JSON = new (function(){
13307 var useHasOwn = {}.hasOwnProperty ? true : false;
13309 // crashes Safari in some instances
13310 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13312 var pad = function(n) {
13313 return n < 10 ? "0" + n : n;
13326 var encodeString = function(s){
13327 if (/["\\\x00-\x1f]/.test(s)) {
13328 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13333 c = b.charCodeAt();
13335 Math.floor(c / 16).toString(16) +
13336 (c % 16).toString(16);
13339 return '"' + s + '"';
13342 var encodeArray = function(o){
13343 var a = ["["], b, i, l = o.length, v;
13344 for (i = 0; i < l; i += 1) {
13346 switch (typeof v) {
13355 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13363 var encodeDate = function(o){
13364 return '"' + o.getFullYear() + "-" +
13365 pad(o.getMonth() + 1) + "-" +
13366 pad(o.getDate()) + "T" +
13367 pad(o.getHours()) + ":" +
13368 pad(o.getMinutes()) + ":" +
13369 pad(o.getSeconds()) + '"';
13373 * Encodes an Object, Array or other value
13374 * @param {Mixed} o The variable to encode
13375 * @return {String} The JSON string
13377 this.encode = function(o)
13379 // should this be extended to fully wrap stringify..
13381 if(typeof o == "undefined" || o === null){
13383 }else if(o instanceof Array){
13384 return encodeArray(o);
13385 }else if(o instanceof Date){
13386 return encodeDate(o);
13387 }else if(typeof o == "string"){
13388 return encodeString(o);
13389 }else if(typeof o == "number"){
13390 return isFinite(o) ? String(o) : "null";
13391 }else if(typeof o == "boolean"){
13394 var a = ["{"], b, i, v;
13396 if(!useHasOwn || o.hasOwnProperty(i)) {
13398 switch (typeof v) {
13407 a.push(this.encode(i), ":",
13408 v === null ? "null" : this.encode(v));
13419 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13420 * @param {String} json The JSON string
13421 * @return {Object} The resulting object
13423 this.decode = function(json){
13425 return /** eval:var:json */ eval("(" + json + ')');
13429 * Shorthand for {@link Roo.util.JSON#encode}
13430 * @member Roo encode
13432 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13434 * Shorthand for {@link Roo.util.JSON#decode}
13435 * @member Roo decode
13437 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13440 * Ext JS Library 1.1.1
13441 * Copyright(c) 2006-2007, Ext JS, LLC.
13443 * Originally Released Under LGPL - original licence link has changed is not relivant.
13446 * <script type="text/javascript">
13450 * @class Roo.util.Format
13451 * Reusable data formatting functions
13454 Roo.util.Format = function(){
13455 var trimRe = /^\s+|\s+$/g;
13458 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13459 * @param {String} value The string to truncate
13460 * @param {Number} length The maximum length to allow before truncating
13461 * @return {String} The converted text
13463 ellipsis : function(value, len){
13464 if(value && value.length > len){
13465 return value.substr(0, len-3)+"...";
13471 * Checks a reference and converts it to empty string if it is undefined
13472 * @param {Mixed} value Reference to check
13473 * @return {Mixed} Empty string if converted, otherwise the original value
13475 undef : function(value){
13476 return typeof value != "undefined" ? value : "";
13480 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13481 * @param {String} value The string to encode
13482 * @return {String} The encoded text
13484 htmlEncode : function(value){
13485 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13489 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13490 * @param {String} value The string to decode
13491 * @return {String} The decoded text
13493 htmlDecode : function(value){
13494 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13498 * Trims any whitespace from either side of a string
13499 * @param {String} value The text to trim
13500 * @return {String} The trimmed text
13502 trim : function(value){
13503 return String(value).replace(trimRe, "");
13507 * Returns a substring from within an original string
13508 * @param {String} value The original text
13509 * @param {Number} start The start index of the substring
13510 * @param {Number} length The length of the substring
13511 * @return {String} The substring
13513 substr : function(value, start, length){
13514 return String(value).substr(start, length);
13518 * Converts a string to all lower case letters
13519 * @param {String} value The text to convert
13520 * @return {String} The converted text
13522 lowercase : function(value){
13523 return String(value).toLowerCase();
13527 * Converts a string to all upper case letters
13528 * @param {String} value The text to convert
13529 * @return {String} The converted text
13531 uppercase : function(value){
13532 return String(value).toUpperCase();
13536 * Converts the first character only of a string to upper case
13537 * @param {String} value The text to convert
13538 * @return {String} The converted text
13540 capitalize : function(value){
13541 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13545 call : function(value, fn){
13546 if(arguments.length > 2){
13547 var args = Array.prototype.slice.call(arguments, 2);
13548 args.unshift(value);
13550 return /** eval:var:value */ eval(fn).apply(window, args);
13552 /** eval:var:value */
13553 return /** eval:var:value */ eval(fn).call(window, value);
13559 * safer version of Math.toFixed..??/
13560 * @param {Number/String} value The numeric value to format
13561 * @param {Number/String} value Decimal places
13562 * @return {String} The formatted currency string
13564 toFixed : function(v, n)
13566 // why not use to fixed - precision is buggered???
13568 return Math.round(v-0);
13570 var fact = Math.pow(10,n+1);
13571 v = (Math.round((v-0)*fact))/fact;
13572 var z = (''+fact).substring(2);
13573 if (v == Math.floor(v)) {
13574 return Math.floor(v) + '.' + z;
13577 // now just padd decimals..
13578 var ps = String(v).split('.');
13579 var fd = (ps[1] + z);
13580 var r = fd.substring(0,n);
13581 var rm = fd.substring(n);
13583 return ps[0] + '.' + r;
13585 r*=1; // turn it into a number;
13587 if (String(r).length != n) {
13590 r = String(r).substring(1); // chop the end off.
13593 return ps[0] + '.' + r;
13598 * Format a number as US currency
13599 * @param {Number/String} value The numeric value to format
13600 * @return {String} The formatted currency string
13602 usMoney : function(v){
13603 return '$' + Roo.util.Format.number(v);
13608 * eventually this should probably emulate php's number_format
13609 * @param {Number/String} value The numeric value to format
13610 * @param {Number} decimals number of decimal places
13611 * @return {String} The formatted currency string
13613 number : function(v,decimals)
13615 // multiply and round.
13616 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13617 var mul = Math.pow(10, decimals);
13618 var zero = String(mul).substring(1);
13619 v = (Math.round((v-0)*mul))/mul;
13621 // if it's '0' number.. then
13623 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13625 var ps = v.split('.');
13629 var r = /(\d+)(\d{3})/;
13631 while (r.test(whole)) {
13632 whole = whole.replace(r, '$1' + ',' + '$2');
13638 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13639 // does not have decimals
13640 (decimals ? ('.' + zero) : '');
13643 return whole + sub ;
13647 * Parse a value into a formatted date using the specified format pattern.
13648 * @param {Mixed} value The value to format
13649 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13650 * @return {String} The formatted date string
13652 date : function(v, format){
13656 if(!(v instanceof Date)){
13657 v = new Date(Date.parse(v));
13659 return v.dateFormat(format || Roo.util.Format.defaults.date);
13663 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13664 * @param {String} format Any valid date format string
13665 * @return {Function} The date formatting function
13667 dateRenderer : function(format){
13668 return function(v){
13669 return Roo.util.Format.date(v, format);
13674 stripTagsRE : /<\/?[^>]+>/gi,
13677 * Strips all HTML tags
13678 * @param {Mixed} value The text from which to strip tags
13679 * @return {String} The stripped text
13681 stripTags : function(v){
13682 return !v ? v : String(v).replace(this.stripTagsRE, "");
13686 Roo.util.Format.defaults = {
13690 * Ext JS Library 1.1.1
13691 * Copyright(c) 2006-2007, Ext JS, LLC.
13693 * Originally Released Under LGPL - original licence link has changed is not relivant.
13696 * <script type="text/javascript">
13703 * @class Roo.MasterTemplate
13704 * @extends Roo.Template
13705 * Provides a template that can have child templates. The syntax is:
13707 var t = new Roo.MasterTemplate(
13708 '<select name="{name}">',
13709 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13712 t.add('options', {value: 'foo', text: 'bar'});
13713 // or you can add multiple child elements in one shot
13714 t.addAll('options', [
13715 {value: 'foo', text: 'bar'},
13716 {value: 'foo2', text: 'bar2'},
13717 {value: 'foo3', text: 'bar3'}
13719 // then append, applying the master template values
13720 t.append('my-form', {name: 'my-select'});
13722 * A name attribute for the child template is not required if you have only one child
13723 * template or you want to refer to them by index.
13725 Roo.MasterTemplate = function(){
13726 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13727 this.originalHtml = this.html;
13729 var m, re = this.subTemplateRe;
13732 while(m = re.exec(this.html)){
13733 var name = m[1], content = m[2];
13738 tpl : new Roo.Template(content)
13741 st[name] = st[subIndex];
13743 st[subIndex].tpl.compile();
13744 st[subIndex].tpl.call = this.call.createDelegate(this);
13747 this.subCount = subIndex;
13750 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13752 * The regular expression used to match sub templates
13756 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13759 * Applies the passed values to a child template.
13760 * @param {String/Number} name (optional) The name or index of the child template
13761 * @param {Array/Object} values The values to be applied to the template
13762 * @return {MasterTemplate} this
13764 add : function(name, values){
13765 if(arguments.length == 1){
13766 values = arguments[0];
13769 var s = this.subs[name];
13770 s.buffer[s.buffer.length] = s.tpl.apply(values);
13775 * Applies all the passed values to a child template.
13776 * @param {String/Number} name (optional) The name or index of the child template
13777 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13778 * @param {Boolean} reset (optional) True to reset the template first
13779 * @return {MasterTemplate} this
13781 fill : function(name, values, reset){
13783 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13791 for(var i = 0, len = values.length; i < len; i++){
13792 this.add(name, values[i]);
13798 * Resets the template for reuse
13799 * @return {MasterTemplate} this
13801 reset : function(){
13803 for(var i = 0; i < this.subCount; i++){
13809 applyTemplate : function(values){
13811 var replaceIndex = -1;
13812 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13813 return s[++replaceIndex].buffer.join("");
13815 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13818 apply : function(){
13819 return this.applyTemplate.apply(this, arguments);
13822 compile : function(){return this;}
13826 * Alias for fill().
13829 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13831 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13832 * var tpl = Roo.MasterTemplate.from('element-id');
13833 * @param {String/HTMLElement} el
13834 * @param {Object} config
13837 Roo.MasterTemplate.from = function(el, config){
13838 el = Roo.getDom(el);
13839 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13842 * Ext JS Library 1.1.1
13843 * Copyright(c) 2006-2007, Ext JS, LLC.
13845 * Originally Released Under LGPL - original licence link has changed is not relivant.
13848 * <script type="text/javascript">
13853 * @class Roo.util.CSS
13854 * Utility class for manipulating CSS rules
13857 Roo.util.CSS = function(){
13859 var doc = document;
13861 var camelRe = /(-[a-z])/gi;
13862 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13866 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13867 * tag and appended to the HEAD of the document.
13868 * @param {String|Object} cssText The text containing the css rules
13869 * @param {String} id An id to add to the stylesheet for later removal
13870 * @return {StyleSheet}
13872 createStyleSheet : function(cssText, id){
13874 var head = doc.getElementsByTagName("head")[0];
13875 var nrules = doc.createElement("style");
13876 nrules.setAttribute("type", "text/css");
13878 nrules.setAttribute("id", id);
13880 if (typeof(cssText) != 'string') {
13881 // support object maps..
13882 // not sure if this a good idea..
13883 // perhaps it should be merged with the general css handling
13884 // and handle js style props.
13885 var cssTextNew = [];
13886 for(var n in cssText) {
13888 for(var k in cssText[n]) {
13889 citems.push( k + ' : ' +cssText[n][k] + ';' );
13891 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13894 cssText = cssTextNew.join("\n");
13900 head.appendChild(nrules);
13901 ss = nrules.styleSheet;
13902 ss.cssText = cssText;
13905 nrules.appendChild(doc.createTextNode(cssText));
13907 nrules.cssText = cssText;
13909 head.appendChild(nrules);
13910 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13912 this.cacheStyleSheet(ss);
13917 * Removes a style or link tag by id
13918 * @param {String} id The id of the tag
13920 removeStyleSheet : function(id){
13921 var existing = doc.getElementById(id);
13923 existing.parentNode.removeChild(existing);
13928 * Dynamically swaps an existing stylesheet reference for a new one
13929 * @param {String} id The id of an existing link tag to remove
13930 * @param {String} url The href of the new stylesheet to include
13932 swapStyleSheet : function(id, url){
13933 this.removeStyleSheet(id);
13934 var ss = doc.createElement("link");
13935 ss.setAttribute("rel", "stylesheet");
13936 ss.setAttribute("type", "text/css");
13937 ss.setAttribute("id", id);
13938 ss.setAttribute("href", url);
13939 doc.getElementsByTagName("head")[0].appendChild(ss);
13943 * Refresh the rule cache if you have dynamically added stylesheets
13944 * @return {Object} An object (hash) of rules indexed by selector
13946 refreshCache : function(){
13947 return this.getRules(true);
13951 cacheStyleSheet : function(stylesheet){
13955 try{// try catch for cross domain access issue
13956 var ssRules = stylesheet.cssRules || stylesheet.rules;
13957 for(var j = ssRules.length-1; j >= 0; --j){
13958 rules[ssRules[j].selectorText] = ssRules[j];
13964 * Gets all css rules for the document
13965 * @param {Boolean} refreshCache true to refresh the internal cache
13966 * @return {Object} An object (hash) of rules indexed by selector
13968 getRules : function(refreshCache){
13969 if(rules == null || refreshCache){
13971 var ds = doc.styleSheets;
13972 for(var i =0, len = ds.length; i < len; i++){
13974 this.cacheStyleSheet(ds[i]);
13982 * Gets an an individual CSS rule by selector(s)
13983 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13984 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13985 * @return {CSSRule} The CSS rule or null if one is not found
13987 getRule : function(selector, refreshCache){
13988 var rs = this.getRules(refreshCache);
13989 if(!(selector instanceof Array)){
13990 return rs[selector];
13992 for(var i = 0; i < selector.length; i++){
13993 if(rs[selector[i]]){
13994 return rs[selector[i]];
14002 * Updates a rule property
14003 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14004 * @param {String} property The css property
14005 * @param {String} value The new value for the property
14006 * @return {Boolean} true If a rule was found and updated
14008 updateRule : function(selector, property, value){
14009 if(!(selector instanceof Array)){
14010 var rule = this.getRule(selector);
14012 rule.style[property.replace(camelRe, camelFn)] = value;
14016 for(var i = 0; i < selector.length; i++){
14017 if(this.updateRule(selector[i], property, value)){
14027 * Ext JS Library 1.1.1
14028 * Copyright(c) 2006-2007, Ext JS, LLC.
14030 * Originally Released Under LGPL - original licence link has changed is not relivant.
14033 * <script type="text/javascript">
14039 * @class Roo.util.ClickRepeater
14040 * @extends Roo.util.Observable
14042 * A wrapper class which can be applied to any element. Fires a "click" event while the
14043 * mouse is pressed. The interval between firings may be specified in the config but
14044 * defaults to 10 milliseconds.
14046 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14048 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14049 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14050 * Similar to an autorepeat key delay.
14051 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14052 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14053 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14054 * "interval" and "delay" are ignored. "immediate" is honored.
14055 * @cfg {Boolean} preventDefault True to prevent the default click event
14056 * @cfg {Boolean} stopDefault True to stop the default click event
14059 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14060 * 2007-02-02 jvs Renamed to ClickRepeater
14061 * 2007-02-03 jvs Modifications for FF Mac and Safari
14064 * @param {String/HTMLElement/Element} el The element to listen on
14065 * @param {Object} config
14067 Roo.util.ClickRepeater = function(el, config)
14069 this.el = Roo.get(el);
14070 this.el.unselectable();
14072 Roo.apply(this, config);
14077 * Fires when the mouse button is depressed.
14078 * @param {Roo.util.ClickRepeater} this
14080 "mousedown" : true,
14083 * Fires on a specified interval during the time the element is pressed.
14084 * @param {Roo.util.ClickRepeater} this
14089 * Fires when the mouse key is released.
14090 * @param {Roo.util.ClickRepeater} this
14095 this.el.on("mousedown", this.handleMouseDown, this);
14096 if(this.preventDefault || this.stopDefault){
14097 this.el.on("click", function(e){
14098 if(this.preventDefault){
14099 e.preventDefault();
14101 if(this.stopDefault){
14107 // allow inline handler
14109 this.on("click", this.handler, this.scope || this);
14112 Roo.util.ClickRepeater.superclass.constructor.call(this);
14115 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14118 preventDefault : true,
14119 stopDefault : false,
14123 handleMouseDown : function(){
14124 clearTimeout(this.timer);
14126 if(this.pressClass){
14127 this.el.addClass(this.pressClass);
14129 this.mousedownTime = new Date();
14131 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14132 this.el.on("mouseout", this.handleMouseOut, this);
14134 this.fireEvent("mousedown", this);
14135 this.fireEvent("click", this);
14137 this.timer = this.click.defer(this.delay || this.interval, this);
14141 click : function(){
14142 this.fireEvent("click", this);
14143 this.timer = this.click.defer(this.getInterval(), this);
14147 getInterval: function(){
14148 if(!this.accelerate){
14149 return this.interval;
14151 var pressTime = this.mousedownTime.getElapsed();
14152 if(pressTime < 500){
14154 }else if(pressTime < 1700){
14156 }else if(pressTime < 2600){
14158 }else if(pressTime < 3500){
14160 }else if(pressTime < 4400){
14162 }else if(pressTime < 5300){
14164 }else if(pressTime < 6200){
14172 handleMouseOut : function(){
14173 clearTimeout(this.timer);
14174 if(this.pressClass){
14175 this.el.removeClass(this.pressClass);
14177 this.el.on("mouseover", this.handleMouseReturn, this);
14181 handleMouseReturn : function(){
14182 this.el.un("mouseover", this.handleMouseReturn);
14183 if(this.pressClass){
14184 this.el.addClass(this.pressClass);
14190 handleMouseUp : function(){
14191 clearTimeout(this.timer);
14192 this.el.un("mouseover", this.handleMouseReturn);
14193 this.el.un("mouseout", this.handleMouseOut);
14194 Roo.get(document).un("mouseup", this.handleMouseUp);
14195 this.el.removeClass(this.pressClass);
14196 this.fireEvent("mouseup", this);
14200 * Ext JS Library 1.1.1
14201 * Copyright(c) 2006-2007, Ext JS, LLC.
14203 * Originally Released Under LGPL - original licence link has changed is not relivant.
14206 * <script type="text/javascript">
14211 * @class Roo.KeyNav
14212 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14213 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14214 * way to implement custom navigation schemes for any UI component.</p>
14215 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14216 * pageUp, pageDown, del, home, end. Usage:</p>
14218 var nav = new Roo.KeyNav("my-element", {
14219 "left" : function(e){
14220 this.moveLeft(e.ctrlKey);
14222 "right" : function(e){
14223 this.moveRight(e.ctrlKey);
14225 "enter" : function(e){
14232 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14233 * @param {Object} config The config
14235 Roo.KeyNav = function(el, config){
14236 this.el = Roo.get(el);
14237 Roo.apply(this, config);
14238 if(!this.disabled){
14239 this.disabled = true;
14244 Roo.KeyNav.prototype = {
14246 * @cfg {Boolean} disabled
14247 * True to disable this KeyNav instance (defaults to false)
14251 * @cfg {String} defaultEventAction
14252 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14253 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14254 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14256 defaultEventAction: "stopEvent",
14258 * @cfg {Boolean} forceKeyDown
14259 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14260 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14261 * handle keydown instead of keypress.
14263 forceKeyDown : false,
14266 prepareEvent : function(e){
14267 var k = e.getKey();
14268 var h = this.keyToHandler[k];
14269 //if(h && this[h]){
14270 // e.stopPropagation();
14272 if(Roo.isSafari && h && k >= 37 && k <= 40){
14278 relay : function(e){
14279 var k = e.getKey();
14280 var h = this.keyToHandler[k];
14282 if(this.doRelay(e, this[h], h) !== true){
14283 e[this.defaultEventAction]();
14289 doRelay : function(e, h, hname){
14290 return h.call(this.scope || this, e);
14293 // possible handlers
14307 // quick lookup hash
14324 * Enable this KeyNav
14326 enable: function(){
14328 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14329 // the EventObject will normalize Safari automatically
14330 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14331 this.el.on("keydown", this.relay, this);
14333 this.el.on("keydown", this.prepareEvent, this);
14334 this.el.on("keypress", this.relay, this);
14336 this.disabled = false;
14341 * Disable this KeyNav
14343 disable: function(){
14344 if(!this.disabled){
14345 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14346 this.el.un("keydown", this.relay);
14348 this.el.un("keydown", this.prepareEvent);
14349 this.el.un("keypress", this.relay);
14351 this.disabled = true;
14356 * Ext JS Library 1.1.1
14357 * Copyright(c) 2006-2007, Ext JS, LLC.
14359 * Originally Released Under LGPL - original licence link has changed is not relivant.
14362 * <script type="text/javascript">
14367 * @class Roo.KeyMap
14368 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14369 * The constructor accepts the same config object as defined by {@link #addBinding}.
14370 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14371 * combination it will call the function with this signature (if the match is a multi-key
14372 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14373 * A KeyMap can also handle a string representation of keys.<br />
14376 // map one key by key code
14377 var map = new Roo.KeyMap("my-element", {
14378 key: 13, // or Roo.EventObject.ENTER
14383 // map multiple keys to one action by string
14384 var map = new Roo.KeyMap("my-element", {
14390 // map multiple keys to multiple actions by strings and array of codes
14391 var map = new Roo.KeyMap("my-element", [
14394 fn: function(){ alert("Return was pressed"); }
14397 fn: function(){ alert('a, b or c was pressed'); }
14402 fn: function(){ alert('Control + shift + tab was pressed.'); }
14406 * <b>Note: A KeyMap starts enabled</b>
14408 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14409 * @param {Object} config The config (see {@link #addBinding})
14410 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14412 Roo.KeyMap = function(el, config, eventName){
14413 this.el = Roo.get(el);
14414 this.eventName = eventName || "keydown";
14415 this.bindings = [];
14417 this.addBinding(config);
14422 Roo.KeyMap.prototype = {
14424 * True to stop the event from bubbling and prevent the default browser action if the
14425 * key was handled by the KeyMap (defaults to false)
14431 * Add a new binding to this KeyMap. The following config object properties are supported:
14433 Property Type Description
14434 ---------- --------------- ----------------------------------------------------------------------
14435 key String/Array A single keycode or an array of keycodes to handle
14436 shift Boolean True to handle key only when shift is pressed (defaults to false)
14437 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14438 alt Boolean True to handle key only when alt is pressed (defaults to false)
14439 fn Function The function to call when KeyMap finds the expected key combination
14440 scope Object The scope of the callback function
14446 var map = new Roo.KeyMap(document, {
14447 key: Roo.EventObject.ENTER,
14452 //Add a new binding to the existing KeyMap later
14460 * @param {Object/Array} config A single KeyMap config or an array of configs
14462 addBinding : function(config){
14463 if(config instanceof Array){
14464 for(var i = 0, len = config.length; i < len; i++){
14465 this.addBinding(config[i]);
14469 var keyCode = config.key,
14470 shift = config.shift,
14471 ctrl = config.ctrl,
14474 scope = config.scope;
14475 if(typeof keyCode == "string"){
14477 var keyString = keyCode.toUpperCase();
14478 for(var j = 0, len = keyString.length; j < len; j++){
14479 ks.push(keyString.charCodeAt(j));
14483 var keyArray = keyCode instanceof Array;
14484 var handler = function(e){
14485 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14486 var k = e.getKey();
14488 for(var i = 0, len = keyCode.length; i < len; i++){
14489 if(keyCode[i] == k){
14490 if(this.stopEvent){
14493 fn.call(scope || window, k, e);
14499 if(this.stopEvent){
14502 fn.call(scope || window, k, e);
14507 this.bindings.push(handler);
14511 * Shorthand for adding a single key listener
14512 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14513 * following options:
14514 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14515 * @param {Function} fn The function to call
14516 * @param {Object} scope (optional) The scope of the function
14518 on : function(key, fn, scope){
14519 var keyCode, shift, ctrl, alt;
14520 if(typeof key == "object" && !(key instanceof Array)){
14539 handleKeyDown : function(e){
14540 if(this.enabled){ //just in case
14541 var b = this.bindings;
14542 for(var i = 0, len = b.length; i < len; i++){
14543 b[i].call(this, e);
14549 * Returns true if this KeyMap is enabled
14550 * @return {Boolean}
14552 isEnabled : function(){
14553 return this.enabled;
14557 * Enables this KeyMap
14559 enable: function(){
14561 this.el.on(this.eventName, this.handleKeyDown, this);
14562 this.enabled = true;
14567 * Disable this KeyMap
14569 disable: function(){
14571 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14572 this.enabled = false;
14577 * Ext JS Library 1.1.1
14578 * Copyright(c) 2006-2007, Ext JS, LLC.
14580 * Originally Released Under LGPL - original licence link has changed is not relivant.
14583 * <script type="text/javascript">
14588 * @class Roo.util.TextMetrics
14589 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14590 * wide, in pixels, a given block of text will be.
14593 Roo.util.TextMetrics = function(){
14597 * Measures the size of the specified text
14598 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14599 * that can affect the size of the rendered text
14600 * @param {String} text The text to measure
14601 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14602 * in order to accurately measure the text height
14603 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14605 measure : function(el, text, fixedWidth){
14607 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14610 shared.setFixedWidth(fixedWidth || 'auto');
14611 return shared.getSize(text);
14615 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14616 * the overhead of multiple calls to initialize the style properties on each measurement.
14617 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14618 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14619 * in order to accurately measure the text height
14620 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14622 createInstance : function(el, fixedWidth){
14623 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14630 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14631 var ml = new Roo.Element(document.createElement('div'));
14632 document.body.appendChild(ml.dom);
14633 ml.position('absolute');
14634 ml.setLeftTop(-1000, -1000);
14638 ml.setWidth(fixedWidth);
14643 * Returns the size of the specified text based on the internal element's style and width properties
14644 * @memberOf Roo.util.TextMetrics.Instance#
14645 * @param {String} text The text to measure
14646 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14648 getSize : function(text){
14650 var s = ml.getSize();
14656 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14657 * that can affect the size of the rendered text
14658 * @memberOf Roo.util.TextMetrics.Instance#
14659 * @param {String/HTMLElement} el The element, dom node or id
14661 bind : function(el){
14663 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14668 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14669 * to set a fixed width in order to accurately measure the text height.
14670 * @memberOf Roo.util.TextMetrics.Instance#
14671 * @param {Number} width The width to set on the element
14673 setFixedWidth : function(width){
14674 ml.setWidth(width);
14678 * Returns the measured width of the specified text
14679 * @memberOf Roo.util.TextMetrics.Instance#
14680 * @param {String} text The text to measure
14681 * @return {Number} width The width in pixels
14683 getWidth : function(text){
14684 ml.dom.style.width = 'auto';
14685 return this.getSize(text).width;
14689 * Returns the measured height of the specified text. For multiline text, be sure to call
14690 * {@link #setFixedWidth} if necessary.
14691 * @memberOf Roo.util.TextMetrics.Instance#
14692 * @param {String} text The text to measure
14693 * @return {Number} height The height in pixels
14695 getHeight : function(text){
14696 return this.getSize(text).height;
14700 instance.bind(bindTo);
14705 // backwards compat
14706 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14708 * Ext JS Library 1.1.1
14709 * Copyright(c) 2006-2007, Ext JS, LLC.
14711 * Originally Released Under LGPL - original licence link has changed is not relivant.
14714 * <script type="text/javascript">
14718 * @class Roo.state.Provider
14719 * Abstract base class for state provider implementations. This class provides methods
14720 * for encoding and decoding <b>typed</b> variables including dates and defines the
14721 * Provider interface.
14723 Roo.state.Provider = function(){
14725 * @event statechange
14726 * Fires when a state change occurs.
14727 * @param {Provider} this This state provider
14728 * @param {String} key The state key which was changed
14729 * @param {String} value The encoded value for the state
14732 "statechange": true
14735 Roo.state.Provider.superclass.constructor.call(this);
14737 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14739 * Returns the current value for a key
14740 * @param {String} name The key name
14741 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14742 * @return {Mixed} The state data
14744 get : function(name, defaultValue){
14745 return typeof this.state[name] == "undefined" ?
14746 defaultValue : this.state[name];
14750 * Clears a value from the state
14751 * @param {String} name The key name
14753 clear : function(name){
14754 delete this.state[name];
14755 this.fireEvent("statechange", this, name, null);
14759 * Sets the value for a key
14760 * @param {String} name The key name
14761 * @param {Mixed} value The value to set
14763 set : function(name, value){
14764 this.state[name] = value;
14765 this.fireEvent("statechange", this, name, value);
14769 * Decodes a string previously encoded with {@link #encodeValue}.
14770 * @param {String} value The value to decode
14771 * @return {Mixed} The decoded value
14773 decodeValue : function(cookie){
14774 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14775 var matches = re.exec(unescape(cookie));
14776 if(!matches || !matches[1]) return; // non state cookie
14777 var type = matches[1];
14778 var v = matches[2];
14781 return parseFloat(v);
14783 return new Date(Date.parse(v));
14788 var values = v.split("^");
14789 for(var i = 0, len = values.length; i < len; i++){
14790 all.push(this.decodeValue(values[i]));
14795 var values = v.split("^");
14796 for(var i = 0, len = values.length; i < len; i++){
14797 var kv = values[i].split("=");
14798 all[kv[0]] = this.decodeValue(kv[1]);
14807 * Encodes a value including type information. Decode with {@link #decodeValue}.
14808 * @param {Mixed} value The value to encode
14809 * @return {String} The encoded value
14811 encodeValue : function(v){
14813 if(typeof v == "number"){
14815 }else if(typeof v == "boolean"){
14816 enc = "b:" + (v ? "1" : "0");
14817 }else if(v instanceof Date){
14818 enc = "d:" + v.toGMTString();
14819 }else if(v instanceof Array){
14821 for(var i = 0, len = v.length; i < len; i++){
14822 flat += this.encodeValue(v[i]);
14823 if(i != len-1) flat += "^";
14826 }else if(typeof v == "object"){
14829 if(typeof v[key] != "function"){
14830 flat += key + "=" + this.encodeValue(v[key]) + "^";
14833 enc = "o:" + flat.substring(0, flat.length-1);
14837 return escape(enc);
14843 * Ext JS Library 1.1.1
14844 * Copyright(c) 2006-2007, Ext JS, LLC.
14846 * Originally Released Under LGPL - original licence link has changed is not relivant.
14849 * <script type="text/javascript">
14852 * @class Roo.state.Manager
14853 * This is the global state manager. By default all components that are "state aware" check this class
14854 * for state information if you don't pass them a custom state provider. In order for this class
14855 * to be useful, it must be initialized with a provider when your application initializes.
14857 // in your initialization function
14859 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14861 // supposed you have a {@link Roo.BorderLayout}
14862 var layout = new Roo.BorderLayout(...);
14863 layout.restoreState();
14864 // or a {Roo.BasicDialog}
14865 var dialog = new Roo.BasicDialog(...);
14866 dialog.restoreState();
14870 Roo.state.Manager = function(){
14871 var provider = new Roo.state.Provider();
14875 * Configures the default state provider for your application
14876 * @param {Provider} stateProvider The state provider to set
14878 setProvider : function(stateProvider){
14879 provider = stateProvider;
14883 * Returns the current value for a key
14884 * @param {String} name The key name
14885 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14886 * @return {Mixed} The state data
14888 get : function(key, defaultValue){
14889 return provider.get(key, defaultValue);
14893 * Sets the value for a key
14894 * @param {String} name The key name
14895 * @param {Mixed} value The state data
14897 set : function(key, value){
14898 provider.set(key, value);
14902 * Clears a value from the state
14903 * @param {String} name The key name
14905 clear : function(key){
14906 provider.clear(key);
14910 * Gets the currently configured state provider
14911 * @return {Provider} The state provider
14913 getProvider : function(){
14920 * Ext JS Library 1.1.1
14921 * Copyright(c) 2006-2007, Ext JS, LLC.
14923 * Originally Released Under LGPL - original licence link has changed is not relivant.
14926 * <script type="text/javascript">
14929 * @class Roo.state.CookieProvider
14930 * @extends Roo.state.Provider
14931 * The default Provider implementation which saves state via cookies.
14934 var cp = new Roo.state.CookieProvider({
14936 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14937 domain: "roojs.com"
14939 Roo.state.Manager.setProvider(cp);
14941 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14942 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14943 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14944 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14945 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14946 * domain the page is running on including the 'www' like 'www.roojs.com')
14947 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14949 * Create a new CookieProvider
14950 * @param {Object} config The configuration object
14952 Roo.state.CookieProvider = function(config){
14953 Roo.state.CookieProvider.superclass.constructor.call(this);
14955 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14956 this.domain = null;
14957 this.secure = false;
14958 Roo.apply(this, config);
14959 this.state = this.readCookies();
14962 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14964 set : function(name, value){
14965 if(typeof value == "undefined" || value === null){
14969 this.setCookie(name, value);
14970 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14974 clear : function(name){
14975 this.clearCookie(name);
14976 Roo.state.CookieProvider.superclass.clear.call(this, name);
14980 readCookies : function(){
14982 var c = document.cookie + ";";
14983 var re = /\s?(.*?)=(.*?);/g;
14985 while((matches = re.exec(c)) != null){
14986 var name = matches[1];
14987 var value = matches[2];
14988 if(name && name.substring(0,3) == "ys-"){
14989 cookies[name.substr(3)] = this.decodeValue(value);
14996 setCookie : function(name, value){
14997 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14998 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14999 ((this.path == null) ? "" : ("; path=" + this.path)) +
15000 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15001 ((this.secure == true) ? "; secure" : "");
15005 clearCookie : function(name){
15006 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15007 ((this.path == null) ? "" : ("; path=" + this.path)) +
15008 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15009 ((this.secure == true) ? "; secure" : "");
15013 * Ext JS Library 1.1.1
15014 * Copyright(c) 2006-2007, Ext JS, LLC.
15016 * Originally Released Under LGPL - original licence link has changed is not relivant.
15019 * <script type="text/javascript">
15024 * @class Roo.ComponentMgr
15025 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15028 Roo.ComponentMgr = function(){
15029 var all = new Roo.util.MixedCollection();
15033 * Registers a component.
15034 * @param {Roo.Component} c The component
15036 register : function(c){
15041 * Unregisters a component.
15042 * @param {Roo.Component} c The component
15044 unregister : function(c){
15049 * Returns a component by id
15050 * @param {String} id The component id
15052 get : function(id){
15053 return all.get(id);
15057 * Registers a function that will be called when a specified component is added to ComponentMgr
15058 * @param {String} id The component id
15059 * @param {Funtction} fn The callback function
15060 * @param {Object} scope The scope of the callback
15062 onAvailable : function(id, fn, scope){
15063 all.on("add", function(index, o){
15065 fn.call(scope || o, o);
15066 all.un("add", fn, scope);
15073 * Ext JS Library 1.1.1
15074 * Copyright(c) 2006-2007, Ext JS, LLC.
15076 * Originally Released Under LGPL - original licence link has changed is not relivant.
15079 * <script type="text/javascript">
15083 * @class Roo.Component
15084 * @extends Roo.util.Observable
15085 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15086 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15087 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15088 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15089 * All visual components (widgets) that require rendering into a layout should subclass Component.
15091 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15092 * 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
15093 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15095 Roo.Component = function(config){
15096 config = config || {};
15097 if(config.tagName || config.dom || typeof config == "string"){ // element object
15098 config = {el: config, id: config.id || config};
15100 this.initialConfig = config;
15102 Roo.apply(this, config);
15106 * Fires after the component is disabled.
15107 * @param {Roo.Component} this
15112 * Fires after the component is enabled.
15113 * @param {Roo.Component} this
15117 * @event beforeshow
15118 * Fires before the component is shown. Return false to stop the show.
15119 * @param {Roo.Component} this
15124 * Fires after the component is shown.
15125 * @param {Roo.Component} this
15129 * @event beforehide
15130 * Fires before the component is hidden. Return false to stop the hide.
15131 * @param {Roo.Component} this
15136 * Fires after the component is hidden.
15137 * @param {Roo.Component} this
15141 * @event beforerender
15142 * Fires before the component is rendered. Return false to stop the render.
15143 * @param {Roo.Component} this
15145 beforerender : true,
15148 * Fires after the component is rendered.
15149 * @param {Roo.Component} this
15153 * @event beforedestroy
15154 * Fires before the component is destroyed. Return false to stop the destroy.
15155 * @param {Roo.Component} this
15157 beforedestroy : true,
15160 * Fires after the component is destroyed.
15161 * @param {Roo.Component} this
15166 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15168 Roo.ComponentMgr.register(this);
15169 Roo.Component.superclass.constructor.call(this);
15170 this.initComponent();
15171 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15172 this.render(this.renderTo);
15173 delete this.renderTo;
15178 Roo.Component.AUTO_ID = 1000;
15180 Roo.extend(Roo.Component, Roo.util.Observable, {
15182 * @scope Roo.Component.prototype
15184 * true if this component is hidden. Read-only.
15189 * true if this component is disabled. Read-only.
15194 * true if this component has been rendered. Read-only.
15198 /** @cfg {String} disableClass
15199 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15201 disabledClass : "x-item-disabled",
15202 /** @cfg {Boolean} allowDomMove
15203 * Whether the component can move the Dom node when rendering (defaults to true).
15205 allowDomMove : true,
15206 /** @cfg {String} hideMode
15207 * How this component should hidden. Supported values are
15208 * "visibility" (css visibility), "offsets" (negative offset position) and
15209 * "display" (css display) - defaults to "display".
15211 hideMode: 'display',
15214 ctype : "Roo.Component",
15217 * @cfg {String} actionMode
15218 * which property holds the element that used for hide() / show() / disable() / enable()
15224 getActionEl : function(){
15225 return this[this.actionMode];
15228 initComponent : Roo.emptyFn,
15230 * If this is a lazy rendering component, render it to its container element.
15231 * @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.
15233 render : function(container, position){
15234 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15235 if(!container && this.el){
15236 this.el = Roo.get(this.el);
15237 container = this.el.dom.parentNode;
15238 this.allowDomMove = false;
15240 this.container = Roo.get(container);
15241 this.rendered = true;
15242 if(position !== undefined){
15243 if(typeof position == 'number'){
15244 position = this.container.dom.childNodes[position];
15246 position = Roo.getDom(position);
15249 this.onRender(this.container, position || null);
15251 this.el.addClass(this.cls);
15255 this.el.applyStyles(this.style);
15258 this.fireEvent("render", this);
15259 this.afterRender(this.container);
15271 // default function is not really useful
15272 onRender : function(ct, position){
15274 this.el = Roo.get(this.el);
15275 if(this.allowDomMove !== false){
15276 ct.dom.insertBefore(this.el.dom, position);
15282 getAutoCreate : function(){
15283 var cfg = typeof this.autoCreate == "object" ?
15284 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15285 if(this.id && !cfg.id){
15292 afterRender : Roo.emptyFn,
15295 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15296 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15298 destroy : function(){
15299 if(this.fireEvent("beforedestroy", this) !== false){
15300 this.purgeListeners();
15301 this.beforeDestroy();
15303 this.el.removeAllListeners();
15305 if(this.actionMode == "container"){
15306 this.container.remove();
15310 Roo.ComponentMgr.unregister(this);
15311 this.fireEvent("destroy", this);
15316 beforeDestroy : function(){
15321 onDestroy : function(){
15326 * Returns the underlying {@link Roo.Element}.
15327 * @return {Roo.Element} The element
15329 getEl : function(){
15334 * Returns the id of this component.
15337 getId : function(){
15342 * Try to focus this component.
15343 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15344 * @return {Roo.Component} this
15346 focus : function(selectText){
15349 if(selectText === true){
15350 this.el.dom.select();
15365 * Disable this component.
15366 * @return {Roo.Component} this
15368 disable : function(){
15372 this.disabled = true;
15373 this.fireEvent("disable", this);
15378 onDisable : function(){
15379 this.getActionEl().addClass(this.disabledClass);
15380 this.el.dom.disabled = true;
15384 * Enable this component.
15385 * @return {Roo.Component} this
15387 enable : function(){
15391 this.disabled = false;
15392 this.fireEvent("enable", this);
15397 onEnable : function(){
15398 this.getActionEl().removeClass(this.disabledClass);
15399 this.el.dom.disabled = false;
15403 * Convenience function for setting disabled/enabled by boolean.
15404 * @param {Boolean} disabled
15406 setDisabled : function(disabled){
15407 this[disabled ? "disable" : "enable"]();
15411 * Show this component.
15412 * @return {Roo.Component} this
15415 if(this.fireEvent("beforeshow", this) !== false){
15416 this.hidden = false;
15420 this.fireEvent("show", this);
15426 onShow : function(){
15427 var ae = this.getActionEl();
15428 if(this.hideMode == 'visibility'){
15429 ae.dom.style.visibility = "visible";
15430 }else if(this.hideMode == 'offsets'){
15431 ae.removeClass('x-hidden');
15433 ae.dom.style.display = "";
15438 * Hide this component.
15439 * @return {Roo.Component} this
15442 if(this.fireEvent("beforehide", this) !== false){
15443 this.hidden = true;
15447 this.fireEvent("hide", this);
15453 onHide : function(){
15454 var ae = this.getActionEl();
15455 if(this.hideMode == 'visibility'){
15456 ae.dom.style.visibility = "hidden";
15457 }else if(this.hideMode == 'offsets'){
15458 ae.addClass('x-hidden');
15460 ae.dom.style.display = "none";
15465 * Convenience function to hide or show this component by boolean.
15466 * @param {Boolean} visible True to show, false to hide
15467 * @return {Roo.Component} this
15469 setVisible: function(visible){
15479 * Returns true if this component is visible.
15481 isVisible : function(){
15482 return this.getActionEl().isVisible();
15485 cloneConfig : function(overrides){
15486 overrides = overrides || {};
15487 var id = overrides.id || Roo.id();
15488 var cfg = Roo.applyIf(overrides, this.initialConfig);
15489 cfg.id = id; // prevent dup id
15490 return new this.constructor(cfg);
15494 * Ext JS Library 1.1.1
15495 * Copyright(c) 2006-2007, Ext JS, LLC.
15497 * Originally Released Under LGPL - original licence link has changed is not relivant.
15500 * <script type="text/javascript">
15504 * @class Roo.BoxComponent
15505 * @extends Roo.Component
15506 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15507 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15508 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15509 * layout containers.
15511 * @param {Roo.Element/String/Object} config The configuration options.
15513 Roo.BoxComponent = function(config){
15514 Roo.Component.call(this, config);
15518 * Fires after the component is resized.
15519 * @param {Roo.Component} this
15520 * @param {Number} adjWidth The box-adjusted width that was set
15521 * @param {Number} adjHeight The box-adjusted height that was set
15522 * @param {Number} rawWidth The width that was originally specified
15523 * @param {Number} rawHeight The height that was originally specified
15528 * Fires after the component is moved.
15529 * @param {Roo.Component} this
15530 * @param {Number} x The new x position
15531 * @param {Number} y The new y position
15537 Roo.extend(Roo.BoxComponent, Roo.Component, {
15538 // private, set in afterRender to signify that the component has been rendered
15540 // private, used to defer height settings to subclasses
15541 deferHeight: false,
15542 /** @cfg {Number} width
15543 * width (optional) size of component
15545 /** @cfg {Number} height
15546 * height (optional) size of component
15550 * Sets the width and height of the component. This method fires the resize event. This method can accept
15551 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15552 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15553 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15554 * @return {Roo.BoxComponent} this
15556 setSize : function(w, h){
15557 // support for standard size objects
15558 if(typeof w == 'object'){
15563 if(!this.boxReady){
15569 // prevent recalcs when not needed
15570 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15573 this.lastSize = {width: w, height: h};
15575 var adj = this.adjustSize(w, h);
15576 var aw = adj.width, ah = adj.height;
15577 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15578 var rz = this.getResizeEl();
15579 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15580 rz.setSize(aw, ah);
15581 }else if(!this.deferHeight && ah !== undefined){
15583 }else if(aw !== undefined){
15586 this.onResize(aw, ah, w, h);
15587 this.fireEvent('resize', this, aw, ah, w, h);
15593 * Gets the current size of the component's underlying element.
15594 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15596 getSize : function(){
15597 return this.el.getSize();
15601 * Gets the current XY position of the component's underlying element.
15602 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15603 * @return {Array} The XY position of the element (e.g., [100, 200])
15605 getPosition : function(local){
15606 if(local === true){
15607 return [this.el.getLeft(true), this.el.getTop(true)];
15609 return this.xy || this.el.getXY();
15613 * Gets the current box measurements of the component's underlying element.
15614 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15615 * @returns {Object} box An object in the format {x, y, width, height}
15617 getBox : function(local){
15618 var s = this.el.getSize();
15620 s.x = this.el.getLeft(true);
15621 s.y = this.el.getTop(true);
15623 var xy = this.xy || this.el.getXY();
15631 * Sets the current box measurements of the component's underlying element.
15632 * @param {Object} box An object in the format {x, y, width, height}
15633 * @returns {Roo.BoxComponent} this
15635 updateBox : function(box){
15636 this.setSize(box.width, box.height);
15637 this.setPagePosition(box.x, box.y);
15642 getResizeEl : function(){
15643 return this.resizeEl || this.el;
15647 getPositionEl : function(){
15648 return this.positionEl || this.el;
15652 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15653 * This method fires the move event.
15654 * @param {Number} left The new left
15655 * @param {Number} top The new top
15656 * @returns {Roo.BoxComponent} this
15658 setPosition : function(x, y){
15661 if(!this.boxReady){
15664 var adj = this.adjustPosition(x, y);
15665 var ax = adj.x, ay = adj.y;
15667 var el = this.getPositionEl();
15668 if(ax !== undefined || ay !== undefined){
15669 if(ax !== undefined && ay !== undefined){
15670 el.setLeftTop(ax, ay);
15671 }else if(ax !== undefined){
15673 }else if(ay !== undefined){
15676 this.onPosition(ax, ay);
15677 this.fireEvent('move', this, ax, ay);
15683 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15684 * This method fires the move event.
15685 * @param {Number} x The new x position
15686 * @param {Number} y The new y position
15687 * @returns {Roo.BoxComponent} this
15689 setPagePosition : function(x, y){
15692 if(!this.boxReady){
15695 if(x === undefined || y === undefined){ // cannot translate undefined points
15698 var p = this.el.translatePoints(x, y);
15699 this.setPosition(p.left, p.top);
15704 onRender : function(ct, position){
15705 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15707 this.resizeEl = Roo.get(this.resizeEl);
15709 if(this.positionEl){
15710 this.positionEl = Roo.get(this.positionEl);
15715 afterRender : function(){
15716 Roo.BoxComponent.superclass.afterRender.call(this);
15717 this.boxReady = true;
15718 this.setSize(this.width, this.height);
15719 if(this.x || this.y){
15720 this.setPosition(this.x, this.y);
15722 if(this.pageX || this.pageY){
15723 this.setPagePosition(this.pageX, this.pageY);
15728 * Force the component's size to recalculate based on the underlying element's current height and width.
15729 * @returns {Roo.BoxComponent} this
15731 syncSize : function(){
15732 delete this.lastSize;
15733 this.setSize(this.el.getWidth(), this.el.getHeight());
15738 * Called after the component is resized, this method is empty by default but can be implemented by any
15739 * subclass that needs to perform custom logic after a resize occurs.
15740 * @param {Number} adjWidth The box-adjusted width that was set
15741 * @param {Number} adjHeight The box-adjusted height that was set
15742 * @param {Number} rawWidth The width that was originally specified
15743 * @param {Number} rawHeight The height that was originally specified
15745 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15750 * Called after the component is moved, this method is empty by default but can be implemented by any
15751 * subclass that needs to perform custom logic after a move occurs.
15752 * @param {Number} x The new x position
15753 * @param {Number} y The new y position
15755 onPosition : function(x, y){
15760 adjustSize : function(w, h){
15761 if(this.autoWidth){
15764 if(this.autoHeight){
15767 return {width : w, height: h};
15771 adjustPosition : function(x, y){
15772 return {x : x, y: y};
15775 * Original code for Roojs - LGPL
15776 * <script type="text/javascript">
15780 * @class Roo.XComponent
15781 * A delayed Element creator...
15782 * Or a way to group chunks of interface together.
15783 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15784 * used in conjunction with XComponent.build() it will create an instance of each element,
15785 * then call addxtype() to build the User interface.
15787 * Mypart.xyx = new Roo.XComponent({
15789 parent : 'Mypart.xyz', // empty == document.element.!!
15793 disabled : function() {}
15795 tree : function() { // return an tree of xtype declared components
15799 xtype : 'NestedLayoutPanel',
15806 * It can be used to build a big heiracy, with parent etc.
15807 * or you can just use this to render a single compoent to a dom element
15808 * MYPART.render(Roo.Element | String(id) | dom_element )
15815 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15816 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15818 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15820 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15821 * - if mulitple topModules exist, the last one is defined as the top module.
15825 * When the top level or multiple modules are to embedded into a existing HTML page,
15826 * the parent element can container '#id' of the element where the module will be drawn.
15830 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15831 * it relies more on a include mechanism, where sub modules are included into an outer page.
15832 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15834 * Bootstrap Roo Included elements
15836 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15837 * hence confusing the component builder as it thinks there are multiple top level elements.
15841 * @extends Roo.util.Observable
15843 * @param cfg {Object} configuration of component
15846 Roo.XComponent = function(cfg) {
15847 Roo.apply(this, cfg);
15851 * Fires when this the componnt is built
15852 * @param {Roo.XComponent} c the component
15857 this.region = this.region || 'center'; // default..
15858 Roo.XComponent.register(this);
15859 this.modules = false;
15860 this.el = false; // where the layout goes..
15864 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15867 * The created element (with Roo.factory())
15868 * @type {Roo.Layout}
15874 * for BC - use el in new code
15875 * @type {Roo.Layout}
15881 * for BC - use el in new code
15882 * @type {Roo.Layout}
15887 * @cfg {Function|boolean} disabled
15888 * If this module is disabled by some rule, return true from the funtion
15893 * @cfg {String} parent
15894 * Name of parent element which it get xtype added to..
15899 * @cfg {String} order
15900 * Used to set the order in which elements are created (usefull for multiple tabs)
15905 * @cfg {String} name
15906 * String to display while loading.
15910 * @cfg {String} region
15911 * Region to render component to (defaults to center)
15916 * @cfg {Array} items
15917 * A single item array - the first element is the root of the tree..
15918 * It's done this way to stay compatible with the Xtype system...
15924 * The method that retuns the tree of parts that make up this compoennt
15931 * render element to dom or tree
15932 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15935 render : function(el)
15939 var hp = this.parent ? 1 : 0;
15940 Roo.debug && Roo.log(this);
15942 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15943 // if parent is a '#.....' string, then let's use that..
15944 var ename = this.parent.substr(1);
15945 this.parent = false;
15946 Roo.debug && Roo.log(ename);
15948 case 'bootstrap-body' :
15949 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15950 this.parent = { el : new Roo.bootstrap.Body() };
15951 Roo.debug && Roo.log("setting el to doc body");
15954 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15958 this.parent = { el : true};
15961 el = Roo.get(ename);
15966 if (!el && !this.parent) {
15967 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15971 Roo.debug && Roo.log("EL:");
15972 Roo.debug && Roo.log(el);
15973 Roo.debug && Roo.log("this.parent.el:");
15974 Roo.debug && Roo.log(this.parent.el);
15976 var tree = this._tree ? this._tree() : this.tree();
15978 // altertive root elements ??? - we need a better way to indicate these.
15979 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15980 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15982 if (!this.parent && is_alt) {
15983 //el = Roo.get(document.body);
15984 this.parent = { el : true };
15989 if (!this.parent) {
15991 Roo.debug && Roo.log("no parent - creating one");
15993 el = el ? Roo.get(el) : false;
15995 // it's a top level one..
15997 el : new Roo.BorderLayout(el || document.body, {
16003 tabPosition: 'top',
16004 //resizeTabs: true,
16005 alwaysShowTabs: el && hp? false : true,
16006 hideTabs: el || !hp ? true : false,
16013 if (!this.parent.el) {
16014 // probably an old style ctor, which has been disabled.
16018 // The 'tree' method is '_tree now'
16020 tree.region = tree.region || this.region;
16022 if (this.parent.el === true) {
16023 // bootstrap... - body..
16024 this.parent.el = Roo.factory(tree);
16027 this.el = this.parent.el.addxtype(tree);
16028 this.fireEvent('built', this);
16030 this.panel = this.el;
16031 this.layout = this.panel.layout;
16032 this.parentLayout = this.parent.layout || false;
16038 Roo.apply(Roo.XComponent, {
16040 * @property hideProgress
16041 * true to disable the building progress bar.. usefull on single page renders.
16044 hideProgress : false,
16046 * @property buildCompleted
16047 * True when the builder has completed building the interface.
16050 buildCompleted : false,
16053 * @property topModule
16054 * the upper most module - uses document.element as it's constructor.
16061 * @property modules
16062 * array of modules to be created by registration system.
16063 * @type {Array} of Roo.XComponent
16068 * @property elmodules
16069 * array of modules to be created by which use #ID
16070 * @type {Array} of Roo.XComponent
16076 * @property build_from_html
16077 * Build elements from html - used by bootstrap HTML stuff
16078 * - this is cleared after build is completed
16079 * @type {boolean} true (default false)
16082 build_from_html : false,
16085 * Register components to be built later.
16087 * This solves the following issues
16088 * - Building is not done on page load, but after an authentication process has occured.
16089 * - Interface elements are registered on page load
16090 * - Parent Interface elements may not be loaded before child, so this handles that..
16097 module : 'Pman.Tab.projectMgr',
16099 parent : 'Pman.layout',
16100 disabled : false, // or use a function..
16103 * * @param {Object} details about module
16105 register : function(obj) {
16107 Roo.XComponent.event.fireEvent('register', obj);
16108 switch(typeof(obj.disabled) ) {
16114 if ( obj.disabled() ) {
16120 if (obj.disabled) {
16126 this.modules.push(obj);
16130 * convert a string to an object..
16131 * eg. 'AAA.BBB' -> finds AAA.BBB
16135 toObject : function(str)
16137 if (!str || typeof(str) == 'object') {
16140 if (str.substring(0,1) == '#') {
16144 var ar = str.split('.');
16149 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16151 throw "Module not found : " + str;
16155 throw "Module not found : " + str;
16157 Roo.each(ar, function(e) {
16158 if (typeof(o[e]) == 'undefined') {
16159 throw "Module not found : " + str;
16170 * move modules into their correct place in the tree..
16173 preBuild : function ()
16176 Roo.each(this.modules , function (obj)
16178 Roo.XComponent.event.fireEvent('beforebuild', obj);
16180 var opar = obj.parent;
16182 obj.parent = this.toObject(opar);
16184 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16189 Roo.debug && Roo.log("GOT top level module");
16190 Roo.debug && Roo.log(obj);
16191 obj.modules = new Roo.util.MixedCollection(false,
16192 function(o) { return o.order + '' }
16194 this.topModule = obj;
16197 // parent is a string (usually a dom element name..)
16198 if (typeof(obj.parent) == 'string') {
16199 this.elmodules.push(obj);
16202 if (obj.parent.constructor != Roo.XComponent) {
16203 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16205 if (!obj.parent.modules) {
16206 obj.parent.modules = new Roo.util.MixedCollection(false,
16207 function(o) { return o.order + '' }
16210 if (obj.parent.disabled) {
16211 obj.disabled = true;
16213 obj.parent.modules.add(obj);
16218 * make a list of modules to build.
16219 * @return {Array} list of modules.
16222 buildOrder : function()
16225 var cmp = function(a,b) {
16226 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16228 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16229 throw "No top level modules to build";
16232 // make a flat list in order of modules to build.
16233 var mods = this.topModule ? [ this.topModule ] : [];
16236 // elmodules (is a list of DOM based modules )
16237 Roo.each(this.elmodules, function(e) {
16239 if (!this.topModule &&
16240 typeof(e.parent) == 'string' &&
16241 e.parent.substring(0,1) == '#' &&
16242 Roo.get(e.parent.substr(1))
16245 _this.topModule = e;
16251 // add modules to their parents..
16252 var addMod = function(m) {
16253 Roo.debug && Roo.log("build Order: add: " + m.name);
16256 if (m.modules && !m.disabled) {
16257 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16258 m.modules.keySort('ASC', cmp );
16259 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16261 m.modules.each(addMod);
16263 Roo.debug && Roo.log("build Order: no child modules");
16265 // not sure if this is used any more..
16267 m.finalize.name = m.name + " (clean up) ";
16268 mods.push(m.finalize);
16272 if (this.topModule && this.topModule.modules) {
16273 this.topModule.modules.keySort('ASC', cmp );
16274 this.topModule.modules.each(addMod);
16280 * Build the registered modules.
16281 * @param {Object} parent element.
16282 * @param {Function} optional method to call after module has been added.
16286 build : function(opts)
16289 if (typeof(opts) != 'undefined') {
16290 Roo.apply(this,opts);
16294 var mods = this.buildOrder();
16296 //this.allmods = mods;
16297 //Roo.debug && Roo.log(mods);
16299 if (!mods.length) { // should not happen
16300 throw "NO modules!!!";
16304 var msg = "Building Interface...";
16305 // flash it up as modal - so we store the mask!?
16306 if (!this.hideProgress && Roo.MessageBox) {
16307 Roo.MessageBox.show({ title: 'loading' });
16308 Roo.MessageBox.show({
16309 title: "Please wait...",
16318 var total = mods.length;
16321 var progressRun = function() {
16322 if (!mods.length) {
16323 Roo.debug && Roo.log('hide?');
16324 if (!this.hideProgress && Roo.MessageBox) {
16325 Roo.MessageBox.hide();
16327 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16329 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16335 var m = mods.shift();
16338 Roo.debug && Roo.log(m);
16339 // not sure if this is supported any more.. - modules that are are just function
16340 if (typeof(m) == 'function') {
16342 return progressRun.defer(10, _this);
16346 msg = "Building Interface " + (total - mods.length) +
16348 (m.name ? (' - ' + m.name) : '');
16349 Roo.debug && Roo.log(msg);
16350 if (!this.hideProgress && Roo.MessageBox) {
16351 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16355 // is the module disabled?
16356 var disabled = (typeof(m.disabled) == 'function') ?
16357 m.disabled.call(m.module.disabled) : m.disabled;
16361 return progressRun(); // we do not update the display!
16369 // it's 10 on top level, and 1 on others??? why...
16370 return progressRun.defer(10, _this);
16373 progressRun.defer(1, _this);
16387 * wrapper for event.on - aliased later..
16388 * Typically use to register a event handler for register:
16390 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16399 Roo.XComponent.event = new Roo.util.Observable({
16403 * Fires when an Component is registered,
16404 * set the disable property on the Component to stop registration.
16405 * @param {Roo.XComponent} c the component being registerd.
16410 * @event beforebuild
16411 * Fires before each Component is built
16412 * can be used to apply permissions.
16413 * @param {Roo.XComponent} c the component being registerd.
16416 'beforebuild' : true,
16418 * @event buildcomplete
16419 * Fires on the top level element when all elements have been built
16420 * @param {Roo.XComponent} the top level component.
16422 'buildcomplete' : true
16427 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16430 * Ext JS Library 1.1.1
16431 * Copyright(c) 2006-2007, Ext JS, LLC.
16433 * Originally Released Under LGPL - original licence link has changed is not relivant.
16436 * <script type="text/javascript">
16442 * These classes are derivatives of the similarly named classes in the YUI Library.
16443 * The original license:
16444 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16445 * Code licensed under the BSD License:
16446 * http://developer.yahoo.net/yui/license.txt
16451 var Event=Roo.EventManager;
16452 var Dom=Roo.lib.Dom;
16455 * @class Roo.dd.DragDrop
16456 * @extends Roo.util.Observable
16457 * Defines the interface and base operation of items that that can be
16458 * dragged or can be drop targets. It was designed to be extended, overriding
16459 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16460 * Up to three html elements can be associated with a DragDrop instance:
16462 * <li>linked element: the element that is passed into the constructor.
16463 * This is the element which defines the boundaries for interaction with
16464 * other DragDrop objects.</li>
16465 * <li>handle element(s): The drag operation only occurs if the element that
16466 * was clicked matches a handle element. By default this is the linked
16467 * element, but there are times that you will want only a portion of the
16468 * linked element to initiate the drag operation, and the setHandleElId()
16469 * method provides a way to define this.</li>
16470 * <li>drag element: this represents the element that would be moved along
16471 * with the cursor during a drag operation. By default, this is the linked
16472 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16473 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16476 * This class should not be instantiated until the onload event to ensure that
16477 * the associated elements are available.
16478 * The following would define a DragDrop obj that would interact with any
16479 * other DragDrop obj in the "group1" group:
16481 * dd = new Roo.dd.DragDrop("div1", "group1");
16483 * Since none of the event handlers have been implemented, nothing would
16484 * actually happen if you were to run the code above. Normally you would
16485 * override this class or one of the default implementations, but you can
16486 * also override the methods you want on an instance of the class...
16488 * dd.onDragDrop = function(e, id) {
16489 * alert("dd was dropped on " + id);
16493 * @param {String} id of the element that is linked to this instance
16494 * @param {String} sGroup the group of related DragDrop objects
16495 * @param {object} config an object containing configurable attributes
16496 * Valid properties for DragDrop:
16497 * padding, isTarget, maintainOffset, primaryButtonOnly
16499 Roo.dd.DragDrop = function(id, sGroup, config) {
16501 this.init(id, sGroup, config);
16506 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16509 * The id of the element associated with this object. This is what we
16510 * refer to as the "linked element" because the size and position of
16511 * this element is used to determine when the drag and drop objects have
16519 * Configuration attributes passed into the constructor
16526 * The id of the element that will be dragged. By default this is same
16527 * as the linked element , but could be changed to another element. Ex:
16529 * @property dragElId
16536 * the id of the element that initiates the drag operation. By default
16537 * this is the linked element, but could be changed to be a child of this
16538 * element. This lets us do things like only starting the drag when the
16539 * header element within the linked html element is clicked.
16540 * @property handleElId
16547 * An associative array of HTML tags that will be ignored if clicked.
16548 * @property invalidHandleTypes
16549 * @type {string: string}
16551 invalidHandleTypes: null,
16554 * An associative array of ids for elements that will be ignored if clicked
16555 * @property invalidHandleIds
16556 * @type {string: string}
16558 invalidHandleIds: null,
16561 * An indexted array of css class names for elements that will be ignored
16563 * @property invalidHandleClasses
16566 invalidHandleClasses: null,
16569 * The linked element's absolute X position at the time the drag was
16571 * @property startPageX
16578 * The linked element's absolute X position at the time the drag was
16580 * @property startPageY
16587 * The group defines a logical collection of DragDrop objects that are
16588 * related. Instances only get events when interacting with other
16589 * DragDrop object in the same group. This lets us define multiple
16590 * groups using a single DragDrop subclass if we want.
16592 * @type {string: string}
16597 * Individual drag/drop instances can be locked. This will prevent
16598 * onmousedown start drag.
16606 * Lock this instance
16609 lock: function() { this.locked = true; },
16612 * Unlock this instace
16615 unlock: function() { this.locked = false; },
16618 * By default, all insances can be a drop target. This can be disabled by
16619 * setting isTarget to false.
16626 * The padding configured for this drag and drop object for calculating
16627 * the drop zone intersection with this object.
16634 * Cached reference to the linked element
16635 * @property _domRef
16641 * Internal typeof flag
16642 * @property __ygDragDrop
16645 __ygDragDrop: true,
16648 * Set to true when horizontal contraints are applied
16649 * @property constrainX
16656 * Set to true when vertical contraints are applied
16657 * @property constrainY
16664 * The left constraint
16672 * The right constraint
16680 * The up constraint
16689 * The down constraint
16697 * Maintain offsets when we resetconstraints. Set to true when you want
16698 * the position of the element relative to its parent to stay the same
16699 * when the page changes
16701 * @property maintainOffset
16704 maintainOffset: false,
16707 * Array of pixel locations the element will snap to if we specified a
16708 * horizontal graduation/interval. This array is generated automatically
16709 * when you define a tick interval.
16716 * Array of pixel locations the element will snap to if we specified a
16717 * vertical graduation/interval. This array is generated automatically
16718 * when you define a tick interval.
16725 * By default the drag and drop instance will only respond to the primary
16726 * button click (left button for a right-handed mouse). Set to true to
16727 * allow drag and drop to start with any mouse click that is propogated
16729 * @property primaryButtonOnly
16732 primaryButtonOnly: true,
16735 * The availabe property is false until the linked dom element is accessible.
16736 * @property available
16742 * By default, drags can only be initiated if the mousedown occurs in the
16743 * region the linked element is. This is done in part to work around a
16744 * bug in some browsers that mis-report the mousedown if the previous
16745 * mouseup happened outside of the window. This property is set to true
16746 * if outer handles are defined.
16748 * @property hasOuterHandles
16752 hasOuterHandles: false,
16755 * Code that executes immediately before the startDrag event
16756 * @method b4StartDrag
16759 b4StartDrag: function(x, y) { },
16762 * Abstract method called after a drag/drop object is clicked
16763 * and the drag or mousedown time thresholds have beeen met.
16764 * @method startDrag
16765 * @param {int} X click location
16766 * @param {int} Y click location
16768 startDrag: function(x, y) { /* override this */ },
16771 * Code that executes immediately before the onDrag event
16775 b4Drag: function(e) { },
16778 * Abstract method called during the onMouseMove event while dragging an
16781 * @param {Event} e the mousemove event
16783 onDrag: function(e) { /* override this */ },
16786 * Abstract method called when this element fist begins hovering over
16787 * another DragDrop obj
16788 * @method onDragEnter
16789 * @param {Event} e the mousemove event
16790 * @param {String|DragDrop[]} id In POINT mode, the element
16791 * id this is hovering over. In INTERSECT mode, an array of one or more
16792 * dragdrop items being hovered over.
16794 onDragEnter: function(e, id) { /* override this */ },
16797 * Code that executes immediately before the onDragOver event
16798 * @method b4DragOver
16801 b4DragOver: function(e) { },
16804 * Abstract method called when this element is hovering over another
16806 * @method onDragOver
16807 * @param {Event} e the mousemove event
16808 * @param {String|DragDrop[]} id In POINT mode, the element
16809 * id this is hovering over. In INTERSECT mode, an array of dd items
16810 * being hovered over.
16812 onDragOver: function(e, id) { /* override this */ },
16815 * Code that executes immediately before the onDragOut event
16816 * @method b4DragOut
16819 b4DragOut: function(e) { },
16822 * Abstract method called when we are no longer hovering over an element
16823 * @method onDragOut
16824 * @param {Event} e the mousemove event
16825 * @param {String|DragDrop[]} id In POINT mode, the element
16826 * id this was hovering over. In INTERSECT mode, an array of dd items
16827 * that the mouse is no longer over.
16829 onDragOut: function(e, id) { /* override this */ },
16832 * Code that executes immediately before the onDragDrop event
16833 * @method b4DragDrop
16836 b4DragDrop: function(e) { },
16839 * Abstract method called when this item is dropped on another DragDrop
16841 * @method onDragDrop
16842 * @param {Event} e the mouseup event
16843 * @param {String|DragDrop[]} id In POINT mode, the element
16844 * id this was dropped on. In INTERSECT mode, an array of dd items this
16847 onDragDrop: function(e, id) { /* override this */ },
16850 * Abstract method called when this item is dropped on an area with no
16852 * @method onInvalidDrop
16853 * @param {Event} e the mouseup event
16855 onInvalidDrop: function(e) { /* override this */ },
16858 * Code that executes immediately before the endDrag event
16859 * @method b4EndDrag
16862 b4EndDrag: function(e) { },
16865 * Fired when we are done dragging the object
16867 * @param {Event} e the mouseup event
16869 endDrag: function(e) { /* override this */ },
16872 * Code executed immediately before the onMouseDown event
16873 * @method b4MouseDown
16874 * @param {Event} e the mousedown event
16877 b4MouseDown: function(e) { },
16880 * Event handler that fires when a drag/drop obj gets a mousedown
16881 * @method onMouseDown
16882 * @param {Event} e the mousedown event
16884 onMouseDown: function(e) { /* override this */ },
16887 * Event handler that fires when a drag/drop obj gets a mouseup
16888 * @method onMouseUp
16889 * @param {Event} e the mouseup event
16891 onMouseUp: function(e) { /* override this */ },
16894 * Override the onAvailable method to do what is needed after the initial
16895 * position was determined.
16896 * @method onAvailable
16898 onAvailable: function () {
16902 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16905 defaultPadding : {left:0, right:0, top:0, bottom:0},
16908 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16912 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16913 { dragElId: "existingProxyDiv" });
16914 dd.startDrag = function(){
16915 this.constrainTo("parent-id");
16918 * Or you can initalize it using the {@link Roo.Element} object:
16920 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16921 startDrag : function(){
16922 this.constrainTo("parent-id");
16926 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16927 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16928 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16929 * an object containing the sides to pad. For example: {right:10, bottom:10}
16930 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16932 constrainTo : function(constrainTo, pad, inContent){
16933 if(typeof pad == "number"){
16934 pad = {left: pad, right:pad, top:pad, bottom:pad};
16936 pad = pad || this.defaultPadding;
16937 var b = Roo.get(this.getEl()).getBox();
16938 var ce = Roo.get(constrainTo);
16939 var s = ce.getScroll();
16940 var c, cd = ce.dom;
16941 if(cd == document.body){
16942 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16945 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16949 var topSpace = b.y - c.y;
16950 var leftSpace = b.x - c.x;
16952 this.resetConstraints();
16953 this.setXConstraint(leftSpace - (pad.left||0), // left
16954 c.width - leftSpace - b.width - (pad.right||0) //right
16956 this.setYConstraint(topSpace - (pad.top||0), //top
16957 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16962 * Returns a reference to the linked element
16964 * @return {HTMLElement} the html element
16966 getEl: function() {
16967 if (!this._domRef) {
16968 this._domRef = Roo.getDom(this.id);
16971 return this._domRef;
16975 * Returns a reference to the actual element to drag. By default this is
16976 * the same as the html element, but it can be assigned to another
16977 * element. An example of this can be found in Roo.dd.DDProxy
16978 * @method getDragEl
16979 * @return {HTMLElement} the html element
16981 getDragEl: function() {
16982 return Roo.getDom(this.dragElId);
16986 * Sets up the DragDrop object. Must be called in the constructor of any
16987 * Roo.dd.DragDrop subclass
16989 * @param id the id of the linked element
16990 * @param {String} sGroup the group of related items
16991 * @param {object} config configuration attributes
16993 init: function(id, sGroup, config) {
16994 this.initTarget(id, sGroup, config);
16995 if (!Roo.isTouch) {
16996 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16998 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16999 // Event.on(this.id, "selectstart", Event.preventDefault);
17003 * Initializes Targeting functionality only... the object does not
17004 * get a mousedown handler.
17005 * @method initTarget
17006 * @param id the id of the linked element
17007 * @param {String} sGroup the group of related items
17008 * @param {object} config configuration attributes
17010 initTarget: function(id, sGroup, config) {
17012 // configuration attributes
17013 this.config = config || {};
17015 // create a local reference to the drag and drop manager
17016 this.DDM = Roo.dd.DDM;
17017 // initialize the groups array
17020 // assume that we have an element reference instead of an id if the
17021 // parameter is not a string
17022 if (typeof id !== "string") {
17029 // add to an interaction group
17030 this.addToGroup((sGroup) ? sGroup : "default");
17032 // We don't want to register this as the handle with the manager
17033 // so we just set the id rather than calling the setter.
17034 this.handleElId = id;
17036 // the linked element is the element that gets dragged by default
17037 this.setDragElId(id);
17039 // by default, clicked anchors will not start drag operations.
17040 this.invalidHandleTypes = { A: "A" };
17041 this.invalidHandleIds = {};
17042 this.invalidHandleClasses = [];
17044 this.applyConfig();
17046 this.handleOnAvailable();
17050 * Applies the configuration parameters that were passed into the constructor.
17051 * This is supposed to happen at each level through the inheritance chain. So
17052 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17053 * DragDrop in order to get all of the parameters that are available in
17055 * @method applyConfig
17057 applyConfig: function() {
17059 // configurable properties:
17060 // padding, isTarget, maintainOffset, primaryButtonOnly
17061 this.padding = this.config.padding || [0, 0, 0, 0];
17062 this.isTarget = (this.config.isTarget !== false);
17063 this.maintainOffset = (this.config.maintainOffset);
17064 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17069 * Executed when the linked element is available
17070 * @method handleOnAvailable
17073 handleOnAvailable: function() {
17074 this.available = true;
17075 this.resetConstraints();
17076 this.onAvailable();
17080 * Configures the padding for the target zone in px. Effectively expands
17081 * (or reduces) the virtual object size for targeting calculations.
17082 * Supports css-style shorthand; if only one parameter is passed, all sides
17083 * will have that padding, and if only two are passed, the top and bottom
17084 * will have the first param, the left and right the second.
17085 * @method setPadding
17086 * @param {int} iTop Top pad
17087 * @param {int} iRight Right pad
17088 * @param {int} iBot Bot pad
17089 * @param {int} iLeft Left pad
17091 setPadding: function(iTop, iRight, iBot, iLeft) {
17092 // this.padding = [iLeft, iRight, iTop, iBot];
17093 if (!iRight && 0 !== iRight) {
17094 this.padding = [iTop, iTop, iTop, iTop];
17095 } else if (!iBot && 0 !== iBot) {
17096 this.padding = [iTop, iRight, iTop, iRight];
17098 this.padding = [iTop, iRight, iBot, iLeft];
17103 * Stores the initial placement of the linked element.
17104 * @method setInitialPosition
17105 * @param {int} diffX the X offset, default 0
17106 * @param {int} diffY the Y offset, default 0
17108 setInitPosition: function(diffX, diffY) {
17109 var el = this.getEl();
17111 if (!this.DDM.verifyEl(el)) {
17115 var dx = diffX || 0;
17116 var dy = diffY || 0;
17118 var p = Dom.getXY( el );
17120 this.initPageX = p[0] - dx;
17121 this.initPageY = p[1] - dy;
17123 this.lastPageX = p[0];
17124 this.lastPageY = p[1];
17127 this.setStartPosition(p);
17131 * Sets the start position of the element. This is set when the obj
17132 * is initialized, the reset when a drag is started.
17133 * @method setStartPosition
17134 * @param pos current position (from previous lookup)
17137 setStartPosition: function(pos) {
17138 var p = pos || Dom.getXY( this.getEl() );
17139 this.deltaSetXY = null;
17141 this.startPageX = p[0];
17142 this.startPageY = p[1];
17146 * Add this instance to a group of related drag/drop objects. All
17147 * instances belong to at least one group, and can belong to as many
17148 * groups as needed.
17149 * @method addToGroup
17150 * @param sGroup {string} the name of the group
17152 addToGroup: function(sGroup) {
17153 this.groups[sGroup] = true;
17154 this.DDM.regDragDrop(this, sGroup);
17158 * Remove's this instance from the supplied interaction group
17159 * @method removeFromGroup
17160 * @param {string} sGroup The group to drop
17162 removeFromGroup: function(sGroup) {
17163 if (this.groups[sGroup]) {
17164 delete this.groups[sGroup];
17167 this.DDM.removeDDFromGroup(this, sGroup);
17171 * Allows you to specify that an element other than the linked element
17172 * will be moved with the cursor during a drag
17173 * @method setDragElId
17174 * @param id {string} the id of the element that will be used to initiate the drag
17176 setDragElId: function(id) {
17177 this.dragElId = id;
17181 * Allows you to specify a child of the linked element that should be
17182 * used to initiate the drag operation. An example of this would be if
17183 * you have a content div with text and links. Clicking anywhere in the
17184 * content area would normally start the drag operation. Use this method
17185 * to specify that an element inside of the content div is the element
17186 * that starts the drag operation.
17187 * @method setHandleElId
17188 * @param id {string} the id of the element that will be used to
17189 * initiate the drag.
17191 setHandleElId: function(id) {
17192 if (typeof id !== "string") {
17195 this.handleElId = id;
17196 this.DDM.regHandle(this.id, id);
17200 * Allows you to set an element outside of the linked element as a drag
17202 * @method setOuterHandleElId
17203 * @param id the id of the element that will be used to initiate the drag
17205 setOuterHandleElId: function(id) {
17206 if (typeof id !== "string") {
17209 Event.on(id, "mousedown",
17210 this.handleMouseDown, this);
17211 this.setHandleElId(id);
17213 this.hasOuterHandles = true;
17217 * Remove all drag and drop hooks for this element
17220 unreg: function() {
17221 Event.un(this.id, "mousedown",
17222 this.handleMouseDown);
17223 Event.un(this.id, "touchstart",
17224 this.handleMouseDown);
17225 this._domRef = null;
17226 this.DDM._remove(this);
17229 destroy : function(){
17234 * Returns true if this instance is locked, or the drag drop mgr is locked
17235 * (meaning that all drag/drop is disabled on the page.)
17237 * @return {boolean} true if this obj or all drag/drop is locked, else
17240 isLocked: function() {
17241 return (this.DDM.isLocked() || this.locked);
17245 * Fired when this object is clicked
17246 * @method handleMouseDown
17248 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17251 handleMouseDown: function(e, oDD){
17253 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17254 //Roo.log('not touch/ button !=0');
17257 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17258 return; // double touch..
17262 if (this.isLocked()) {
17263 //Roo.log('locked');
17267 this.DDM.refreshCache(this.groups);
17268 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17269 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17270 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17271 //Roo.log('no outer handes or not over target');
17274 // Roo.log('check validator');
17275 if (this.clickValidator(e)) {
17276 // Roo.log('validate success');
17277 // set the initial element position
17278 this.setStartPosition();
17281 this.b4MouseDown(e);
17282 this.onMouseDown(e);
17284 this.DDM.handleMouseDown(e, this);
17286 this.DDM.stopEvent(e);
17294 clickValidator: function(e) {
17295 var target = e.getTarget();
17296 return ( this.isValidHandleChild(target) &&
17297 (this.id == this.handleElId ||
17298 this.DDM.handleWasClicked(target, this.id)) );
17302 * Allows you to specify a tag name that should not start a drag operation
17303 * when clicked. This is designed to facilitate embedding links within a
17304 * drag handle that do something other than start the drag.
17305 * @method addInvalidHandleType
17306 * @param {string} tagName the type of element to exclude
17308 addInvalidHandleType: function(tagName) {
17309 var type = tagName.toUpperCase();
17310 this.invalidHandleTypes[type] = type;
17314 * Lets you to specify an element id for a child of a drag handle
17315 * that should not initiate a drag
17316 * @method addInvalidHandleId
17317 * @param {string} id the element id of the element you wish to ignore
17319 addInvalidHandleId: function(id) {
17320 if (typeof id !== "string") {
17323 this.invalidHandleIds[id] = id;
17327 * Lets you specify a css class of elements that will not initiate a drag
17328 * @method addInvalidHandleClass
17329 * @param {string} cssClass the class of the elements you wish to ignore
17331 addInvalidHandleClass: function(cssClass) {
17332 this.invalidHandleClasses.push(cssClass);
17336 * Unsets an excluded tag name set by addInvalidHandleType
17337 * @method removeInvalidHandleType
17338 * @param {string} tagName the type of element to unexclude
17340 removeInvalidHandleType: function(tagName) {
17341 var type = tagName.toUpperCase();
17342 // this.invalidHandleTypes[type] = null;
17343 delete this.invalidHandleTypes[type];
17347 * Unsets an invalid handle id
17348 * @method removeInvalidHandleId
17349 * @param {string} id the id of the element to re-enable
17351 removeInvalidHandleId: function(id) {
17352 if (typeof id !== "string") {
17355 delete this.invalidHandleIds[id];
17359 * Unsets an invalid css class
17360 * @method removeInvalidHandleClass
17361 * @param {string} cssClass the class of the element(s) you wish to
17364 removeInvalidHandleClass: function(cssClass) {
17365 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17366 if (this.invalidHandleClasses[i] == cssClass) {
17367 delete this.invalidHandleClasses[i];
17373 * Checks the tag exclusion list to see if this click should be ignored
17374 * @method isValidHandleChild
17375 * @param {HTMLElement} node the HTMLElement to evaluate
17376 * @return {boolean} true if this is a valid tag type, false if not
17378 isValidHandleChild: function(node) {
17381 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17384 nodeName = node.nodeName.toUpperCase();
17386 nodeName = node.nodeName;
17388 valid = valid && !this.invalidHandleTypes[nodeName];
17389 valid = valid && !this.invalidHandleIds[node.id];
17391 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17392 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17401 * Create the array of horizontal tick marks if an interval was specified
17402 * in setXConstraint().
17403 * @method setXTicks
17406 setXTicks: function(iStartX, iTickSize) {
17408 this.xTickSize = iTickSize;
17412 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17414 this.xTicks[this.xTicks.length] = i;
17419 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17421 this.xTicks[this.xTicks.length] = i;
17426 this.xTicks.sort(this.DDM.numericSort) ;
17430 * Create the array of vertical tick marks if an interval was specified in
17431 * setYConstraint().
17432 * @method setYTicks
17435 setYTicks: function(iStartY, iTickSize) {
17437 this.yTickSize = iTickSize;
17441 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17443 this.yTicks[this.yTicks.length] = i;
17448 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17450 this.yTicks[this.yTicks.length] = i;
17455 this.yTicks.sort(this.DDM.numericSort) ;
17459 * By default, the element can be dragged any place on the screen. Use
17460 * this method to limit the horizontal travel of the element. Pass in
17461 * 0,0 for the parameters if you want to lock the drag to the y axis.
17462 * @method setXConstraint
17463 * @param {int} iLeft the number of pixels the element can move to the left
17464 * @param {int} iRight the number of pixels the element can move to the
17466 * @param {int} iTickSize optional parameter for specifying that the
17468 * should move iTickSize pixels at a time.
17470 setXConstraint: function(iLeft, iRight, iTickSize) {
17471 this.leftConstraint = iLeft;
17472 this.rightConstraint = iRight;
17474 this.minX = this.initPageX - iLeft;
17475 this.maxX = this.initPageX + iRight;
17476 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17478 this.constrainX = true;
17482 * Clears any constraints applied to this instance. Also clears ticks
17483 * since they can't exist independent of a constraint at this time.
17484 * @method clearConstraints
17486 clearConstraints: function() {
17487 this.constrainX = false;
17488 this.constrainY = false;
17493 * Clears any tick interval defined for this instance
17494 * @method clearTicks
17496 clearTicks: function() {
17497 this.xTicks = null;
17498 this.yTicks = null;
17499 this.xTickSize = 0;
17500 this.yTickSize = 0;
17504 * By default, the element can be dragged any place on the screen. Set
17505 * this to limit the vertical travel of the element. Pass in 0,0 for the
17506 * parameters if you want to lock the drag to the x axis.
17507 * @method setYConstraint
17508 * @param {int} iUp the number of pixels the element can move up
17509 * @param {int} iDown the number of pixels the element can move down
17510 * @param {int} iTickSize optional parameter for specifying that the
17511 * element should move iTickSize pixels at a time.
17513 setYConstraint: function(iUp, iDown, iTickSize) {
17514 this.topConstraint = iUp;
17515 this.bottomConstraint = iDown;
17517 this.minY = this.initPageY - iUp;
17518 this.maxY = this.initPageY + iDown;
17519 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17521 this.constrainY = true;
17526 * resetConstraints must be called if you manually reposition a dd element.
17527 * @method resetConstraints
17528 * @param {boolean} maintainOffset
17530 resetConstraints: function() {
17533 // Maintain offsets if necessary
17534 if (this.initPageX || this.initPageX === 0) {
17535 // figure out how much this thing has moved
17536 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17537 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17539 this.setInitPosition(dx, dy);
17541 // This is the first time we have detected the element's position
17543 this.setInitPosition();
17546 if (this.constrainX) {
17547 this.setXConstraint( this.leftConstraint,
17548 this.rightConstraint,
17552 if (this.constrainY) {
17553 this.setYConstraint( this.topConstraint,
17554 this.bottomConstraint,
17560 * Normally the drag element is moved pixel by pixel, but we can specify
17561 * that it move a number of pixels at a time. This method resolves the
17562 * location when we have it set up like this.
17564 * @param {int} val where we want to place the object
17565 * @param {int[]} tickArray sorted array of valid points
17566 * @return {int} the closest tick
17569 getTick: function(val, tickArray) {
17572 // If tick interval is not defined, it is effectively 1 pixel,
17573 // so we return the value passed to us.
17575 } else if (tickArray[0] >= val) {
17576 // The value is lower than the first tick, so we return the first
17578 return tickArray[0];
17580 for (var i=0, len=tickArray.length; i<len; ++i) {
17582 if (tickArray[next] && tickArray[next] >= val) {
17583 var diff1 = val - tickArray[i];
17584 var diff2 = tickArray[next] - val;
17585 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17589 // The value is larger than the last tick, so we return the last
17591 return tickArray[tickArray.length - 1];
17598 * @return {string} string representation of the dd obj
17600 toString: function() {
17601 return ("DragDrop " + this.id);
17609 * Ext JS Library 1.1.1
17610 * Copyright(c) 2006-2007, Ext JS, LLC.
17612 * Originally Released Under LGPL - original licence link has changed is not relivant.
17615 * <script type="text/javascript">
17620 * The drag and drop utility provides a framework for building drag and drop
17621 * applications. In addition to enabling drag and drop for specific elements,
17622 * the drag and drop elements are tracked by the manager class, and the
17623 * interactions between the various elements are tracked during the drag and
17624 * the implementing code is notified about these important moments.
17627 // Only load the library once. Rewriting the manager class would orphan
17628 // existing drag and drop instances.
17629 if (!Roo.dd.DragDropMgr) {
17632 * @class Roo.dd.DragDropMgr
17633 * DragDropMgr is a singleton that tracks the element interaction for
17634 * all DragDrop items in the window. Generally, you will not call
17635 * this class directly, but it does have helper methods that could
17636 * be useful in your DragDrop implementations.
17639 Roo.dd.DragDropMgr = function() {
17641 var Event = Roo.EventManager;
17646 * Two dimensional Array of registered DragDrop objects. The first
17647 * dimension is the DragDrop item group, the second the DragDrop
17650 * @type {string: string}
17657 * Array of element ids defined as drag handles. Used to determine
17658 * if the element that generated the mousedown event is actually the
17659 * handle and not the html element itself.
17660 * @property handleIds
17661 * @type {string: string}
17668 * the DragDrop object that is currently being dragged
17669 * @property dragCurrent
17677 * the DragDrop object(s) that are being hovered over
17678 * @property dragOvers
17686 * the X distance between the cursor and the object being dragged
17695 * the Y distance between the cursor and the object being dragged
17704 * Flag to determine if we should prevent the default behavior of the
17705 * events we define. By default this is true, but this can be set to
17706 * false if you need the default behavior (not recommended)
17707 * @property preventDefault
17711 preventDefault: true,
17714 * Flag to determine if we should stop the propagation of the events
17715 * we generate. This is true by default but you may want to set it to
17716 * false if the html element contains other features that require the
17718 * @property stopPropagation
17722 stopPropagation: true,
17725 * Internal flag that is set to true when drag and drop has been
17727 * @property initialized
17734 * All drag and drop can be disabled.
17742 * Called the first time an element is registered.
17748 this.initialized = true;
17752 * In point mode, drag and drop interaction is defined by the
17753 * location of the cursor during the drag/drop
17761 * In intersect mode, drag and drop interactio nis defined by the
17762 * overlap of two or more drag and drop objects.
17763 * @property INTERSECT
17770 * The current drag and drop mode. Default: POINT
17778 * Runs method on all drag and drop objects
17779 * @method _execOnAll
17783 _execOnAll: function(sMethod, args) {
17784 for (var i in this.ids) {
17785 for (var j in this.ids[i]) {
17786 var oDD = this.ids[i][j];
17787 if (! this.isTypeOfDD(oDD)) {
17790 oDD[sMethod].apply(oDD, args);
17796 * Drag and drop initialization. Sets up the global event handlers
17801 _onLoad: function() {
17805 if (!Roo.isTouch) {
17806 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17807 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17809 Event.on(document, "touchend", this.handleMouseUp, this, true);
17810 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17812 Event.on(window, "unload", this._onUnload, this, true);
17813 Event.on(window, "resize", this._onResize, this, true);
17814 // Event.on(window, "mouseout", this._test);
17819 * Reset constraints on all drag and drop objs
17820 * @method _onResize
17824 _onResize: function(e) {
17825 this._execOnAll("resetConstraints", []);
17829 * Lock all drag and drop functionality
17833 lock: function() { this.locked = true; },
17836 * Unlock all drag and drop functionality
17840 unlock: function() { this.locked = false; },
17843 * Is drag and drop locked?
17845 * @return {boolean} True if drag and drop is locked, false otherwise.
17848 isLocked: function() { return this.locked; },
17851 * Location cache that is set for all drag drop objects when a drag is
17852 * initiated, cleared when the drag is finished.
17853 * @property locationCache
17860 * Set useCache to false if you want to force object the lookup of each
17861 * drag and drop linked element constantly during a drag.
17862 * @property useCache
17869 * The number of pixels that the mouse needs to move after the
17870 * mousedown before the drag is initiated. Default=3;
17871 * @property clickPixelThresh
17875 clickPixelThresh: 3,
17878 * The number of milliseconds after the mousedown event to initiate the
17879 * drag if we don't get a mouseup event. Default=1000
17880 * @property clickTimeThresh
17884 clickTimeThresh: 350,
17887 * Flag that indicates that either the drag pixel threshold or the
17888 * mousdown time threshold has been met
17889 * @property dragThreshMet
17894 dragThreshMet: false,
17897 * Timeout used for the click time threshold
17898 * @property clickTimeout
17903 clickTimeout: null,
17906 * The X position of the mousedown event stored for later use when a
17907 * drag threshold is met.
17916 * The Y position of the mousedown event stored for later use when a
17917 * drag threshold is met.
17926 * Each DragDrop instance must be registered with the DragDropMgr.
17927 * This is executed in DragDrop.init()
17928 * @method regDragDrop
17929 * @param {DragDrop} oDD the DragDrop object to register
17930 * @param {String} sGroup the name of the group this element belongs to
17933 regDragDrop: function(oDD, sGroup) {
17934 if (!this.initialized) { this.init(); }
17936 if (!this.ids[sGroup]) {
17937 this.ids[sGroup] = {};
17939 this.ids[sGroup][oDD.id] = oDD;
17943 * Removes the supplied dd instance from the supplied group. Executed
17944 * by DragDrop.removeFromGroup, so don't call this function directly.
17945 * @method removeDDFromGroup
17949 removeDDFromGroup: function(oDD, sGroup) {
17950 if (!this.ids[sGroup]) {
17951 this.ids[sGroup] = {};
17954 var obj = this.ids[sGroup];
17955 if (obj && obj[oDD.id]) {
17956 delete obj[oDD.id];
17961 * Unregisters a drag and drop item. This is executed in
17962 * DragDrop.unreg, use that method instead of calling this directly.
17967 _remove: function(oDD) {
17968 for (var g in oDD.groups) {
17969 if (g && this.ids[g][oDD.id]) {
17970 delete this.ids[g][oDD.id];
17973 delete this.handleIds[oDD.id];
17977 * Each DragDrop handle element must be registered. This is done
17978 * automatically when executing DragDrop.setHandleElId()
17979 * @method regHandle
17980 * @param {String} sDDId the DragDrop id this element is a handle for
17981 * @param {String} sHandleId the id of the element that is the drag
17985 regHandle: function(sDDId, sHandleId) {
17986 if (!this.handleIds[sDDId]) {
17987 this.handleIds[sDDId] = {};
17989 this.handleIds[sDDId][sHandleId] = sHandleId;
17993 * Utility function to determine if a given element has been
17994 * registered as a drag drop item.
17995 * @method isDragDrop
17996 * @param {String} id the element id to check
17997 * @return {boolean} true if this element is a DragDrop item,
18001 isDragDrop: function(id) {
18002 return ( this.getDDById(id) ) ? true : false;
18006 * Returns the drag and drop instances that are in all groups the
18007 * passed in instance belongs to.
18008 * @method getRelated
18009 * @param {DragDrop} p_oDD the obj to get related data for
18010 * @param {boolean} bTargetsOnly if true, only return targetable objs
18011 * @return {DragDrop[]} the related instances
18014 getRelated: function(p_oDD, bTargetsOnly) {
18016 for (var i in p_oDD.groups) {
18017 for (j in this.ids[i]) {
18018 var dd = this.ids[i][j];
18019 if (! this.isTypeOfDD(dd)) {
18022 if (!bTargetsOnly || dd.isTarget) {
18023 oDDs[oDDs.length] = dd;
18032 * Returns true if the specified dd target is a legal target for
18033 * the specifice drag obj
18034 * @method isLegalTarget
18035 * @param {DragDrop} the drag obj
18036 * @param {DragDrop} the target
18037 * @return {boolean} true if the target is a legal target for the
18041 isLegalTarget: function (oDD, oTargetDD) {
18042 var targets = this.getRelated(oDD, true);
18043 for (var i=0, len=targets.length;i<len;++i) {
18044 if (targets[i].id == oTargetDD.id) {
18053 * My goal is to be able to transparently determine if an object is
18054 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18055 * returns "object", oDD.constructor.toString() always returns
18056 * "DragDrop" and not the name of the subclass. So for now it just
18057 * evaluates a well-known variable in DragDrop.
18058 * @method isTypeOfDD
18059 * @param {Object} the object to evaluate
18060 * @return {boolean} true if typeof oDD = DragDrop
18063 isTypeOfDD: function (oDD) {
18064 return (oDD && oDD.__ygDragDrop);
18068 * Utility function to determine if a given element has been
18069 * registered as a drag drop handle for the given Drag Drop object.
18071 * @param {String} id the element id to check
18072 * @return {boolean} true if this element is a DragDrop handle, false
18076 isHandle: function(sDDId, sHandleId) {
18077 return ( this.handleIds[sDDId] &&
18078 this.handleIds[sDDId][sHandleId] );
18082 * Returns the DragDrop instance for a given id
18083 * @method getDDById
18084 * @param {String} id the id of the DragDrop object
18085 * @return {DragDrop} the drag drop object, null if it is not found
18088 getDDById: function(id) {
18089 for (var i in this.ids) {
18090 if (this.ids[i][id]) {
18091 return this.ids[i][id];
18098 * Fired after a registered DragDrop object gets the mousedown event.
18099 * Sets up the events required to track the object being dragged
18100 * @method handleMouseDown
18101 * @param {Event} e the event
18102 * @param oDD the DragDrop object being dragged
18106 handleMouseDown: function(e, oDD) {
18108 Roo.QuickTips.disable();
18110 this.currentTarget = e.getTarget();
18112 this.dragCurrent = oDD;
18114 var el = oDD.getEl();
18116 // track start position
18117 this.startX = e.getPageX();
18118 this.startY = e.getPageY();
18120 this.deltaX = this.startX - el.offsetLeft;
18121 this.deltaY = this.startY - el.offsetTop;
18123 this.dragThreshMet = false;
18125 this.clickTimeout = setTimeout(
18127 var DDM = Roo.dd.DDM;
18128 DDM.startDrag(DDM.startX, DDM.startY);
18130 this.clickTimeThresh );
18134 * Fired when either the drag pixel threshol or the mousedown hold
18135 * time threshold has been met.
18136 * @method startDrag
18137 * @param x {int} the X position of the original mousedown
18138 * @param y {int} the Y position of the original mousedown
18141 startDrag: function(x, y) {
18142 clearTimeout(this.clickTimeout);
18143 if (this.dragCurrent) {
18144 this.dragCurrent.b4StartDrag(x, y);
18145 this.dragCurrent.startDrag(x, y);
18147 this.dragThreshMet = true;
18151 * Internal function to handle the mouseup event. Will be invoked
18152 * from the context of the document.
18153 * @method handleMouseUp
18154 * @param {Event} e the event
18158 handleMouseUp: function(e) {
18161 Roo.QuickTips.enable();
18163 if (! this.dragCurrent) {
18167 clearTimeout(this.clickTimeout);
18169 if (this.dragThreshMet) {
18170 this.fireEvents(e, true);
18180 * Utility to stop event propagation and event default, if these
18181 * features are turned on.
18182 * @method stopEvent
18183 * @param {Event} e the event as returned by this.getEvent()
18186 stopEvent: function(e){
18187 if(this.stopPropagation) {
18188 e.stopPropagation();
18191 if (this.preventDefault) {
18192 e.preventDefault();
18197 * Internal function to clean up event handlers after the drag
18198 * operation is complete
18200 * @param {Event} e the event
18204 stopDrag: function(e) {
18205 // Fire the drag end event for the item that was dragged
18206 if (this.dragCurrent) {
18207 if (this.dragThreshMet) {
18208 this.dragCurrent.b4EndDrag(e);
18209 this.dragCurrent.endDrag(e);
18212 this.dragCurrent.onMouseUp(e);
18215 this.dragCurrent = null;
18216 this.dragOvers = {};
18220 * Internal function to handle the mousemove event. Will be invoked
18221 * from the context of the html element.
18223 * @TODO figure out what we can do about mouse events lost when the
18224 * user drags objects beyond the window boundary. Currently we can
18225 * detect this in internet explorer by verifying that the mouse is
18226 * down during the mousemove event. Firefox doesn't give us the
18227 * button state on the mousemove event.
18228 * @method handleMouseMove
18229 * @param {Event} e the event
18233 handleMouseMove: function(e) {
18234 if (! this.dragCurrent) {
18238 // var button = e.which || e.button;
18240 // check for IE mouseup outside of page boundary
18241 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18243 return this.handleMouseUp(e);
18246 if (!this.dragThreshMet) {
18247 var diffX = Math.abs(this.startX - e.getPageX());
18248 var diffY = Math.abs(this.startY - e.getPageY());
18249 if (diffX > this.clickPixelThresh ||
18250 diffY > this.clickPixelThresh) {
18251 this.startDrag(this.startX, this.startY);
18255 if (this.dragThreshMet) {
18256 this.dragCurrent.b4Drag(e);
18257 this.dragCurrent.onDrag(e);
18258 if(!this.dragCurrent.moveOnly){
18259 this.fireEvents(e, false);
18269 * Iterates over all of the DragDrop elements to find ones we are
18270 * hovering over or dropping on
18271 * @method fireEvents
18272 * @param {Event} e the event
18273 * @param {boolean} isDrop is this a drop op or a mouseover op?
18277 fireEvents: function(e, isDrop) {
18278 var dc = this.dragCurrent;
18280 // If the user did the mouse up outside of the window, we could
18281 // get here even though we have ended the drag.
18282 if (!dc || dc.isLocked()) {
18286 var pt = e.getPoint();
18288 // cache the previous dragOver array
18294 var enterEvts = [];
18296 // Check to see if the object(s) we were hovering over is no longer
18297 // being hovered over so we can fire the onDragOut event
18298 for (var i in this.dragOvers) {
18300 var ddo = this.dragOvers[i];
18302 if (! this.isTypeOfDD(ddo)) {
18306 if (! this.isOverTarget(pt, ddo, this.mode)) {
18307 outEvts.push( ddo );
18310 oldOvers[i] = true;
18311 delete this.dragOvers[i];
18314 for (var sGroup in dc.groups) {
18316 if ("string" != typeof sGroup) {
18320 for (i in this.ids[sGroup]) {
18321 var oDD = this.ids[sGroup][i];
18322 if (! this.isTypeOfDD(oDD)) {
18326 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18327 if (this.isOverTarget(pt, oDD, this.mode)) {
18328 // look for drop interactions
18330 dropEvts.push( oDD );
18331 // look for drag enter and drag over interactions
18334 // initial drag over: dragEnter fires
18335 if (!oldOvers[oDD.id]) {
18336 enterEvts.push( oDD );
18337 // subsequent drag overs: dragOver fires
18339 overEvts.push( oDD );
18342 this.dragOvers[oDD.id] = oDD;
18350 if (outEvts.length) {
18351 dc.b4DragOut(e, outEvts);
18352 dc.onDragOut(e, outEvts);
18355 if (enterEvts.length) {
18356 dc.onDragEnter(e, enterEvts);
18359 if (overEvts.length) {
18360 dc.b4DragOver(e, overEvts);
18361 dc.onDragOver(e, overEvts);
18364 if (dropEvts.length) {
18365 dc.b4DragDrop(e, dropEvts);
18366 dc.onDragDrop(e, dropEvts);
18370 // fire dragout events
18372 for (i=0, len=outEvts.length; i<len; ++i) {
18373 dc.b4DragOut(e, outEvts[i].id);
18374 dc.onDragOut(e, outEvts[i].id);
18377 // fire enter events
18378 for (i=0,len=enterEvts.length; i<len; ++i) {
18379 // dc.b4DragEnter(e, oDD.id);
18380 dc.onDragEnter(e, enterEvts[i].id);
18383 // fire over events
18384 for (i=0,len=overEvts.length; i<len; ++i) {
18385 dc.b4DragOver(e, overEvts[i].id);
18386 dc.onDragOver(e, overEvts[i].id);
18389 // fire drop events
18390 for (i=0, len=dropEvts.length; i<len; ++i) {
18391 dc.b4DragDrop(e, dropEvts[i].id);
18392 dc.onDragDrop(e, dropEvts[i].id);
18397 // notify about a drop that did not find a target
18398 if (isDrop && !dropEvts.length) {
18399 dc.onInvalidDrop(e);
18405 * Helper function for getting the best match from the list of drag
18406 * and drop objects returned by the drag and drop events when we are
18407 * in INTERSECT mode. It returns either the first object that the
18408 * cursor is over, or the object that has the greatest overlap with
18409 * the dragged element.
18410 * @method getBestMatch
18411 * @param {DragDrop[]} dds The array of drag and drop objects
18413 * @return {DragDrop} The best single match
18416 getBestMatch: function(dds) {
18418 // Return null if the input is not what we expect
18419 //if (!dds || !dds.length || dds.length == 0) {
18421 // If there is only one item, it wins
18422 //} else if (dds.length == 1) {
18424 var len = dds.length;
18429 // Loop through the targeted items
18430 for (var i=0; i<len; ++i) {
18432 // If the cursor is over the object, it wins. If the
18433 // cursor is over multiple matches, the first one we come
18435 if (dd.cursorIsOver) {
18438 // Otherwise the object with the most overlap wins
18441 winner.overlap.getArea() < dd.overlap.getArea()) {
18452 * Refreshes the cache of the top-left and bottom-right points of the
18453 * drag and drop objects in the specified group(s). This is in the
18454 * format that is stored in the drag and drop instance, so typical
18457 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18461 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18463 * @TODO this really should be an indexed array. Alternatively this
18464 * method could accept both.
18465 * @method refreshCache
18466 * @param {Object} groups an associative array of groups to refresh
18469 refreshCache: function(groups) {
18470 for (var sGroup in groups) {
18471 if ("string" != typeof sGroup) {
18474 for (var i in this.ids[sGroup]) {
18475 var oDD = this.ids[sGroup][i];
18477 if (this.isTypeOfDD(oDD)) {
18478 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18479 var loc = this.getLocation(oDD);
18481 this.locationCache[oDD.id] = loc;
18483 delete this.locationCache[oDD.id];
18484 // this will unregister the drag and drop object if
18485 // the element is not in a usable state
18494 * This checks to make sure an element exists and is in the DOM. The
18495 * main purpose is to handle cases where innerHTML is used to remove
18496 * drag and drop objects from the DOM. IE provides an 'unspecified
18497 * error' when trying to access the offsetParent of such an element
18499 * @param {HTMLElement} el the element to check
18500 * @return {boolean} true if the element looks usable
18503 verifyEl: function(el) {
18508 parent = el.offsetParent;
18511 parent = el.offsetParent;
18522 * Returns a Region object containing the drag and drop element's position
18523 * and size, including the padding configured for it
18524 * @method getLocation
18525 * @param {DragDrop} oDD the drag and drop object to get the
18527 * @return {Roo.lib.Region} a Region object representing the total area
18528 * the element occupies, including any padding
18529 * the instance is configured for.
18532 getLocation: function(oDD) {
18533 if (! this.isTypeOfDD(oDD)) {
18537 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18540 pos= Roo.lib.Dom.getXY(el);
18548 x2 = x1 + el.offsetWidth;
18550 y2 = y1 + el.offsetHeight;
18552 t = y1 - oDD.padding[0];
18553 r = x2 + oDD.padding[1];
18554 b = y2 + oDD.padding[2];
18555 l = x1 - oDD.padding[3];
18557 return new Roo.lib.Region( t, r, b, l );
18561 * Checks the cursor location to see if it over the target
18562 * @method isOverTarget
18563 * @param {Roo.lib.Point} pt The point to evaluate
18564 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18565 * @return {boolean} true if the mouse is over the target
18569 isOverTarget: function(pt, oTarget, intersect) {
18570 // use cache if available
18571 var loc = this.locationCache[oTarget.id];
18572 if (!loc || !this.useCache) {
18573 loc = this.getLocation(oTarget);
18574 this.locationCache[oTarget.id] = loc;
18582 oTarget.cursorIsOver = loc.contains( pt );
18584 // DragDrop is using this as a sanity check for the initial mousedown
18585 // in this case we are done. In POINT mode, if the drag obj has no
18586 // contraints, we are also done. Otherwise we need to evaluate the
18587 // location of the target as related to the actual location of the
18588 // dragged element.
18589 var dc = this.dragCurrent;
18590 if (!dc || !dc.getTargetCoord ||
18591 (!intersect && !dc.constrainX && !dc.constrainY)) {
18592 return oTarget.cursorIsOver;
18595 oTarget.overlap = null;
18597 // Get the current location of the drag element, this is the
18598 // location of the mouse event less the delta that represents
18599 // where the original mousedown happened on the element. We
18600 // need to consider constraints and ticks as well.
18601 var pos = dc.getTargetCoord(pt.x, pt.y);
18603 var el = dc.getDragEl();
18604 var curRegion = new Roo.lib.Region( pos.y,
18605 pos.x + el.offsetWidth,
18606 pos.y + el.offsetHeight,
18609 var overlap = curRegion.intersect(loc);
18612 oTarget.overlap = overlap;
18613 return (intersect) ? true : oTarget.cursorIsOver;
18620 * unload event handler
18621 * @method _onUnload
18625 _onUnload: function(e, me) {
18626 Roo.dd.DragDropMgr.unregAll();
18630 * Cleans up the drag and drop events and objects.
18635 unregAll: function() {
18637 if (this.dragCurrent) {
18639 this.dragCurrent = null;
18642 this._execOnAll("unreg", []);
18644 for (i in this.elementCache) {
18645 delete this.elementCache[i];
18648 this.elementCache = {};
18653 * A cache of DOM elements
18654 * @property elementCache
18661 * Get the wrapper for the DOM element specified
18662 * @method getElWrapper
18663 * @param {String} id the id of the element to get
18664 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18666 * @deprecated This wrapper isn't that useful
18669 getElWrapper: function(id) {
18670 var oWrapper = this.elementCache[id];
18671 if (!oWrapper || !oWrapper.el) {
18672 oWrapper = this.elementCache[id] =
18673 new this.ElementWrapper(Roo.getDom(id));
18679 * Returns the actual DOM element
18680 * @method getElement
18681 * @param {String} id the id of the elment to get
18682 * @return {Object} The element
18683 * @deprecated use Roo.getDom instead
18686 getElement: function(id) {
18687 return Roo.getDom(id);
18691 * Returns the style property for the DOM element (i.e.,
18692 * document.getElById(id).style)
18694 * @param {String} id the id of the elment to get
18695 * @return {Object} The style property of the element
18696 * @deprecated use Roo.getDom instead
18699 getCss: function(id) {
18700 var el = Roo.getDom(id);
18701 return (el) ? el.style : null;
18705 * Inner class for cached elements
18706 * @class DragDropMgr.ElementWrapper
18711 ElementWrapper: function(el) {
18716 this.el = el || null;
18721 this.id = this.el && el.id;
18723 * A reference to the style property
18726 this.css = this.el && el.style;
18730 * Returns the X position of an html element
18732 * @param el the element for which to get the position
18733 * @return {int} the X coordinate
18735 * @deprecated use Roo.lib.Dom.getX instead
18738 getPosX: function(el) {
18739 return Roo.lib.Dom.getX(el);
18743 * Returns the Y position of an html element
18745 * @param el the element for which to get the position
18746 * @return {int} the Y coordinate
18747 * @deprecated use Roo.lib.Dom.getY instead
18750 getPosY: function(el) {
18751 return Roo.lib.Dom.getY(el);
18755 * Swap two nodes. In IE, we use the native method, for others we
18756 * emulate the IE behavior
18758 * @param n1 the first node to swap
18759 * @param n2 the other node to swap
18762 swapNode: function(n1, n2) {
18766 var p = n2.parentNode;
18767 var s = n2.nextSibling;
18770 p.insertBefore(n1, n2);
18771 } else if (n2 == n1.nextSibling) {
18772 p.insertBefore(n2, n1);
18774 n1.parentNode.replaceChild(n2, n1);
18775 p.insertBefore(n1, s);
18781 * Returns the current scroll position
18782 * @method getScroll
18786 getScroll: function () {
18787 var t, l, dde=document.documentElement, db=document.body;
18788 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18790 l = dde.scrollLeft;
18797 return { top: t, left: l };
18801 * Returns the specified element style property
18803 * @param {HTMLElement} el the element
18804 * @param {string} styleProp the style property
18805 * @return {string} The value of the style property
18806 * @deprecated use Roo.lib.Dom.getStyle
18809 getStyle: function(el, styleProp) {
18810 return Roo.fly(el).getStyle(styleProp);
18814 * Gets the scrollTop
18815 * @method getScrollTop
18816 * @return {int} the document's scrollTop
18819 getScrollTop: function () { return this.getScroll().top; },
18822 * Gets the scrollLeft
18823 * @method getScrollLeft
18824 * @return {int} the document's scrollTop
18827 getScrollLeft: function () { return this.getScroll().left; },
18830 * Sets the x/y position of an element to the location of the
18833 * @param {HTMLElement} moveEl The element to move
18834 * @param {HTMLElement} targetEl The position reference element
18837 moveToEl: function (moveEl, targetEl) {
18838 var aCoord = Roo.lib.Dom.getXY(targetEl);
18839 Roo.lib.Dom.setXY(moveEl, aCoord);
18843 * Numeric array sort function
18844 * @method numericSort
18847 numericSort: function(a, b) { return (a - b); },
18851 * @property _timeoutCount
18858 * Trying to make the load order less important. Without this we get
18859 * an error if this file is loaded before the Event Utility.
18860 * @method _addListeners
18864 _addListeners: function() {
18865 var DDM = Roo.dd.DDM;
18866 if ( Roo.lib.Event && document ) {
18869 if (DDM._timeoutCount > 2000) {
18871 setTimeout(DDM._addListeners, 10);
18872 if (document && document.body) {
18873 DDM._timeoutCount += 1;
18880 * Recursively searches the immediate parent and all child nodes for
18881 * the handle element in order to determine wheter or not it was
18883 * @method handleWasClicked
18884 * @param node the html element to inspect
18887 handleWasClicked: function(node, id) {
18888 if (this.isHandle(id, node.id)) {
18891 // check to see if this is a text node child of the one we want
18892 var p = node.parentNode;
18895 if (this.isHandle(id, p.id)) {
18910 // shorter alias, save a few bytes
18911 Roo.dd.DDM = Roo.dd.DragDropMgr;
18912 Roo.dd.DDM._addListeners();
18916 * Ext JS Library 1.1.1
18917 * Copyright(c) 2006-2007, Ext JS, LLC.
18919 * Originally Released Under LGPL - original licence link has changed is not relivant.
18922 * <script type="text/javascript">
18927 * A DragDrop implementation where the linked element follows the
18928 * mouse cursor during a drag.
18929 * @extends Roo.dd.DragDrop
18931 * @param {String} id the id of the linked element
18932 * @param {String} sGroup the group of related DragDrop items
18933 * @param {object} config an object containing configurable attributes
18934 * Valid properties for DD:
18937 Roo.dd.DD = function(id, sGroup, config) {
18939 this.init(id, sGroup, config);
18943 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18946 * When set to true, the utility automatically tries to scroll the browser
18947 * window wehn a drag and drop element is dragged near the viewport boundary.
18948 * Defaults to true.
18955 * Sets the pointer offset to the distance between the linked element's top
18956 * left corner and the location the element was clicked
18957 * @method autoOffset
18958 * @param {int} iPageX the X coordinate of the click
18959 * @param {int} iPageY the Y coordinate of the click
18961 autoOffset: function(iPageX, iPageY) {
18962 var x = iPageX - this.startPageX;
18963 var y = iPageY - this.startPageY;
18964 this.setDelta(x, y);
18968 * Sets the pointer offset. You can call this directly to force the
18969 * offset to be in a particular location (e.g., pass in 0,0 to set it
18970 * to the center of the object)
18972 * @param {int} iDeltaX the distance from the left
18973 * @param {int} iDeltaY the distance from the top
18975 setDelta: function(iDeltaX, iDeltaY) {
18976 this.deltaX = iDeltaX;
18977 this.deltaY = iDeltaY;
18981 * Sets the drag element to the location of the mousedown or click event,
18982 * maintaining the cursor location relative to the location on the element
18983 * that was clicked. Override this if you want to place the element in a
18984 * location other than where the cursor is.
18985 * @method setDragElPos
18986 * @param {int} iPageX the X coordinate of the mousedown or drag event
18987 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18989 setDragElPos: function(iPageX, iPageY) {
18990 // the first time we do this, we are going to check to make sure
18991 // the element has css positioning
18993 var el = this.getDragEl();
18994 this.alignElWithMouse(el, iPageX, iPageY);
18998 * Sets the element to the location of the mousedown or click event,
18999 * maintaining the cursor location relative to the location on the element
19000 * that was clicked. Override this if you want to place the element in a
19001 * location other than where the cursor is.
19002 * @method alignElWithMouse
19003 * @param {HTMLElement} el the element to move
19004 * @param {int} iPageX the X coordinate of the mousedown or drag event
19005 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19007 alignElWithMouse: function(el, iPageX, iPageY) {
19008 var oCoord = this.getTargetCoord(iPageX, iPageY);
19009 var fly = el.dom ? el : Roo.fly(el);
19010 if (!this.deltaSetXY) {
19011 var aCoord = [oCoord.x, oCoord.y];
19013 var newLeft = fly.getLeft(true);
19014 var newTop = fly.getTop(true);
19015 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19017 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19020 this.cachePosition(oCoord.x, oCoord.y);
19021 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19026 * Saves the most recent position so that we can reset the constraints and
19027 * tick marks on-demand. We need to know this so that we can calculate the
19028 * number of pixels the element is offset from its original position.
19029 * @method cachePosition
19030 * @param iPageX the current x position (optional, this just makes it so we
19031 * don't have to look it up again)
19032 * @param iPageY the current y position (optional, this just makes it so we
19033 * don't have to look it up again)
19035 cachePosition: function(iPageX, iPageY) {
19037 this.lastPageX = iPageX;
19038 this.lastPageY = iPageY;
19040 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19041 this.lastPageX = aCoord[0];
19042 this.lastPageY = aCoord[1];
19047 * Auto-scroll the window if the dragged object has been moved beyond the
19048 * visible window boundary.
19049 * @method autoScroll
19050 * @param {int} x the drag element's x position
19051 * @param {int} y the drag element's y position
19052 * @param {int} h the height of the drag element
19053 * @param {int} w the width of the drag element
19056 autoScroll: function(x, y, h, w) {
19059 // The client height
19060 var clientH = Roo.lib.Dom.getViewWidth();
19062 // The client width
19063 var clientW = Roo.lib.Dom.getViewHeight();
19065 // The amt scrolled down
19066 var st = this.DDM.getScrollTop();
19068 // The amt scrolled right
19069 var sl = this.DDM.getScrollLeft();
19071 // Location of the bottom of the element
19074 // Location of the right of the element
19077 // The distance from the cursor to the bottom of the visible area,
19078 // adjusted so that we don't scroll if the cursor is beyond the
19079 // element drag constraints
19080 var toBot = (clientH + st - y - this.deltaY);
19082 // The distance from the cursor to the right of the visible area
19083 var toRight = (clientW + sl - x - this.deltaX);
19086 // How close to the edge the cursor must be before we scroll
19087 // var thresh = (document.all) ? 100 : 40;
19090 // How many pixels to scroll per autoscroll op. This helps to reduce
19091 // clunky scrolling. IE is more sensitive about this ... it needs this
19092 // value to be higher.
19093 var scrAmt = (document.all) ? 80 : 30;
19095 // Scroll down if we are near the bottom of the visible page and the
19096 // obj extends below the crease
19097 if ( bot > clientH && toBot < thresh ) {
19098 window.scrollTo(sl, st + scrAmt);
19101 // Scroll up if the window is scrolled down and the top of the object
19102 // goes above the top border
19103 if ( y < st && st > 0 && y - st < thresh ) {
19104 window.scrollTo(sl, st - scrAmt);
19107 // Scroll right if the obj is beyond the right border and the cursor is
19108 // near the border.
19109 if ( right > clientW && toRight < thresh ) {
19110 window.scrollTo(sl + scrAmt, st);
19113 // Scroll left if the window has been scrolled to the right and the obj
19114 // extends past the left border
19115 if ( x < sl && sl > 0 && x - sl < thresh ) {
19116 window.scrollTo(sl - scrAmt, st);
19122 * Finds the location the element should be placed if we want to move
19123 * it to where the mouse location less the click offset would place us.
19124 * @method getTargetCoord
19125 * @param {int} iPageX the X coordinate of the click
19126 * @param {int} iPageY the Y coordinate of the click
19127 * @return an object that contains the coordinates (Object.x and Object.y)
19130 getTargetCoord: function(iPageX, iPageY) {
19133 var x = iPageX - this.deltaX;
19134 var y = iPageY - this.deltaY;
19136 if (this.constrainX) {
19137 if (x < this.minX) { x = this.minX; }
19138 if (x > this.maxX) { x = this.maxX; }
19141 if (this.constrainY) {
19142 if (y < this.minY) { y = this.minY; }
19143 if (y > this.maxY) { y = this.maxY; }
19146 x = this.getTick(x, this.xTicks);
19147 y = this.getTick(y, this.yTicks);
19154 * Sets up config options specific to this class. Overrides
19155 * Roo.dd.DragDrop, but all versions of this method through the
19156 * inheritance chain are called
19158 applyConfig: function() {
19159 Roo.dd.DD.superclass.applyConfig.call(this);
19160 this.scroll = (this.config.scroll !== false);
19164 * Event that fires prior to the onMouseDown event. Overrides
19167 b4MouseDown: function(e) {
19168 // this.resetConstraints();
19169 this.autoOffset(e.getPageX(),
19174 * Event that fires prior to the onDrag event. Overrides
19177 b4Drag: function(e) {
19178 this.setDragElPos(e.getPageX(),
19182 toString: function() {
19183 return ("DD " + this.id);
19186 //////////////////////////////////////////////////////////////////////////
19187 // Debugging ygDragDrop events that can be overridden
19188 //////////////////////////////////////////////////////////////////////////
19190 startDrag: function(x, y) {
19193 onDrag: function(e) {
19196 onDragEnter: function(e, id) {
19199 onDragOver: function(e, id) {
19202 onDragOut: function(e, id) {
19205 onDragDrop: function(e, id) {
19208 endDrag: function(e) {
19215 * Ext JS Library 1.1.1
19216 * Copyright(c) 2006-2007, Ext JS, LLC.
19218 * Originally Released Under LGPL - original licence link has changed is not relivant.
19221 * <script type="text/javascript">
19225 * @class Roo.dd.DDProxy
19226 * A DragDrop implementation that inserts an empty, bordered div into
19227 * the document that follows the cursor during drag operations. At the time of
19228 * the click, the frame div is resized to the dimensions of the linked html
19229 * element, and moved to the exact location of the linked element.
19231 * References to the "frame" element refer to the single proxy element that
19232 * was created to be dragged in place of all DDProxy elements on the
19235 * @extends Roo.dd.DD
19237 * @param {String} id the id of the linked html element
19238 * @param {String} sGroup the group of related DragDrop objects
19239 * @param {object} config an object containing configurable attributes
19240 * Valid properties for DDProxy in addition to those in DragDrop:
19241 * resizeFrame, centerFrame, dragElId
19243 Roo.dd.DDProxy = function(id, sGroup, config) {
19245 this.init(id, sGroup, config);
19251 * The default drag frame div id
19252 * @property Roo.dd.DDProxy.dragElId
19256 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19258 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19261 * By default we resize the drag frame to be the same size as the element
19262 * we want to drag (this is to get the frame effect). We can turn it off
19263 * if we want a different behavior.
19264 * @property resizeFrame
19270 * By default the frame is positioned exactly where the drag element is, so
19271 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19272 * you do not have constraints on the obj is to have the drag frame centered
19273 * around the cursor. Set centerFrame to true for this effect.
19274 * @property centerFrame
19277 centerFrame: false,
19280 * Creates the proxy element if it does not yet exist
19281 * @method createFrame
19283 createFrame: function() {
19285 var body = document.body;
19287 if (!body || !body.firstChild) {
19288 setTimeout( function() { self.createFrame(); }, 50 );
19292 var div = this.getDragEl();
19295 div = document.createElement("div");
19296 div.id = this.dragElId;
19299 s.position = "absolute";
19300 s.visibility = "hidden";
19302 s.border = "2px solid #aaa";
19305 // appendChild can blow up IE if invoked prior to the window load event
19306 // while rendering a table. It is possible there are other scenarios
19307 // that would cause this to happen as well.
19308 body.insertBefore(div, body.firstChild);
19313 * Initialization for the drag frame element. Must be called in the
19314 * constructor of all subclasses
19315 * @method initFrame
19317 initFrame: function() {
19318 this.createFrame();
19321 applyConfig: function() {
19322 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19324 this.resizeFrame = (this.config.resizeFrame !== false);
19325 this.centerFrame = (this.config.centerFrame);
19326 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19330 * Resizes the drag frame to the dimensions of the clicked object, positions
19331 * it over the object, and finally displays it
19332 * @method showFrame
19333 * @param {int} iPageX X click position
19334 * @param {int} iPageY Y click position
19337 showFrame: function(iPageX, iPageY) {
19338 var el = this.getEl();
19339 var dragEl = this.getDragEl();
19340 var s = dragEl.style;
19342 this._resizeProxy();
19344 if (this.centerFrame) {
19345 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19346 Math.round(parseInt(s.height, 10)/2) );
19349 this.setDragElPos(iPageX, iPageY);
19351 Roo.fly(dragEl).show();
19355 * The proxy is automatically resized to the dimensions of the linked
19356 * element when a drag is initiated, unless resizeFrame is set to false
19357 * @method _resizeProxy
19360 _resizeProxy: function() {
19361 if (this.resizeFrame) {
19362 var el = this.getEl();
19363 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19367 // overrides Roo.dd.DragDrop
19368 b4MouseDown: function(e) {
19369 var x = e.getPageX();
19370 var y = e.getPageY();
19371 this.autoOffset(x, y);
19372 this.setDragElPos(x, y);
19375 // overrides Roo.dd.DragDrop
19376 b4StartDrag: function(x, y) {
19377 // show the drag frame
19378 this.showFrame(x, y);
19381 // overrides Roo.dd.DragDrop
19382 b4EndDrag: function(e) {
19383 Roo.fly(this.getDragEl()).hide();
19386 // overrides Roo.dd.DragDrop
19387 // By default we try to move the element to the last location of the frame.
19388 // This is so that the default behavior mirrors that of Roo.dd.DD.
19389 endDrag: function(e) {
19391 var lel = this.getEl();
19392 var del = this.getDragEl();
19394 // Show the drag frame briefly so we can get its position
19395 del.style.visibility = "";
19398 // Hide the linked element before the move to get around a Safari
19400 lel.style.visibility = "hidden";
19401 Roo.dd.DDM.moveToEl(lel, del);
19402 del.style.visibility = "hidden";
19403 lel.style.visibility = "";
19408 beforeMove : function(){
19412 afterDrag : function(){
19416 toString: function() {
19417 return ("DDProxy " + this.id);
19423 * Ext JS Library 1.1.1
19424 * Copyright(c) 2006-2007, Ext JS, LLC.
19426 * Originally Released Under LGPL - original licence link has changed is not relivant.
19429 * <script type="text/javascript">
19433 * @class Roo.dd.DDTarget
19434 * A DragDrop implementation that does not move, but can be a drop
19435 * target. You would get the same result by simply omitting implementation
19436 * for the event callbacks, but this way we reduce the processing cost of the
19437 * event listener and the callbacks.
19438 * @extends Roo.dd.DragDrop
19440 * @param {String} id the id of the element that is a drop target
19441 * @param {String} sGroup the group of related DragDrop objects
19442 * @param {object} config an object containing configurable attributes
19443 * Valid properties for DDTarget in addition to those in
19447 Roo.dd.DDTarget = function(id, sGroup, config) {
19449 this.initTarget(id, sGroup, config);
19451 if (config.listeners || config.events) {
19452 Roo.dd.DragDrop.superclass.constructor.call(this, {
19453 listeners : config.listeners || {},
19454 events : config.events || {}
19459 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19460 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19461 toString: function() {
19462 return ("DDTarget " + this.id);
19467 * Ext JS Library 1.1.1
19468 * Copyright(c) 2006-2007, Ext JS, LLC.
19470 * Originally Released Under LGPL - original licence link has changed is not relivant.
19473 * <script type="text/javascript">
19478 * @class Roo.dd.ScrollManager
19479 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19480 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19483 Roo.dd.ScrollManager = function(){
19484 var ddm = Roo.dd.DragDropMgr;
19491 var onStop = function(e){
19496 var triggerRefresh = function(){
19497 if(ddm.dragCurrent){
19498 ddm.refreshCache(ddm.dragCurrent.groups);
19502 var doScroll = function(){
19503 if(ddm.dragCurrent){
19504 var dds = Roo.dd.ScrollManager;
19506 if(proc.el.scroll(proc.dir, dds.increment)){
19510 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19515 var clearProc = function(){
19517 clearInterval(proc.id);
19524 var startProc = function(el, dir){
19525 Roo.log('scroll startproc');
19529 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19532 var onFire = function(e, isDrop){
19534 if(isDrop || !ddm.dragCurrent){ return; }
19535 var dds = Roo.dd.ScrollManager;
19536 if(!dragEl || dragEl != ddm.dragCurrent){
19537 dragEl = ddm.dragCurrent;
19538 // refresh regions on drag start
19539 dds.refreshCache();
19542 var xy = Roo.lib.Event.getXY(e);
19543 var pt = new Roo.lib.Point(xy[0], xy[1]);
19544 for(var id in els){
19545 var el = els[id], r = el._region;
19546 if(r && r.contains(pt) && el.isScrollable()){
19547 if(r.bottom - pt.y <= dds.thresh){
19549 startProc(el, "down");
19552 }else if(r.right - pt.x <= dds.thresh){
19554 startProc(el, "left");
19557 }else if(pt.y - r.top <= dds.thresh){
19559 startProc(el, "up");
19562 }else if(pt.x - r.left <= dds.thresh){
19564 startProc(el, "right");
19573 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19574 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19578 * Registers new overflow element(s) to auto scroll
19579 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19581 register : function(el){
19582 if(el instanceof Array){
19583 for(var i = 0, len = el.length; i < len; i++) {
19584 this.register(el[i]);
19590 Roo.dd.ScrollManager.els = els;
19594 * Unregisters overflow element(s) so they are no longer scrolled
19595 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19597 unregister : function(el){
19598 if(el instanceof Array){
19599 for(var i = 0, len = el.length; i < len; i++) {
19600 this.unregister(el[i]);
19609 * The number of pixels from the edge of a container the pointer needs to be to
19610 * trigger scrolling (defaults to 25)
19616 * The number of pixels to scroll in each scroll increment (defaults to 50)
19622 * The frequency of scrolls in milliseconds (defaults to 500)
19628 * True to animate the scroll (defaults to true)
19634 * The animation duration in seconds -
19635 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19641 * Manually trigger a cache refresh.
19643 refreshCache : function(){
19644 for(var id in els){
19645 if(typeof els[id] == 'object'){ // for people extending the object prototype
19646 els[id]._region = els[id].getRegion();
19653 * Ext JS Library 1.1.1
19654 * Copyright(c) 2006-2007, Ext JS, LLC.
19656 * Originally Released Under LGPL - original licence link has changed is not relivant.
19659 * <script type="text/javascript">
19664 * @class Roo.dd.Registry
19665 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19666 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19669 Roo.dd.Registry = function(){
19672 var autoIdSeed = 0;
19674 var getId = function(el, autogen){
19675 if(typeof el == "string"){
19679 if(!id && autogen !== false){
19680 id = "roodd-" + (++autoIdSeed);
19688 * Register a drag drop element
19689 * @param {String|HTMLElement} element The id or DOM node to register
19690 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19691 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19692 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19693 * populated in the data object (if applicable):
19695 Value Description<br />
19696 --------- ------------------------------------------<br />
19697 handles Array of DOM nodes that trigger dragging<br />
19698 for the element being registered<br />
19699 isHandle True if the element passed in triggers<br />
19700 dragging itself, else false
19703 register : function(el, data){
19705 if(typeof el == "string"){
19706 el = document.getElementById(el);
19709 elements[getId(el)] = data;
19710 if(data.isHandle !== false){
19711 handles[data.ddel.id] = data;
19714 var hs = data.handles;
19715 for(var i = 0, len = hs.length; i < len; i++){
19716 handles[getId(hs[i])] = data;
19722 * Unregister a drag drop element
19723 * @param {String|HTMLElement} element The id or DOM node to unregister
19725 unregister : function(el){
19726 var id = getId(el, false);
19727 var data = elements[id];
19729 delete elements[id];
19731 var hs = data.handles;
19732 for(var i = 0, len = hs.length; i < len; i++){
19733 delete handles[getId(hs[i], false)];
19740 * Returns the handle registered for a DOM Node by id
19741 * @param {String|HTMLElement} id The DOM node or id to look up
19742 * @return {Object} handle The custom handle data
19744 getHandle : function(id){
19745 if(typeof id != "string"){ // must be element?
19748 return handles[id];
19752 * Returns the handle that is registered for the DOM node that is the target of the event
19753 * @param {Event} e The event
19754 * @return {Object} handle The custom handle data
19756 getHandleFromEvent : function(e){
19757 var t = Roo.lib.Event.getTarget(e);
19758 return t ? handles[t.id] : null;
19762 * Returns a custom data object that is registered for a DOM node by id
19763 * @param {String|HTMLElement} id The DOM node or id to look up
19764 * @return {Object} data The custom data
19766 getTarget : function(id){
19767 if(typeof id != "string"){ // must be element?
19770 return elements[id];
19774 * Returns a custom data object that is registered for the DOM node that is the target of the event
19775 * @param {Event} e The event
19776 * @return {Object} data The custom data
19778 getTargetFromEvent : function(e){
19779 var t = Roo.lib.Event.getTarget(e);
19780 return t ? elements[t.id] || handles[t.id] : null;
19785 * Ext JS Library 1.1.1
19786 * Copyright(c) 2006-2007, Ext JS, LLC.
19788 * Originally Released Under LGPL - original licence link has changed is not relivant.
19791 * <script type="text/javascript">
19796 * @class Roo.dd.StatusProxy
19797 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19798 * default drag proxy used by all Roo.dd components.
19800 * @param {Object} config
19802 Roo.dd.StatusProxy = function(config){
19803 Roo.apply(this, config);
19804 this.id = this.id || Roo.id();
19805 this.el = new Roo.Layer({
19807 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19808 {tag: "div", cls: "x-dd-drop-icon"},
19809 {tag: "div", cls: "x-dd-drag-ghost"}
19812 shadow: !config || config.shadow !== false
19814 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19815 this.dropStatus = this.dropNotAllowed;
19818 Roo.dd.StatusProxy.prototype = {
19820 * @cfg {String} dropAllowed
19821 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19823 dropAllowed : "x-dd-drop-ok",
19825 * @cfg {String} dropNotAllowed
19826 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19828 dropNotAllowed : "x-dd-drop-nodrop",
19831 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19832 * over the current target element.
19833 * @param {String} cssClass The css class for the new drop status indicator image
19835 setStatus : function(cssClass){
19836 cssClass = cssClass || this.dropNotAllowed;
19837 if(this.dropStatus != cssClass){
19838 this.el.replaceClass(this.dropStatus, cssClass);
19839 this.dropStatus = cssClass;
19844 * Resets the status indicator to the default dropNotAllowed value
19845 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19847 reset : function(clearGhost){
19848 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19849 this.dropStatus = this.dropNotAllowed;
19851 this.ghost.update("");
19856 * Updates the contents of the ghost element
19857 * @param {String} html The html that will replace the current innerHTML of the ghost element
19859 update : function(html){
19860 if(typeof html == "string"){
19861 this.ghost.update(html);
19863 this.ghost.update("");
19864 html.style.margin = "0";
19865 this.ghost.dom.appendChild(html);
19867 // ensure float = none set?? cant remember why though.
19868 var el = this.ghost.dom.firstChild;
19870 Roo.fly(el).setStyle('float', 'none');
19875 * Returns the underlying proxy {@link Roo.Layer}
19876 * @return {Roo.Layer} el
19878 getEl : function(){
19883 * Returns the ghost element
19884 * @return {Roo.Element} el
19886 getGhost : function(){
19892 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19894 hide : function(clear){
19902 * Stops the repair animation if it's currently running
19905 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19911 * Displays this proxy
19918 * Force the Layer to sync its shadow and shim positions to the element
19925 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19926 * invalid drop operation by the item being dragged.
19927 * @param {Array} xy The XY position of the element ([x, y])
19928 * @param {Function} callback The function to call after the repair is complete
19929 * @param {Object} scope The scope in which to execute the callback
19931 repair : function(xy, callback, scope){
19932 this.callback = callback;
19933 this.scope = scope;
19934 if(xy && this.animRepair !== false){
19935 this.el.addClass("x-dd-drag-repair");
19936 this.el.hideUnders(true);
19937 this.anim = this.el.shift({
19938 duration: this.repairDuration || .5,
19942 callback: this.afterRepair,
19946 this.afterRepair();
19951 afterRepair : function(){
19953 if(typeof this.callback == "function"){
19954 this.callback.call(this.scope || this);
19956 this.callback = null;
19961 * Ext JS Library 1.1.1
19962 * Copyright(c) 2006-2007, Ext JS, LLC.
19964 * Originally Released Under LGPL - original licence link has changed is not relivant.
19967 * <script type="text/javascript">
19971 * @class Roo.dd.DragSource
19972 * @extends Roo.dd.DDProxy
19973 * A simple class that provides the basic implementation needed to make any element draggable.
19975 * @param {String/HTMLElement/Element} el The container element
19976 * @param {Object} config
19978 Roo.dd.DragSource = function(el, config){
19979 this.el = Roo.get(el);
19980 this.dragData = {};
19982 Roo.apply(this, config);
19985 this.proxy = new Roo.dd.StatusProxy();
19988 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19989 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19991 this.dragging = false;
19994 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19996 * @cfg {String} dropAllowed
19997 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19999 dropAllowed : "x-dd-drop-ok",
20001 * @cfg {String} dropNotAllowed
20002 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20004 dropNotAllowed : "x-dd-drop-nodrop",
20007 * Returns the data object associated with this drag source
20008 * @return {Object} data An object containing arbitrary data
20010 getDragData : function(e){
20011 return this.dragData;
20015 onDragEnter : function(e, id){
20016 var target = Roo.dd.DragDropMgr.getDDById(id);
20017 this.cachedTarget = target;
20018 if(this.beforeDragEnter(target, e, id) !== false){
20019 if(target.isNotifyTarget){
20020 var status = target.notifyEnter(this, e, this.dragData);
20021 this.proxy.setStatus(status);
20023 this.proxy.setStatus(this.dropAllowed);
20026 if(this.afterDragEnter){
20028 * An empty function by default, but provided so that you can perform a custom action
20029 * when the dragged item enters the drop target by providing an implementation.
20030 * @param {Roo.dd.DragDrop} target The drop target
20031 * @param {Event} e The event object
20032 * @param {String} id The id of the dragged element
20033 * @method afterDragEnter
20035 this.afterDragEnter(target, e, id);
20041 * An empty function by default, but provided so that you can perform a custom action
20042 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20043 * @param {Roo.dd.DragDrop} target The drop target
20044 * @param {Event} e The event object
20045 * @param {String} id The id of the dragged element
20046 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20048 beforeDragEnter : function(target, e, id){
20053 alignElWithMouse: function() {
20054 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20059 onDragOver : function(e, id){
20060 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20061 if(this.beforeDragOver(target, e, id) !== false){
20062 if(target.isNotifyTarget){
20063 var status = target.notifyOver(this, e, this.dragData);
20064 this.proxy.setStatus(status);
20067 if(this.afterDragOver){
20069 * An empty function by default, but provided so that you can perform a custom action
20070 * while the dragged item is over the drop target by providing an implementation.
20071 * @param {Roo.dd.DragDrop} target The drop target
20072 * @param {Event} e The event object
20073 * @param {String} id The id of the dragged element
20074 * @method afterDragOver
20076 this.afterDragOver(target, e, id);
20082 * An empty function by default, but provided so that you can perform a custom action
20083 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20084 * @param {Roo.dd.DragDrop} target The drop target
20085 * @param {Event} e The event object
20086 * @param {String} id The id of the dragged element
20087 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20089 beforeDragOver : function(target, e, id){
20094 onDragOut : function(e, id){
20095 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20096 if(this.beforeDragOut(target, e, id) !== false){
20097 if(target.isNotifyTarget){
20098 target.notifyOut(this, e, this.dragData);
20100 this.proxy.reset();
20101 if(this.afterDragOut){
20103 * An empty function by default, but provided so that you can perform a custom action
20104 * after the dragged item is dragged out of the target without dropping.
20105 * @param {Roo.dd.DragDrop} target The drop target
20106 * @param {Event} e The event object
20107 * @param {String} id The id of the dragged element
20108 * @method afterDragOut
20110 this.afterDragOut(target, e, id);
20113 this.cachedTarget = null;
20117 * An empty function by default, but provided so that you can perform a custom action before the dragged
20118 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20119 * @param {Roo.dd.DragDrop} target The drop target
20120 * @param {Event} e The event object
20121 * @param {String} id The id of the dragged element
20122 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20124 beforeDragOut : function(target, e, id){
20129 onDragDrop : function(e, id){
20130 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20131 if(this.beforeDragDrop(target, e, id) !== false){
20132 if(target.isNotifyTarget){
20133 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20134 this.onValidDrop(target, e, id);
20136 this.onInvalidDrop(target, e, id);
20139 this.onValidDrop(target, e, id);
20142 if(this.afterDragDrop){
20144 * An empty function by default, but provided so that you can perform a custom action
20145 * after a valid drag drop has occurred by providing an implementation.
20146 * @param {Roo.dd.DragDrop} target The drop target
20147 * @param {Event} e The event object
20148 * @param {String} id The id of the dropped element
20149 * @method afterDragDrop
20151 this.afterDragDrop(target, e, id);
20154 delete this.cachedTarget;
20158 * An empty function by default, but provided so that you can perform a custom action before the dragged
20159 * item is dropped onto the target and optionally cancel the onDragDrop.
20160 * @param {Roo.dd.DragDrop} target The drop target
20161 * @param {Event} e The event object
20162 * @param {String} id The id of the dragged element
20163 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20165 beforeDragDrop : function(target, e, id){
20170 onValidDrop : function(target, e, id){
20172 if(this.afterValidDrop){
20174 * An empty function by default, but provided so that you can perform a custom action
20175 * after a valid drop has occurred by providing an implementation.
20176 * @param {Object} target The target DD
20177 * @param {Event} e The event object
20178 * @param {String} id The id of the dropped element
20179 * @method afterInvalidDrop
20181 this.afterValidDrop(target, e, id);
20186 getRepairXY : function(e, data){
20187 return this.el.getXY();
20191 onInvalidDrop : function(target, e, id){
20192 this.beforeInvalidDrop(target, e, id);
20193 if(this.cachedTarget){
20194 if(this.cachedTarget.isNotifyTarget){
20195 this.cachedTarget.notifyOut(this, e, this.dragData);
20197 this.cacheTarget = null;
20199 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20201 if(this.afterInvalidDrop){
20203 * An empty function by default, but provided so that you can perform a custom action
20204 * after an invalid drop has occurred by providing an implementation.
20205 * @param {Event} e The event object
20206 * @param {String} id The id of the dropped element
20207 * @method afterInvalidDrop
20209 this.afterInvalidDrop(e, id);
20214 afterRepair : function(){
20216 this.el.highlight(this.hlColor || "c3daf9");
20218 this.dragging = false;
20222 * An empty function by default, but provided so that you can perform a custom action after an invalid
20223 * drop has occurred.
20224 * @param {Roo.dd.DragDrop} target The drop target
20225 * @param {Event} e The event object
20226 * @param {String} id The id of the dragged element
20227 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20229 beforeInvalidDrop : function(target, e, id){
20234 handleMouseDown : function(e){
20235 if(this.dragging) {
20238 var data = this.getDragData(e);
20239 if(data && this.onBeforeDrag(data, e) !== false){
20240 this.dragData = data;
20242 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20247 * An empty function by default, but provided so that you can perform a custom action before the initial
20248 * drag event begins and optionally cancel it.
20249 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20250 * @param {Event} e The event object
20251 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20253 onBeforeDrag : function(data, e){
20258 * An empty function by default, but provided so that you can perform a custom action once the initial
20259 * drag event has begun. The drag cannot be canceled from this function.
20260 * @param {Number} x The x position of the click on the dragged object
20261 * @param {Number} y The y position of the click on the dragged object
20263 onStartDrag : Roo.emptyFn,
20265 // private - YUI override
20266 startDrag : function(x, y){
20267 this.proxy.reset();
20268 this.dragging = true;
20269 this.proxy.update("");
20270 this.onInitDrag(x, y);
20275 onInitDrag : function(x, y){
20276 var clone = this.el.dom.cloneNode(true);
20277 clone.id = Roo.id(); // prevent duplicate ids
20278 this.proxy.update(clone);
20279 this.onStartDrag(x, y);
20284 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20285 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20287 getProxy : function(){
20292 * Hides the drag source's {@link Roo.dd.StatusProxy}
20294 hideProxy : function(){
20296 this.proxy.reset(true);
20297 this.dragging = false;
20301 triggerCacheRefresh : function(){
20302 Roo.dd.DDM.refreshCache(this.groups);
20305 // private - override to prevent hiding
20306 b4EndDrag: function(e) {
20309 // private - override to prevent moving
20310 endDrag : function(e){
20311 this.onEndDrag(this.dragData, e);
20315 onEndDrag : function(data, e){
20318 // private - pin to cursor
20319 autoOffset : function(x, y) {
20320 this.setDelta(-12, -20);
20324 * Ext JS Library 1.1.1
20325 * Copyright(c) 2006-2007, Ext JS, LLC.
20327 * Originally Released Under LGPL - original licence link has changed is not relivant.
20330 * <script type="text/javascript">
20335 * @class Roo.dd.DropTarget
20336 * @extends Roo.dd.DDTarget
20337 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20338 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20340 * @param {String/HTMLElement/Element} el The container element
20341 * @param {Object} config
20343 Roo.dd.DropTarget = function(el, config){
20344 this.el = Roo.get(el);
20346 var listeners = false; ;
20347 if (config && config.listeners) {
20348 listeners= config.listeners;
20349 delete config.listeners;
20351 Roo.apply(this, config);
20353 if(this.containerScroll){
20354 Roo.dd.ScrollManager.register(this.el);
20358 * @scope Roo.dd.DropTarget
20363 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20364 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20365 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20367 * IMPORTANT : it should set this.overClass and this.dropAllowed
20369 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20370 * @param {Event} e The event
20371 * @param {Object} data An object containing arbitrary data supplied by the drag source
20377 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20378 * This method will be called on every mouse movement while the drag source is over the drop target.
20379 * This default implementation simply returns the dropAllowed config value.
20381 * IMPORTANT : it should set this.dropAllowed
20383 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20384 * @param {Event} e The event
20385 * @param {Object} data An object containing arbitrary data supplied by the drag source
20391 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20392 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20393 * overClass (if any) from the drop element.
20395 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20396 * @param {Event} e The event
20397 * @param {Object} data An object containing arbitrary data supplied by the drag source
20403 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20404 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20405 * implementation that does something to process the drop event and returns true so that the drag source's
20406 * repair action does not run.
20408 * IMPORTANT : it should set this.success
20410 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20411 * @param {Event} e The event
20412 * @param {Object} data An object containing arbitrary data supplied by the drag source
20418 Roo.dd.DropTarget.superclass.constructor.call( this,
20420 this.ddGroup || this.group,
20423 listeners : listeners || {}
20431 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20433 * @cfg {String} overClass
20434 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20437 * @cfg {String} ddGroup
20438 * The drag drop group to handle drop events for
20442 * @cfg {String} dropAllowed
20443 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20445 dropAllowed : "x-dd-drop-ok",
20447 * @cfg {String} dropNotAllowed
20448 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20450 dropNotAllowed : "x-dd-drop-nodrop",
20452 * @cfg {boolean} success
20453 * set this after drop listener..
20457 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20458 * if the drop point is valid for over/enter..
20465 isNotifyTarget : true,
20470 notifyEnter : function(dd, e, data)
20473 this.fireEvent('enter', dd, e, data);
20474 if(this.overClass){
20475 this.el.addClass(this.overClass);
20477 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20478 this.valid ? this.dropAllowed : this.dropNotAllowed
20485 notifyOver : function(dd, e, data)
20488 this.fireEvent('over', dd, e, data);
20489 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20490 this.valid ? this.dropAllowed : this.dropNotAllowed
20497 notifyOut : function(dd, e, data)
20499 this.fireEvent('out', dd, e, data);
20500 if(this.overClass){
20501 this.el.removeClass(this.overClass);
20508 notifyDrop : function(dd, e, data)
20510 this.success = false;
20511 this.fireEvent('drop', dd, e, data);
20512 return this.success;
20516 * Ext JS Library 1.1.1
20517 * Copyright(c) 2006-2007, Ext JS, LLC.
20519 * Originally Released Under LGPL - original licence link has changed is not relivant.
20522 * <script type="text/javascript">
20527 * @class Roo.dd.DragZone
20528 * @extends Roo.dd.DragSource
20529 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20530 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20532 * @param {String/HTMLElement/Element} el The container element
20533 * @param {Object} config
20535 Roo.dd.DragZone = function(el, config){
20536 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20537 if(this.containerScroll){
20538 Roo.dd.ScrollManager.register(this.el);
20542 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20544 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20545 * for auto scrolling during drag operations.
20548 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20549 * method after a failed drop (defaults to "c3daf9" - light blue)
20553 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20554 * for a valid target to drag based on the mouse down. Override this method
20555 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20556 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20557 * @param {EventObject} e The mouse down event
20558 * @return {Object} The dragData
20560 getDragData : function(e){
20561 return Roo.dd.Registry.getHandleFromEvent(e);
20565 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20566 * this.dragData.ddel
20567 * @param {Number} x The x position of the click on the dragged object
20568 * @param {Number} y The y position of the click on the dragged object
20569 * @return {Boolean} true to continue the drag, false to cancel
20571 onInitDrag : function(x, y){
20572 this.proxy.update(this.dragData.ddel.cloneNode(true));
20573 this.onStartDrag(x, y);
20578 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20580 afterRepair : function(){
20582 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20584 this.dragging = false;
20588 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20589 * the XY of this.dragData.ddel
20590 * @param {EventObject} e The mouse up event
20591 * @return {Array} The xy location (e.g. [100, 200])
20593 getRepairXY : function(e){
20594 return Roo.Element.fly(this.dragData.ddel).getXY();
20598 * Ext JS Library 1.1.1
20599 * Copyright(c) 2006-2007, Ext JS, LLC.
20601 * Originally Released Under LGPL - original licence link has changed is not relivant.
20604 * <script type="text/javascript">
20607 * @class Roo.dd.DropZone
20608 * @extends Roo.dd.DropTarget
20609 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20610 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20612 * @param {String/HTMLElement/Element} el The container element
20613 * @param {Object} config
20615 Roo.dd.DropZone = function(el, config){
20616 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20619 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20621 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20622 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20623 * provide your own custom lookup.
20624 * @param {Event} e The event
20625 * @return {Object} data The custom data
20627 getTargetFromEvent : function(e){
20628 return Roo.dd.Registry.getTargetFromEvent(e);
20632 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20633 * that it has registered. This method has no default implementation and should be overridden to provide
20634 * node-specific processing if necessary.
20635 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20636 * {@link #getTargetFromEvent} for this node)
20637 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20638 * @param {Event} e The event
20639 * @param {Object} data An object containing arbitrary data supplied by the drag source
20641 onNodeEnter : function(n, dd, e, data){
20646 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20647 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20648 * overridden to provide the proper feedback.
20649 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20650 * {@link #getTargetFromEvent} for this node)
20651 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20652 * @param {Event} e The event
20653 * @param {Object} data An object containing arbitrary data supplied by the drag source
20654 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20655 * underlying {@link Roo.dd.StatusProxy} can be updated
20657 onNodeOver : function(n, dd, e, data){
20658 return this.dropAllowed;
20662 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20663 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20664 * node-specific processing if necessary.
20665 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20666 * {@link #getTargetFromEvent} for this node)
20667 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20668 * @param {Event} e The event
20669 * @param {Object} data An object containing arbitrary data supplied by the drag source
20671 onNodeOut : function(n, dd, e, data){
20676 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20677 * the drop node. The default implementation returns false, so it should be overridden to provide the
20678 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20679 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20680 * {@link #getTargetFromEvent} for this node)
20681 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20682 * @param {Event} e The event
20683 * @param {Object} data An object containing arbitrary data supplied by the drag source
20684 * @return {Boolean} True if the drop was valid, else false
20686 onNodeDrop : function(n, dd, e, data){
20691 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20692 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20693 * it should be overridden to provide the proper feedback if necessary.
20694 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20695 * @param {Event} e The event
20696 * @param {Object} data An object containing arbitrary data supplied by the drag source
20697 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20698 * underlying {@link Roo.dd.StatusProxy} can be updated
20700 onContainerOver : function(dd, e, data){
20701 return this.dropNotAllowed;
20705 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20706 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20707 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20708 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20709 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20710 * @param {Event} e The event
20711 * @param {Object} data An object containing arbitrary data supplied by the drag source
20712 * @return {Boolean} True if the drop was valid, else false
20714 onContainerDrop : function(dd, e, data){
20719 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20720 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20721 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20722 * you should override this method and provide a custom implementation.
20723 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20724 * @param {Event} e The event
20725 * @param {Object} data An object containing arbitrary data supplied by the drag source
20726 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20727 * underlying {@link Roo.dd.StatusProxy} can be updated
20729 notifyEnter : function(dd, e, data){
20730 return this.dropNotAllowed;
20734 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20735 * This method will be called on every mouse movement while the drag source is over the drop zone.
20736 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20737 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20738 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20739 * registered node, it will call {@link #onContainerOver}.
20740 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20741 * @param {Event} e The event
20742 * @param {Object} data An object containing arbitrary data supplied by the drag source
20743 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20744 * underlying {@link Roo.dd.StatusProxy} can be updated
20746 notifyOver : function(dd, e, data){
20747 var n = this.getTargetFromEvent(e);
20748 if(!n){ // not over valid drop target
20749 if(this.lastOverNode){
20750 this.onNodeOut(this.lastOverNode, dd, e, data);
20751 this.lastOverNode = null;
20753 return this.onContainerOver(dd, e, data);
20755 if(this.lastOverNode != n){
20756 if(this.lastOverNode){
20757 this.onNodeOut(this.lastOverNode, dd, e, data);
20759 this.onNodeEnter(n, dd, e, data);
20760 this.lastOverNode = n;
20762 return this.onNodeOver(n, dd, e, data);
20766 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20767 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20768 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20769 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20770 * @param {Event} e The event
20771 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20773 notifyOut : function(dd, e, data){
20774 if(this.lastOverNode){
20775 this.onNodeOut(this.lastOverNode, dd, e, data);
20776 this.lastOverNode = null;
20781 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20782 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20783 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20784 * otherwise it will call {@link #onContainerDrop}.
20785 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20786 * @param {Event} e The event
20787 * @param {Object} data An object containing arbitrary data supplied by the drag source
20788 * @return {Boolean} True if the drop was valid, else false
20790 notifyDrop : function(dd, e, data){
20791 if(this.lastOverNode){
20792 this.onNodeOut(this.lastOverNode, dd, e, data);
20793 this.lastOverNode = null;
20795 var n = this.getTargetFromEvent(e);
20797 this.onNodeDrop(n, dd, e, data) :
20798 this.onContainerDrop(dd, e, data);
20802 triggerCacheRefresh : function(){
20803 Roo.dd.DDM.refreshCache(this.groups);
20807 * Ext JS Library 1.1.1
20808 * Copyright(c) 2006-2007, Ext JS, LLC.
20810 * Originally Released Under LGPL - original licence link has changed is not relivant.
20813 * <script type="text/javascript">
20818 * @class Roo.data.SortTypes
20820 * Defines the default sorting (casting?) comparison functions used when sorting data.
20822 Roo.data.SortTypes = {
20824 * Default sort that does nothing
20825 * @param {Mixed} s The value being converted
20826 * @return {Mixed} The comparison value
20828 none : function(s){
20833 * The regular expression used to strip tags
20837 stripTagsRE : /<\/?[^>]+>/gi,
20840 * Strips all HTML tags to sort on text only
20841 * @param {Mixed} s The value being converted
20842 * @return {String} The comparison value
20844 asText : function(s){
20845 return String(s).replace(this.stripTagsRE, "");
20849 * Strips all HTML tags to sort on text only - Case insensitive
20850 * @param {Mixed} s The value being converted
20851 * @return {String} The comparison value
20853 asUCText : function(s){
20854 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20858 * Case insensitive string
20859 * @param {Mixed} s The value being converted
20860 * @return {String} The comparison value
20862 asUCString : function(s) {
20863 return String(s).toUpperCase();
20868 * @param {Mixed} s The value being converted
20869 * @return {Number} The comparison value
20871 asDate : function(s) {
20875 if(s instanceof Date){
20876 return s.getTime();
20878 return Date.parse(String(s));
20883 * @param {Mixed} s The value being converted
20884 * @return {Float} The comparison value
20886 asFloat : function(s) {
20887 var val = parseFloat(String(s).replace(/,/g, ""));
20888 if(isNaN(val)) val = 0;
20894 * @param {Mixed} s The value being converted
20895 * @return {Number} The comparison value
20897 asInt : function(s) {
20898 var val = parseInt(String(s).replace(/,/g, ""));
20899 if(isNaN(val)) val = 0;
20904 * Ext JS Library 1.1.1
20905 * Copyright(c) 2006-2007, Ext JS, LLC.
20907 * Originally Released Under LGPL - original licence link has changed is not relivant.
20910 * <script type="text/javascript">
20914 * @class Roo.data.Record
20915 * Instances of this class encapsulate both record <em>definition</em> information, and record
20916 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20917 * to access Records cached in an {@link Roo.data.Store} object.<br>
20919 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20920 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20923 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20925 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20926 * {@link #create}. The parameters are the same.
20927 * @param {Array} data An associative Array of data values keyed by the field name.
20928 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20929 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20930 * not specified an integer id is generated.
20932 Roo.data.Record = function(data, id){
20933 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20938 * Generate a constructor for a specific record layout.
20939 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20940 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20941 * Each field definition object may contain the following properties: <ul>
20942 * <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,
20943 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20944 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20945 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20946 * is being used, then this is a string containing the javascript expression to reference the data relative to
20947 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20948 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20949 * this may be omitted.</p></li>
20950 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20951 * <ul><li>auto (Default, implies no conversion)</li>
20956 * <li>date</li></ul></p></li>
20957 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20958 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20959 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20960 * by the Reader into an object that will be stored in the Record. It is passed the
20961 * following parameters:<ul>
20962 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20964 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20966 * <br>usage:<br><pre><code>
20967 var TopicRecord = Roo.data.Record.create(
20968 {name: 'title', mapping: 'topic_title'},
20969 {name: 'author', mapping: 'username'},
20970 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20971 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20972 {name: 'lastPoster', mapping: 'user2'},
20973 {name: 'excerpt', mapping: 'post_text'}
20976 var myNewRecord = new TopicRecord({
20977 title: 'Do my job please',
20980 lastPost: new Date(),
20981 lastPoster: 'Animal',
20982 excerpt: 'No way dude!'
20984 myStore.add(myNewRecord);
20989 Roo.data.Record.create = function(o){
20990 var f = function(){
20991 f.superclass.constructor.apply(this, arguments);
20993 Roo.extend(f, Roo.data.Record);
20994 var p = f.prototype;
20995 p.fields = new Roo.util.MixedCollection(false, function(field){
20998 for(var i = 0, len = o.length; i < len; i++){
20999 p.fields.add(new Roo.data.Field(o[i]));
21001 f.getField = function(name){
21002 return p.fields.get(name);
21007 Roo.data.Record.AUTO_ID = 1000;
21008 Roo.data.Record.EDIT = 'edit';
21009 Roo.data.Record.REJECT = 'reject';
21010 Roo.data.Record.COMMIT = 'commit';
21012 Roo.data.Record.prototype = {
21014 * Readonly flag - true if this record has been modified.
21023 join : function(store){
21024 this.store = store;
21028 * Set the named field to the specified value.
21029 * @param {String} name The name of the field to set.
21030 * @param {Object} value The value to set the field to.
21032 set : function(name, value){
21033 if(this.data[name] == value){
21037 if(!this.modified){
21038 this.modified = {};
21040 if(typeof this.modified[name] == 'undefined'){
21041 this.modified[name] = this.data[name];
21043 this.data[name] = value;
21044 if(!this.editing && this.store){
21045 this.store.afterEdit(this);
21050 * Get the value of the named field.
21051 * @param {String} name The name of the field to get the value of.
21052 * @return {Object} The value of the field.
21054 get : function(name){
21055 return this.data[name];
21059 beginEdit : function(){
21060 this.editing = true;
21061 this.modified = {};
21065 cancelEdit : function(){
21066 this.editing = false;
21067 delete this.modified;
21071 endEdit : function(){
21072 this.editing = false;
21073 if(this.dirty && this.store){
21074 this.store.afterEdit(this);
21079 * Usually called by the {@link Roo.data.Store} which owns the Record.
21080 * Rejects all changes made to the Record since either creation, or the last commit operation.
21081 * Modified fields are reverted to their original values.
21083 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21084 * of reject operations.
21086 reject : function(){
21087 var m = this.modified;
21089 if(typeof m[n] != "function"){
21090 this.data[n] = m[n];
21093 this.dirty = false;
21094 delete this.modified;
21095 this.editing = false;
21097 this.store.afterReject(this);
21102 * Usually called by the {@link Roo.data.Store} which owns the Record.
21103 * Commits all changes made to the Record since either creation, or the last commit operation.
21105 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21106 * of commit operations.
21108 commit : function(){
21109 this.dirty = false;
21110 delete this.modified;
21111 this.editing = false;
21113 this.store.afterCommit(this);
21118 hasError : function(){
21119 return this.error != null;
21123 clearError : function(){
21128 * Creates a copy of this record.
21129 * @param {String} id (optional) A new record id if you don't want to use this record's id
21132 copy : function(newId) {
21133 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21137 * Ext JS Library 1.1.1
21138 * Copyright(c) 2006-2007, Ext JS, LLC.
21140 * Originally Released Under LGPL - original licence link has changed is not relivant.
21143 * <script type="text/javascript">
21149 * @class Roo.data.Store
21150 * @extends Roo.util.Observable
21151 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21152 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21154 * 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
21155 * has no knowledge of the format of the data returned by the Proxy.<br>
21157 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21158 * instances from the data object. These records are cached and made available through accessor functions.
21160 * Creates a new Store.
21161 * @param {Object} config A config object containing the objects needed for the Store to access data,
21162 * and read the data into Records.
21164 Roo.data.Store = function(config){
21165 this.data = new Roo.util.MixedCollection(false);
21166 this.data.getKey = function(o){
21169 this.baseParams = {};
21171 this.paramNames = {
21176 "multisort" : "_multisort"
21179 if(config && config.data){
21180 this.inlineData = config.data;
21181 delete config.data;
21184 Roo.apply(this, config);
21186 if(this.reader){ // reader passed
21187 this.reader = Roo.factory(this.reader, Roo.data);
21188 this.reader.xmodule = this.xmodule || false;
21189 if(!this.recordType){
21190 this.recordType = this.reader.recordType;
21192 if(this.reader.onMetaChange){
21193 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21197 if(this.recordType){
21198 this.fields = this.recordType.prototype.fields;
21200 this.modified = [];
21204 * @event datachanged
21205 * Fires when the data cache has changed, and a widget which is using this Store
21206 * as a Record cache should refresh its view.
21207 * @param {Store} this
21209 datachanged : true,
21211 * @event metachange
21212 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21213 * @param {Store} this
21214 * @param {Object} meta The JSON metadata
21219 * Fires when Records have been added to the Store
21220 * @param {Store} this
21221 * @param {Roo.data.Record[]} records The array of Records added
21222 * @param {Number} index The index at which the record(s) were added
21227 * Fires when a Record has been removed from the Store
21228 * @param {Store} this
21229 * @param {Roo.data.Record} record The Record that was removed
21230 * @param {Number} index The index at which the record was removed
21235 * Fires when a Record has been updated
21236 * @param {Store} this
21237 * @param {Roo.data.Record} record The Record that was updated
21238 * @param {String} operation The update operation being performed. Value may be one of:
21240 Roo.data.Record.EDIT
21241 Roo.data.Record.REJECT
21242 Roo.data.Record.COMMIT
21248 * Fires when the data cache has been cleared.
21249 * @param {Store} this
21253 * @event beforeload
21254 * Fires before a request is made for a new data object. If the beforeload handler returns false
21255 * the load action will be canceled.
21256 * @param {Store} this
21257 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21261 * @event beforeloadadd
21262 * Fires after a new set of Records has been loaded.
21263 * @param {Store} this
21264 * @param {Roo.data.Record[]} records The Records that were loaded
21265 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21267 beforeloadadd : true,
21270 * Fires after a new set of Records has been loaded, before they are added to the store.
21271 * @param {Store} this
21272 * @param {Roo.data.Record[]} records The Records that were loaded
21273 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21274 * @params {Object} return from reader
21278 * @event loadexception
21279 * Fires if an exception occurs in the Proxy during loading.
21280 * Called with the signature of the Proxy's "loadexception" event.
21281 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21284 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21285 * @param {Object} load options
21286 * @param {Object} jsonData from your request (normally this contains the Exception)
21288 loadexception : true
21292 this.proxy = Roo.factory(this.proxy, Roo.data);
21293 this.proxy.xmodule = this.xmodule || false;
21294 this.relayEvents(this.proxy, ["loadexception"]);
21296 this.sortToggle = {};
21297 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21299 Roo.data.Store.superclass.constructor.call(this);
21301 if(this.inlineData){
21302 this.loadData(this.inlineData);
21303 delete this.inlineData;
21307 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21309 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21310 * without a remote query - used by combo/forms at present.
21314 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21317 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21320 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21321 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21324 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21325 * on any HTTP request
21328 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21331 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21335 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21336 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21338 remoteSort : false,
21341 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21342 * loaded or when a record is removed. (defaults to false).
21344 pruneModifiedRecords : false,
21347 lastOptions : null,
21350 * Add Records to the Store and fires the add event.
21351 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21353 add : function(records){
21354 records = [].concat(records);
21355 for(var i = 0, len = records.length; i < len; i++){
21356 records[i].join(this);
21358 var index = this.data.length;
21359 this.data.addAll(records);
21360 this.fireEvent("add", this, records, index);
21364 * Remove a Record from the Store and fires the remove event.
21365 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21367 remove : function(record){
21368 var index = this.data.indexOf(record);
21369 this.data.removeAt(index);
21370 if(this.pruneModifiedRecords){
21371 this.modified.remove(record);
21373 this.fireEvent("remove", this, record, index);
21377 * Remove all Records from the Store and fires the clear event.
21379 removeAll : function(){
21381 if(this.pruneModifiedRecords){
21382 this.modified = [];
21384 this.fireEvent("clear", this);
21388 * Inserts Records to the Store at the given index and fires the add event.
21389 * @param {Number} index The start index at which to insert the passed Records.
21390 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21392 insert : function(index, records){
21393 records = [].concat(records);
21394 for(var i = 0, len = records.length; i < len; i++){
21395 this.data.insert(index, records[i]);
21396 records[i].join(this);
21398 this.fireEvent("add", this, records, index);
21402 * Get the index within the cache of the passed Record.
21403 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21404 * @return {Number} The index of the passed Record. Returns -1 if not found.
21406 indexOf : function(record){
21407 return this.data.indexOf(record);
21411 * Get the index within the cache of the Record with the passed id.
21412 * @param {String} id The id of the Record to find.
21413 * @return {Number} The index of the Record. Returns -1 if not found.
21415 indexOfId : function(id){
21416 return this.data.indexOfKey(id);
21420 * Get the Record with the specified id.
21421 * @param {String} id The id of the Record to find.
21422 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21424 getById : function(id){
21425 return this.data.key(id);
21429 * Get the Record at the specified index.
21430 * @param {Number} index The index of the Record to find.
21431 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21433 getAt : function(index){
21434 return this.data.itemAt(index);
21438 * Returns a range of Records between specified indices.
21439 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21440 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21441 * @return {Roo.data.Record[]} An array of Records
21443 getRange : function(start, end){
21444 return this.data.getRange(start, end);
21448 storeOptions : function(o){
21449 o = Roo.apply({}, o);
21452 this.lastOptions = o;
21456 * Loads the Record cache from the configured Proxy using the configured Reader.
21458 * If using remote paging, then the first load call must specify the <em>start</em>
21459 * and <em>limit</em> properties in the options.params property to establish the initial
21460 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21462 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21463 * and this call will return before the new data has been loaded. Perform any post-processing
21464 * in a callback function, or in a "load" event handler.</strong>
21466 * @param {Object} options An object containing properties which control loading options:<ul>
21467 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21468 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21469 * passed the following arguments:<ul>
21470 * <li>r : Roo.data.Record[]</li>
21471 * <li>options: Options object from the load call</li>
21472 * <li>success: Boolean success indicator</li></ul></li>
21473 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21474 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21477 load : function(options){
21478 options = options || {};
21479 if(this.fireEvent("beforeload", this, options) !== false){
21480 this.storeOptions(options);
21481 var p = Roo.apply(options.params || {}, this.baseParams);
21482 // if meta was not loaded from remote source.. try requesting it.
21483 if (!this.reader.metaFromRemote) {
21484 p._requestMeta = 1;
21486 if(this.sortInfo && this.remoteSort){
21487 var pn = this.paramNames;
21488 p[pn["sort"]] = this.sortInfo.field;
21489 p[pn["dir"]] = this.sortInfo.direction;
21491 if (this.multiSort) {
21492 var pn = this.paramNames;
21493 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21496 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21501 * Reloads the Record cache from the configured Proxy using the configured Reader and
21502 * the options from the last load operation performed.
21503 * @param {Object} options (optional) An object containing properties which may override the options
21504 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21505 * the most recently used options are reused).
21507 reload : function(options){
21508 this.load(Roo.applyIf(options||{}, this.lastOptions));
21512 // Called as a callback by the Reader during a load operation.
21513 loadRecords : function(o, options, success){
21514 if(!o || success === false){
21515 if(success !== false){
21516 this.fireEvent("load", this, [], options, o);
21518 if(options.callback){
21519 options.callback.call(options.scope || this, [], options, false);
21523 // if data returned failure - throw an exception.
21524 if (o.success === false) {
21525 // show a message if no listener is registered.
21526 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21527 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21529 // loadmask wil be hooked into this..
21530 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21533 var r = o.records, t = o.totalRecords || r.length;
21535 this.fireEvent("beforeloadadd", this, r, options, o);
21537 if(!options || options.add !== true){
21538 if(this.pruneModifiedRecords){
21539 this.modified = [];
21541 for(var i = 0, len = r.length; i < len; i++){
21545 this.data = this.snapshot;
21546 delete this.snapshot;
21549 this.data.addAll(r);
21550 this.totalLength = t;
21552 this.fireEvent("datachanged", this);
21554 this.totalLength = Math.max(t, this.data.length+r.length);
21557 this.fireEvent("load", this, r, options, o);
21558 if(options.callback){
21559 options.callback.call(options.scope || this, r, options, true);
21565 * Loads data from a passed data block. A Reader which understands the format of the data
21566 * must have been configured in the constructor.
21567 * @param {Object} data The data block from which to read the Records. The format of the data expected
21568 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21569 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21571 loadData : function(o, append){
21572 var r = this.reader.readRecords(o);
21573 this.loadRecords(r, {add: append}, true);
21577 * Gets the number of cached records.
21579 * <em>If using paging, this may not be the total size of the dataset. If the data object
21580 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21581 * the data set size</em>
21583 getCount : function(){
21584 return this.data.length || 0;
21588 * Gets the total number of records in the dataset as returned by the server.
21590 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21591 * the dataset size</em>
21593 getTotalCount : function(){
21594 return this.totalLength || 0;
21598 * Returns the sort state of the Store as an object with two properties:
21600 field {String} The name of the field by which the Records are sorted
21601 direction {String} The sort order, "ASC" or "DESC"
21604 getSortState : function(){
21605 return this.sortInfo;
21609 applySort : function(){
21610 if(this.sortInfo && !this.remoteSort){
21611 var s = this.sortInfo, f = s.field;
21612 var st = this.fields.get(f).sortType;
21613 var fn = function(r1, r2){
21614 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21615 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21617 this.data.sort(s.direction, fn);
21618 if(this.snapshot && this.snapshot != this.data){
21619 this.snapshot.sort(s.direction, fn);
21625 * Sets the default sort column and order to be used by the next load operation.
21626 * @param {String} fieldName The name of the field to sort by.
21627 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21629 setDefaultSort : function(field, dir){
21630 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21634 * Sort the Records.
21635 * If remote sorting is used, the sort is performed on the server, and the cache is
21636 * reloaded. If local sorting is used, the cache is sorted internally.
21637 * @param {String} fieldName The name of the field to sort by.
21638 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21640 sort : function(fieldName, dir){
21641 var f = this.fields.get(fieldName);
21643 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21645 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21646 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21651 this.sortToggle[f.name] = dir;
21652 this.sortInfo = {field: f.name, direction: dir};
21653 if(!this.remoteSort){
21655 this.fireEvent("datachanged", this);
21657 this.load(this.lastOptions);
21662 * Calls the specified function for each of the Records in the cache.
21663 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21664 * Returning <em>false</em> aborts and exits the iteration.
21665 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21667 each : function(fn, scope){
21668 this.data.each(fn, scope);
21672 * Gets all records modified since the last commit. Modified records are persisted across load operations
21673 * (e.g., during paging).
21674 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21676 getModifiedRecords : function(){
21677 return this.modified;
21681 createFilterFn : function(property, value, anyMatch){
21682 if(!value.exec){ // not a regex
21683 value = String(value);
21684 if(value.length == 0){
21687 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21689 return function(r){
21690 return value.test(r.data[property]);
21695 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21696 * @param {String} property A field on your records
21697 * @param {Number} start The record index to start at (defaults to 0)
21698 * @param {Number} end The last record index to include (defaults to length - 1)
21699 * @return {Number} The sum
21701 sum : function(property, start, end){
21702 var rs = this.data.items, v = 0;
21703 start = start || 0;
21704 end = (end || end === 0) ? end : rs.length-1;
21706 for(var i = start; i <= end; i++){
21707 v += (rs[i].data[property] || 0);
21713 * Filter the records by a specified property.
21714 * @param {String} field A field on your records
21715 * @param {String/RegExp} value Either a string that the field
21716 * should start with or a RegExp to test against the field
21717 * @param {Boolean} anyMatch True to match any part not just the beginning
21719 filter : function(property, value, anyMatch){
21720 var fn = this.createFilterFn(property, value, anyMatch);
21721 return fn ? this.filterBy(fn) : this.clearFilter();
21725 * Filter by a function. The specified function will be called with each
21726 * record in this data source. If the function returns true the record is included,
21727 * otherwise it is filtered.
21728 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21729 * @param {Object} scope (optional) The scope of the function (defaults to this)
21731 filterBy : function(fn, scope){
21732 this.snapshot = this.snapshot || this.data;
21733 this.data = this.queryBy(fn, scope||this);
21734 this.fireEvent("datachanged", this);
21738 * Query the records by a specified property.
21739 * @param {String} field A field on your records
21740 * @param {String/RegExp} value Either a string that the field
21741 * should start with or a RegExp to test against the field
21742 * @param {Boolean} anyMatch True to match any part not just the beginning
21743 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21745 query : function(property, value, anyMatch){
21746 var fn = this.createFilterFn(property, value, anyMatch);
21747 return fn ? this.queryBy(fn) : this.data.clone();
21751 * Query by a function. The specified function will be called with each
21752 * record in this data source. If the function returns true the record is included
21754 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21755 * @param {Object} scope (optional) The scope of the function (defaults to this)
21756 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21758 queryBy : function(fn, scope){
21759 var data = this.snapshot || this.data;
21760 return data.filterBy(fn, scope||this);
21764 * Collects unique values for a particular dataIndex from this store.
21765 * @param {String} dataIndex The property to collect
21766 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21767 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21768 * @return {Array} An array of the unique values
21770 collect : function(dataIndex, allowNull, bypassFilter){
21771 var d = (bypassFilter === true && this.snapshot) ?
21772 this.snapshot.items : this.data.items;
21773 var v, sv, r = [], l = {};
21774 for(var i = 0, len = d.length; i < len; i++){
21775 v = d[i].data[dataIndex];
21777 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21786 * Revert to a view of the Record cache with no filtering applied.
21787 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21789 clearFilter : function(suppressEvent){
21790 if(this.snapshot && this.snapshot != this.data){
21791 this.data = this.snapshot;
21792 delete this.snapshot;
21793 if(suppressEvent !== true){
21794 this.fireEvent("datachanged", this);
21800 afterEdit : function(record){
21801 if(this.modified.indexOf(record) == -1){
21802 this.modified.push(record);
21804 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21808 afterReject : function(record){
21809 this.modified.remove(record);
21810 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21814 afterCommit : function(record){
21815 this.modified.remove(record);
21816 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21820 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21821 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21823 commitChanges : function(){
21824 var m = this.modified.slice(0);
21825 this.modified = [];
21826 for(var i = 0, len = m.length; i < len; i++){
21832 * Cancel outstanding changes on all changed records.
21834 rejectChanges : function(){
21835 var m = this.modified.slice(0);
21836 this.modified = [];
21837 for(var i = 0, len = m.length; i < len; i++){
21842 onMetaChange : function(meta, rtype, o){
21843 this.recordType = rtype;
21844 this.fields = rtype.prototype.fields;
21845 delete this.snapshot;
21846 this.sortInfo = meta.sortInfo || this.sortInfo;
21847 this.modified = [];
21848 this.fireEvent('metachange', this, this.reader.meta);
21851 moveIndex : function(data, type)
21853 var index = this.indexOf(data);
21855 var newIndex = index + type;
21859 this.insert(newIndex, data);
21864 * Ext JS Library 1.1.1
21865 * Copyright(c) 2006-2007, Ext JS, LLC.
21867 * Originally Released Under LGPL - original licence link has changed is not relivant.
21870 * <script type="text/javascript">
21874 * @class Roo.data.SimpleStore
21875 * @extends Roo.data.Store
21876 * Small helper class to make creating Stores from Array data easier.
21877 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21878 * @cfg {Array} fields An array of field definition objects, or field name strings.
21879 * @cfg {Array} data The multi-dimensional array of data
21881 * @param {Object} config
21883 Roo.data.SimpleStore = function(config){
21884 Roo.data.SimpleStore.superclass.constructor.call(this, {
21886 reader: new Roo.data.ArrayReader({
21889 Roo.data.Record.create(config.fields)
21891 proxy : new Roo.data.MemoryProxy(config.data)
21895 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21897 * Ext JS Library 1.1.1
21898 * Copyright(c) 2006-2007, Ext JS, LLC.
21900 * Originally Released Under LGPL - original licence link has changed is not relivant.
21903 * <script type="text/javascript">
21908 * @extends Roo.data.Store
21909 * @class Roo.data.JsonStore
21910 * Small helper class to make creating Stores for JSON data easier. <br/>
21912 var store = new Roo.data.JsonStore({
21913 url: 'get-images.php',
21915 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21918 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21919 * JsonReader and HttpProxy (unless inline data is provided).</b>
21920 * @cfg {Array} fields An array of field definition objects, or field name strings.
21922 * @param {Object} config
21924 Roo.data.JsonStore = function(c){
21925 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21926 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21927 reader: new Roo.data.JsonReader(c, c.fields)
21930 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21932 * Ext JS Library 1.1.1
21933 * Copyright(c) 2006-2007, Ext JS, LLC.
21935 * Originally Released Under LGPL - original licence link has changed is not relivant.
21938 * <script type="text/javascript">
21942 Roo.data.Field = function(config){
21943 if(typeof config == "string"){
21944 config = {name: config};
21946 Roo.apply(this, config);
21949 this.type = "auto";
21952 var st = Roo.data.SortTypes;
21953 // named sortTypes are supported, here we look them up
21954 if(typeof this.sortType == "string"){
21955 this.sortType = st[this.sortType];
21958 // set default sortType for strings and dates
21959 if(!this.sortType){
21962 this.sortType = st.asUCString;
21965 this.sortType = st.asDate;
21968 this.sortType = st.none;
21973 var stripRe = /[\$,%]/g;
21975 // prebuilt conversion function for this field, instead of
21976 // switching every time we're reading a value
21978 var cv, dateFormat = this.dateFormat;
21983 cv = function(v){ return v; };
21986 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21990 return v !== undefined && v !== null && v !== '' ?
21991 parseInt(String(v).replace(stripRe, ""), 10) : '';
21996 return v !== undefined && v !== null && v !== '' ?
21997 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22002 cv = function(v){ return v === true || v === "true" || v == 1; };
22009 if(v instanceof Date){
22013 if(dateFormat == "timestamp"){
22014 return new Date(v*1000);
22016 return Date.parseDate(v, dateFormat);
22018 var parsed = Date.parse(v);
22019 return parsed ? new Date(parsed) : null;
22028 Roo.data.Field.prototype = {
22036 * Ext JS Library 1.1.1
22037 * Copyright(c) 2006-2007, Ext JS, LLC.
22039 * Originally Released Under LGPL - original licence link has changed is not relivant.
22042 * <script type="text/javascript">
22045 // Base class for reading structured data from a data source. This class is intended to be
22046 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22049 * @class Roo.data.DataReader
22050 * Base class for reading structured data from a data source. This class is intended to be
22051 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22054 Roo.data.DataReader = function(meta, recordType){
22058 this.recordType = recordType instanceof Array ?
22059 Roo.data.Record.create(recordType) : recordType;
22062 Roo.data.DataReader.prototype = {
22064 * Create an empty record
22065 * @param {Object} data (optional) - overlay some values
22066 * @return {Roo.data.Record} record created.
22068 newRow : function(d) {
22070 this.recordType.prototype.fields.each(function(c) {
22072 case 'int' : da[c.name] = 0; break;
22073 case 'date' : da[c.name] = new Date(); break;
22074 case 'float' : da[c.name] = 0.0; break;
22075 case 'boolean' : da[c.name] = false; break;
22076 default : da[c.name] = ""; break;
22080 return new this.recordType(Roo.apply(da, d));
22085 * Ext JS Library 1.1.1
22086 * Copyright(c) 2006-2007, Ext JS, LLC.
22088 * Originally Released Under LGPL - original licence link has changed is not relivant.
22091 * <script type="text/javascript">
22095 * @class Roo.data.DataProxy
22096 * @extends Roo.data.Observable
22097 * This class is an abstract base class for implementations which provide retrieval of
22098 * unformatted data objects.<br>
22100 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22101 * (of the appropriate type which knows how to parse the data object) to provide a block of
22102 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22104 * Custom implementations must implement the load method as described in
22105 * {@link Roo.data.HttpProxy#load}.
22107 Roo.data.DataProxy = function(){
22110 * @event beforeload
22111 * Fires before a network request is made to retrieve a data object.
22112 * @param {Object} This DataProxy object.
22113 * @param {Object} params The params parameter to the load function.
22118 * Fires before the load method's callback is called.
22119 * @param {Object} This DataProxy object.
22120 * @param {Object} o The data object.
22121 * @param {Object} arg The callback argument object passed to the load function.
22125 * @event loadexception
22126 * Fires if an Exception occurs during data retrieval.
22127 * @param {Object} This DataProxy object.
22128 * @param {Object} o The data object.
22129 * @param {Object} arg The callback argument object passed to the load function.
22130 * @param {Object} e The Exception.
22132 loadexception : true
22134 Roo.data.DataProxy.superclass.constructor.call(this);
22137 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22140 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22144 * Ext JS Library 1.1.1
22145 * Copyright(c) 2006-2007, Ext JS, LLC.
22147 * Originally Released Under LGPL - original licence link has changed is not relivant.
22150 * <script type="text/javascript">
22153 * @class Roo.data.MemoryProxy
22154 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22155 * to the Reader when its load method is called.
22157 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22159 Roo.data.MemoryProxy = function(data){
22163 Roo.data.MemoryProxy.superclass.constructor.call(this);
22167 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22169 * Load data from the requested source (in this case an in-memory
22170 * data object passed to the constructor), read the data object into
22171 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22172 * process that block using the passed callback.
22173 * @param {Object} params This parameter is not used by the MemoryProxy class.
22174 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22175 * object into a block of Roo.data.Records.
22176 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22177 * The function must be passed <ul>
22178 * <li>The Record block object</li>
22179 * <li>The "arg" argument from the load function</li>
22180 * <li>A boolean success indicator</li>
22182 * @param {Object} scope The scope in which to call the callback
22183 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22185 load : function(params, reader, callback, scope, arg){
22186 params = params || {};
22189 result = reader.readRecords(this.data);
22191 this.fireEvent("loadexception", this, arg, null, e);
22192 callback.call(scope, null, arg, false);
22195 callback.call(scope, result, arg, true);
22199 update : function(params, records){
22204 * Ext JS Library 1.1.1
22205 * Copyright(c) 2006-2007, Ext JS, LLC.
22207 * Originally Released Under LGPL - original licence link has changed is not relivant.
22210 * <script type="text/javascript">
22213 * @class Roo.data.HttpProxy
22214 * @extends Roo.data.DataProxy
22215 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22216 * configured to reference a certain URL.<br><br>
22218 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22219 * from which the running page was served.<br><br>
22221 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22223 * Be aware that to enable the browser to parse an XML document, the server must set
22224 * the Content-Type header in the HTTP response to "text/xml".
22226 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22227 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22228 * will be used to make the request.
22230 Roo.data.HttpProxy = function(conn){
22231 Roo.data.HttpProxy.superclass.constructor.call(this);
22232 // is conn a conn config or a real conn?
22234 this.useAjax = !conn || !conn.events;
22238 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22239 // thse are take from connection...
22242 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22245 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22246 * extra parameters to each request made by this object. (defaults to undefined)
22249 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22250 * to each request made by this object. (defaults to undefined)
22253 * @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)
22256 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22259 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22265 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22269 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22270 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22271 * a finer-grained basis than the DataProxy events.
22273 getConnection : function(){
22274 return this.useAjax ? Roo.Ajax : this.conn;
22278 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22279 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22280 * process that block using the passed callback.
22281 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22282 * for the request to the remote server.
22283 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22284 * object into a block of Roo.data.Records.
22285 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22286 * The function must be passed <ul>
22287 * <li>The Record block object</li>
22288 * <li>The "arg" argument from the load function</li>
22289 * <li>A boolean success indicator</li>
22291 * @param {Object} scope The scope in which to call the callback
22292 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22294 load : function(params, reader, callback, scope, arg){
22295 if(this.fireEvent("beforeload", this, params) !== false){
22297 params : params || {},
22299 callback : callback,
22304 callback : this.loadResponse,
22308 Roo.applyIf(o, this.conn);
22309 if(this.activeRequest){
22310 Roo.Ajax.abort(this.activeRequest);
22312 this.activeRequest = Roo.Ajax.request(o);
22314 this.conn.request(o);
22317 callback.call(scope||this, null, arg, false);
22322 loadResponse : function(o, success, response){
22323 delete this.activeRequest;
22325 this.fireEvent("loadexception", this, o, response);
22326 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22331 result = o.reader.read(response);
22333 this.fireEvent("loadexception", this, o, response, e);
22334 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22338 this.fireEvent("load", this, o, o.request.arg);
22339 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22343 update : function(dataSet){
22348 updateResponse : function(dataSet){
22353 * Ext JS Library 1.1.1
22354 * Copyright(c) 2006-2007, Ext JS, LLC.
22356 * Originally Released Under LGPL - original licence link has changed is not relivant.
22359 * <script type="text/javascript">
22363 * @class Roo.data.ScriptTagProxy
22364 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22365 * other than the originating domain of the running page.<br><br>
22367 * <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
22368 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22370 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22371 * source code that is used as the source inside a <script> tag.<br><br>
22373 * In order for the browser to process the returned data, the server must wrap the data object
22374 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22375 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22376 * depending on whether the callback name was passed:
22379 boolean scriptTag = false;
22380 String cb = request.getParameter("callback");
22383 response.setContentType("text/javascript");
22385 response.setContentType("application/x-json");
22387 Writer out = response.getWriter();
22389 out.write(cb + "(");
22391 out.print(dataBlock.toJsonString());
22398 * @param {Object} config A configuration object.
22400 Roo.data.ScriptTagProxy = function(config){
22401 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22402 Roo.apply(this, config);
22403 this.head = document.getElementsByTagName("head")[0];
22406 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22408 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22410 * @cfg {String} url The URL from which to request the data object.
22413 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22417 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22418 * the server the name of the callback function set up by the load call to process the returned data object.
22419 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22420 * javascript output which calls this named function passing the data object as its only parameter.
22422 callbackParam : "callback",
22424 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22425 * name to the request.
22430 * Load data from the configured URL, read the data object into
22431 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22432 * process that block using the passed callback.
22433 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22434 * for the request to the remote server.
22435 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22436 * object into a block of Roo.data.Records.
22437 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22438 * The function must be passed <ul>
22439 * <li>The Record block object</li>
22440 * <li>The "arg" argument from the load function</li>
22441 * <li>A boolean success indicator</li>
22443 * @param {Object} scope The scope in which to call the callback
22444 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22446 load : function(params, reader, callback, scope, arg){
22447 if(this.fireEvent("beforeload", this, params) !== false){
22449 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22451 var url = this.url;
22452 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22454 url += "&_dc=" + (new Date().getTime());
22456 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22459 cb : "stcCallback"+transId,
22460 scriptId : "stcScript"+transId,
22464 callback : callback,
22470 window[trans.cb] = function(o){
22471 conn.handleResponse(o, trans);
22474 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22476 if(this.autoAbort !== false){
22480 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22482 var script = document.createElement("script");
22483 script.setAttribute("src", url);
22484 script.setAttribute("type", "text/javascript");
22485 script.setAttribute("id", trans.scriptId);
22486 this.head.appendChild(script);
22488 this.trans = trans;
22490 callback.call(scope||this, null, arg, false);
22495 isLoading : function(){
22496 return this.trans ? true : false;
22500 * Abort the current server request.
22502 abort : function(){
22503 if(this.isLoading()){
22504 this.destroyTrans(this.trans);
22509 destroyTrans : function(trans, isLoaded){
22510 this.head.removeChild(document.getElementById(trans.scriptId));
22511 clearTimeout(trans.timeoutId);
22513 window[trans.cb] = undefined;
22515 delete window[trans.cb];
22518 // if hasn't been loaded, wait for load to remove it to prevent script error
22519 window[trans.cb] = function(){
22520 window[trans.cb] = undefined;
22522 delete window[trans.cb];
22529 handleResponse : function(o, trans){
22530 this.trans = false;
22531 this.destroyTrans(trans, true);
22534 result = trans.reader.readRecords(o);
22536 this.fireEvent("loadexception", this, o, trans.arg, e);
22537 trans.callback.call(trans.scope||window, null, trans.arg, false);
22540 this.fireEvent("load", this, o, trans.arg);
22541 trans.callback.call(trans.scope||window, result, trans.arg, true);
22545 handleFailure : function(trans){
22546 this.trans = false;
22547 this.destroyTrans(trans, false);
22548 this.fireEvent("loadexception", this, null, trans.arg);
22549 trans.callback.call(trans.scope||window, null, trans.arg, false);
22553 * Ext JS Library 1.1.1
22554 * Copyright(c) 2006-2007, Ext JS, LLC.
22556 * Originally Released Under LGPL - original licence link has changed is not relivant.
22559 * <script type="text/javascript">
22563 * @class Roo.data.JsonReader
22564 * @extends Roo.data.DataReader
22565 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22566 * based on mappings in a provided Roo.data.Record constructor.
22568 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22569 * in the reply previously.
22574 var RecordDef = Roo.data.Record.create([
22575 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22576 {name: 'occupation'} // This field will use "occupation" as the mapping.
22578 var myReader = new Roo.data.JsonReader({
22579 totalProperty: "results", // The property which contains the total dataset size (optional)
22580 root: "rows", // The property which contains an Array of row objects
22581 id: "id" // The property within each row object that provides an ID for the record (optional)
22585 * This would consume a JSON file like this:
22587 { 'results': 2, 'rows': [
22588 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22589 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22592 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22593 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22594 * paged from the remote server.
22595 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22596 * @cfg {String} root name of the property which contains the Array of row objects.
22597 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22599 * Create a new JsonReader
22600 * @param {Object} meta Metadata configuration options
22601 * @param {Object} recordType Either an Array of field definition objects,
22602 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22604 Roo.data.JsonReader = function(meta, recordType){
22607 // set some defaults:
22608 Roo.applyIf(meta, {
22609 totalProperty: 'total',
22610 successProperty : 'success',
22615 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22617 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22620 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22621 * Used by Store query builder to append _requestMeta to params.
22624 metaFromRemote : false,
22626 * This method is only used by a DataProxy which has retrieved data from a remote server.
22627 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22628 * @return {Object} data A data block which is used by an Roo.data.Store object as
22629 * a cache of Roo.data.Records.
22631 read : function(response){
22632 var json = response.responseText;
22634 var o = /* eval:var:o */ eval("("+json+")");
22636 throw {message: "JsonReader.read: Json object not found"};
22642 this.metaFromRemote = true;
22643 this.meta = o.metaData;
22644 this.recordType = Roo.data.Record.create(o.metaData.fields);
22645 this.onMetaChange(this.meta, this.recordType, o);
22647 return this.readRecords(o);
22650 // private function a store will implement
22651 onMetaChange : function(meta, recordType, o){
22658 simpleAccess: function(obj, subsc) {
22665 getJsonAccessor: function(){
22667 return function(expr) {
22669 return(re.test(expr))
22670 ? new Function("obj", "return obj." + expr)
22675 return Roo.emptyFn;
22680 * Create a data block containing Roo.data.Records from an XML document.
22681 * @param {Object} o An object which contains an Array of row objects in the property specified
22682 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22683 * which contains the total size of the dataset.
22684 * @return {Object} data A data block which is used by an Roo.data.Store object as
22685 * a cache of Roo.data.Records.
22687 readRecords : function(o){
22689 * After any data loads, the raw JSON data is available for further custom processing.
22693 var s = this.meta, Record = this.recordType,
22694 f = Record.prototype.fields, fi = f.items, fl = f.length;
22696 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22698 if(s.totalProperty) {
22699 this.getTotal = this.getJsonAccessor(s.totalProperty);
22701 if(s.successProperty) {
22702 this.getSuccess = this.getJsonAccessor(s.successProperty);
22704 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22706 var g = this.getJsonAccessor(s.id);
22707 this.getId = function(rec) {
22709 return (r === undefined || r === "") ? null : r;
22712 this.getId = function(){return null;};
22715 for(var jj = 0; jj < fl; jj++){
22717 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22718 this.ef[jj] = this.getJsonAccessor(map);
22722 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22723 if(s.totalProperty){
22724 var vt = parseInt(this.getTotal(o), 10);
22729 if(s.successProperty){
22730 var vs = this.getSuccess(o);
22731 if(vs === false || vs === 'false'){
22736 for(var i = 0; i < c; i++){
22739 var id = this.getId(n);
22740 for(var j = 0; j < fl; j++){
22742 var v = this.ef[j](n);
22744 Roo.log('missing convert for ' + f.name);
22748 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22750 var record = new Record(values, id);
22752 records[i] = record;
22758 totalRecords : totalRecords
22763 * Ext JS Library 1.1.1
22764 * Copyright(c) 2006-2007, Ext JS, LLC.
22766 * Originally Released Under LGPL - original licence link has changed is not relivant.
22769 * <script type="text/javascript">
22773 * @class Roo.data.XmlReader
22774 * @extends Roo.data.DataReader
22775 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22776 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22778 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22779 * header in the HTTP response must be set to "text/xml".</em>
22783 var RecordDef = Roo.data.Record.create([
22784 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22785 {name: 'occupation'} // This field will use "occupation" as the mapping.
22787 var myReader = new Roo.data.XmlReader({
22788 totalRecords: "results", // The element which contains the total dataset size (optional)
22789 record: "row", // The repeated element which contains row information
22790 id: "id" // The element within the row that provides an ID for the record (optional)
22794 * This would consume an XML file like this:
22798 <results>2</results>
22801 <name>Bill</name>
22802 <occupation>Gardener</occupation>
22806 <name>Ben</name>
22807 <occupation>Horticulturalist</occupation>
22811 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22812 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22813 * paged from the remote server.
22814 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22815 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22816 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22817 * a record identifier value.
22819 * Create a new XmlReader
22820 * @param {Object} meta Metadata configuration options
22821 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22822 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22823 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22825 Roo.data.XmlReader = function(meta, recordType){
22827 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22829 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22831 * This method is only used by a DataProxy which has retrieved data from a remote server.
22832 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22833 * to contain a method called 'responseXML' that returns an XML document object.
22834 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22835 * a cache of Roo.data.Records.
22837 read : function(response){
22838 var doc = response.responseXML;
22840 throw {message: "XmlReader.read: XML Document not available"};
22842 return this.readRecords(doc);
22846 * Create a data block containing Roo.data.Records from an XML document.
22847 * @param {Object} doc A parsed XML document.
22848 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22849 * a cache of Roo.data.Records.
22851 readRecords : function(doc){
22853 * After any data loads/reads, the raw XML Document is available for further custom processing.
22854 * @type XMLDocument
22856 this.xmlData = doc;
22857 var root = doc.documentElement || doc;
22858 var q = Roo.DomQuery;
22859 var recordType = this.recordType, fields = recordType.prototype.fields;
22860 var sid = this.meta.id;
22861 var totalRecords = 0, success = true;
22862 if(this.meta.totalRecords){
22863 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22866 if(this.meta.success){
22867 var sv = q.selectValue(this.meta.success, root, true);
22868 success = sv !== false && sv !== 'false';
22871 var ns = q.select(this.meta.record, root);
22872 for(var i = 0, len = ns.length; i < len; i++) {
22875 var id = sid ? q.selectValue(sid, n) : undefined;
22876 for(var j = 0, jlen = fields.length; j < jlen; j++){
22877 var f = fields.items[j];
22878 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22880 values[f.name] = v;
22882 var record = new recordType(values, id);
22884 records[records.length] = record;
22890 totalRecords : totalRecords || records.length
22895 * Ext JS Library 1.1.1
22896 * Copyright(c) 2006-2007, Ext JS, LLC.
22898 * Originally Released Under LGPL - original licence link has changed is not relivant.
22901 * <script type="text/javascript">
22905 * @class Roo.data.ArrayReader
22906 * @extends Roo.data.DataReader
22907 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22908 * Each element of that Array represents a row of data fields. The
22909 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22910 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22914 var RecordDef = Roo.data.Record.create([
22915 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22916 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22918 var myReader = new Roo.data.ArrayReader({
22919 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22923 * This would consume an Array like this:
22925 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22927 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22929 * Create a new JsonReader
22930 * @param {Object} meta Metadata configuration options.
22931 * @param {Object} recordType Either an Array of field definition objects
22932 * as specified to {@link Roo.data.Record#create},
22933 * or an {@link Roo.data.Record} object
22934 * created using {@link Roo.data.Record#create}.
22936 Roo.data.ArrayReader = function(meta, recordType){
22937 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22940 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22942 * Create a data block containing Roo.data.Records from an XML document.
22943 * @param {Object} o An Array of row objects which represents the dataset.
22944 * @return {Object} data A data block which is used by an Roo.data.Store object as
22945 * a cache of Roo.data.Records.
22947 readRecords : function(o){
22948 var sid = this.meta ? this.meta.id : null;
22949 var recordType = this.recordType, fields = recordType.prototype.fields;
22952 for(var i = 0; i < root.length; i++){
22955 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22956 for(var j = 0, jlen = fields.length; j < jlen; j++){
22957 var f = fields.items[j];
22958 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22959 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22961 values[f.name] = v;
22963 var record = new recordType(values, id);
22965 records[records.length] = record;
22969 totalRecords : records.length
22974 * Ext JS Library 1.1.1
22975 * Copyright(c) 2006-2007, Ext JS, LLC.
22977 * Originally Released Under LGPL - original licence link has changed is not relivant.
22980 * <script type="text/javascript">
22985 * @class Roo.data.Tree
22986 * @extends Roo.util.Observable
22987 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22988 * in the tree have most standard DOM functionality.
22990 * @param {Node} root (optional) The root node
22992 Roo.data.Tree = function(root){
22993 this.nodeHash = {};
22995 * The root node for this tree
23000 this.setRootNode(root);
23005 * Fires when a new child node is appended to a node in this tree.
23006 * @param {Tree} tree The owner tree
23007 * @param {Node} parent The parent node
23008 * @param {Node} node The newly appended node
23009 * @param {Number} index The index of the newly appended node
23014 * Fires when a child node is removed from a node in this tree.
23015 * @param {Tree} tree The owner tree
23016 * @param {Node} parent The parent node
23017 * @param {Node} node The child node removed
23022 * Fires when a node is moved to a new location in the tree
23023 * @param {Tree} tree The owner tree
23024 * @param {Node} node The node moved
23025 * @param {Node} oldParent The old parent of this node
23026 * @param {Node} newParent The new parent of this node
23027 * @param {Number} index The index it was moved to
23032 * Fires when a new child node is inserted in a node in this tree.
23033 * @param {Tree} tree The owner tree
23034 * @param {Node} parent The parent node
23035 * @param {Node} node The child node inserted
23036 * @param {Node} refNode The child node the node was inserted before
23040 * @event beforeappend
23041 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23042 * @param {Tree} tree The owner tree
23043 * @param {Node} parent The parent node
23044 * @param {Node} node The child node to be appended
23046 "beforeappend" : true,
23048 * @event beforeremove
23049 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23050 * @param {Tree} tree The owner tree
23051 * @param {Node} parent The parent node
23052 * @param {Node} node The child node to be removed
23054 "beforeremove" : true,
23056 * @event beforemove
23057 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23058 * @param {Tree} tree The owner tree
23059 * @param {Node} node The node being moved
23060 * @param {Node} oldParent The parent of the node
23061 * @param {Node} newParent The new parent the node is moving to
23062 * @param {Number} index The index it is being moved to
23064 "beforemove" : true,
23066 * @event beforeinsert
23067 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23068 * @param {Tree} tree The owner tree
23069 * @param {Node} parent The parent node
23070 * @param {Node} node The child node to be inserted
23071 * @param {Node} refNode The child node the node is being inserted before
23073 "beforeinsert" : true
23076 Roo.data.Tree.superclass.constructor.call(this);
23079 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23080 pathSeparator: "/",
23082 proxyNodeEvent : function(){
23083 return this.fireEvent.apply(this, arguments);
23087 * Returns the root node for this tree.
23090 getRootNode : function(){
23095 * Sets the root node for this tree.
23096 * @param {Node} node
23099 setRootNode : function(node){
23101 node.ownerTree = this;
23102 node.isRoot = true;
23103 this.registerNode(node);
23108 * Gets a node in this tree by its id.
23109 * @param {String} id
23112 getNodeById : function(id){
23113 return this.nodeHash[id];
23116 registerNode : function(node){
23117 this.nodeHash[node.id] = node;
23120 unregisterNode : function(node){
23121 delete this.nodeHash[node.id];
23124 toString : function(){
23125 return "[Tree"+(this.id?" "+this.id:"")+"]";
23130 * @class Roo.data.Node
23131 * @extends Roo.util.Observable
23132 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23133 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23135 * @param {Object} attributes The attributes/config for the node
23137 Roo.data.Node = function(attributes){
23139 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23142 this.attributes = attributes || {};
23143 this.leaf = this.attributes.leaf;
23145 * The node id. @type String
23147 this.id = this.attributes.id;
23149 this.id = Roo.id(null, "ynode-");
23150 this.attributes.id = this.id;
23155 * All child nodes of this node. @type Array
23157 this.childNodes = [];
23158 if(!this.childNodes.indexOf){ // indexOf is a must
23159 this.childNodes.indexOf = function(o){
23160 for(var i = 0, len = this.length; i < len; i++){
23169 * The parent node for this node. @type Node
23171 this.parentNode = null;
23173 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23175 this.firstChild = null;
23177 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23179 this.lastChild = null;
23181 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23183 this.previousSibling = null;
23185 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23187 this.nextSibling = null;
23192 * Fires when a new child node is appended
23193 * @param {Tree} tree The owner tree
23194 * @param {Node} this This node
23195 * @param {Node} node The newly appended node
23196 * @param {Number} index The index of the newly appended node
23201 * Fires when a child node is removed
23202 * @param {Tree} tree The owner tree
23203 * @param {Node} this This node
23204 * @param {Node} node The removed node
23209 * Fires when this node is moved to a new location in the tree
23210 * @param {Tree} tree The owner tree
23211 * @param {Node} this This node
23212 * @param {Node} oldParent The old parent of this node
23213 * @param {Node} newParent The new parent of this node
23214 * @param {Number} index The index it was moved to
23219 * Fires when a new child node is inserted.
23220 * @param {Tree} tree The owner tree
23221 * @param {Node} this This node
23222 * @param {Node} node The child node inserted
23223 * @param {Node} refNode The child node the node was inserted before
23227 * @event beforeappend
23228 * Fires before a new child is appended, return false to cancel the append.
23229 * @param {Tree} tree The owner tree
23230 * @param {Node} this This node
23231 * @param {Node} node The child node to be appended
23233 "beforeappend" : true,
23235 * @event beforeremove
23236 * Fires before a child is removed, return false to cancel the remove.
23237 * @param {Tree} tree The owner tree
23238 * @param {Node} this This node
23239 * @param {Node} node The child node to be removed
23241 "beforeremove" : true,
23243 * @event beforemove
23244 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23245 * @param {Tree} tree The owner tree
23246 * @param {Node} this This node
23247 * @param {Node} oldParent The parent of this node
23248 * @param {Node} newParent The new parent this node is moving to
23249 * @param {Number} index The index it is being moved to
23251 "beforemove" : true,
23253 * @event beforeinsert
23254 * Fires before a new child is inserted, return false to cancel the insert.
23255 * @param {Tree} tree The owner tree
23256 * @param {Node} this This node
23257 * @param {Node} node The child node to be inserted
23258 * @param {Node} refNode The child node the node is being inserted before
23260 "beforeinsert" : true
23262 this.listeners = this.attributes.listeners;
23263 Roo.data.Node.superclass.constructor.call(this);
23266 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23267 fireEvent : function(evtName){
23268 // first do standard event for this node
23269 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23272 // then bubble it up to the tree if the event wasn't cancelled
23273 var ot = this.getOwnerTree();
23275 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23283 * Returns true if this node is a leaf
23284 * @return {Boolean}
23286 isLeaf : function(){
23287 return this.leaf === true;
23291 setFirstChild : function(node){
23292 this.firstChild = node;
23296 setLastChild : function(node){
23297 this.lastChild = node;
23302 * Returns true if this node is the last child of its parent
23303 * @return {Boolean}
23305 isLast : function(){
23306 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23310 * Returns true if this node is the first child of its parent
23311 * @return {Boolean}
23313 isFirst : function(){
23314 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23317 hasChildNodes : function(){
23318 return !this.isLeaf() && this.childNodes.length > 0;
23322 * Insert node(s) as the last child node of this node.
23323 * @param {Node/Array} node The node or Array of nodes to append
23324 * @return {Node} The appended node if single append, or null if an array was passed
23326 appendChild : function(node){
23328 if(node instanceof Array){
23330 }else if(arguments.length > 1){
23333 // if passed an array or multiple args do them one by one
23335 for(var i = 0, len = multi.length; i < len; i++) {
23336 this.appendChild(multi[i]);
23339 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23342 var index = this.childNodes.length;
23343 var oldParent = node.parentNode;
23344 // it's a move, make sure we move it cleanly
23346 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23349 oldParent.removeChild(node);
23351 index = this.childNodes.length;
23353 this.setFirstChild(node);
23355 this.childNodes.push(node);
23356 node.parentNode = this;
23357 var ps = this.childNodes[index-1];
23359 node.previousSibling = ps;
23360 ps.nextSibling = node;
23362 node.previousSibling = null;
23364 node.nextSibling = null;
23365 this.setLastChild(node);
23366 node.setOwnerTree(this.getOwnerTree());
23367 this.fireEvent("append", this.ownerTree, this, node, index);
23369 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23376 * Removes a child node from this node.
23377 * @param {Node} node The node to remove
23378 * @return {Node} The removed node
23380 removeChild : function(node){
23381 var index = this.childNodes.indexOf(node);
23385 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23389 // remove it from childNodes collection
23390 this.childNodes.splice(index, 1);
23393 if(node.previousSibling){
23394 node.previousSibling.nextSibling = node.nextSibling;
23396 if(node.nextSibling){
23397 node.nextSibling.previousSibling = node.previousSibling;
23400 // update child refs
23401 if(this.firstChild == node){
23402 this.setFirstChild(node.nextSibling);
23404 if(this.lastChild == node){
23405 this.setLastChild(node.previousSibling);
23408 node.setOwnerTree(null);
23409 // clear any references from the node
23410 node.parentNode = null;
23411 node.previousSibling = null;
23412 node.nextSibling = null;
23413 this.fireEvent("remove", this.ownerTree, this, node);
23418 * Inserts the first node before the second node in this nodes childNodes collection.
23419 * @param {Node} node The node to insert
23420 * @param {Node} refNode The node to insert before (if null the node is appended)
23421 * @return {Node} The inserted node
23423 insertBefore : function(node, refNode){
23424 if(!refNode){ // like standard Dom, refNode can be null for append
23425 return this.appendChild(node);
23428 if(node == refNode){
23432 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23435 var index = this.childNodes.indexOf(refNode);
23436 var oldParent = node.parentNode;
23437 var refIndex = index;
23439 // when moving internally, indexes will change after remove
23440 if(oldParent == this && this.childNodes.indexOf(node) < index){
23444 // it's a move, make sure we move it cleanly
23446 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23449 oldParent.removeChild(node);
23452 this.setFirstChild(node);
23454 this.childNodes.splice(refIndex, 0, node);
23455 node.parentNode = this;
23456 var ps = this.childNodes[refIndex-1];
23458 node.previousSibling = ps;
23459 ps.nextSibling = node;
23461 node.previousSibling = null;
23463 node.nextSibling = refNode;
23464 refNode.previousSibling = node;
23465 node.setOwnerTree(this.getOwnerTree());
23466 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23468 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23474 * Returns the child node at the specified index.
23475 * @param {Number} index
23478 item : function(index){
23479 return this.childNodes[index];
23483 * Replaces one child node in this node with another.
23484 * @param {Node} newChild The replacement node
23485 * @param {Node} oldChild The node to replace
23486 * @return {Node} The replaced node
23488 replaceChild : function(newChild, oldChild){
23489 this.insertBefore(newChild, oldChild);
23490 this.removeChild(oldChild);
23495 * Returns the index of a child node
23496 * @param {Node} node
23497 * @return {Number} The index of the node or -1 if it was not found
23499 indexOf : function(child){
23500 return this.childNodes.indexOf(child);
23504 * Returns the tree this node is in.
23507 getOwnerTree : function(){
23508 // if it doesn't have one, look for one
23509 if(!this.ownerTree){
23513 this.ownerTree = p.ownerTree;
23519 return this.ownerTree;
23523 * Returns depth of this node (the root node has a depth of 0)
23526 getDepth : function(){
23529 while(p.parentNode){
23537 setOwnerTree : function(tree){
23538 // if it's move, we need to update everyone
23539 if(tree != this.ownerTree){
23540 if(this.ownerTree){
23541 this.ownerTree.unregisterNode(this);
23543 this.ownerTree = tree;
23544 var cs = this.childNodes;
23545 for(var i = 0, len = cs.length; i < len; i++) {
23546 cs[i].setOwnerTree(tree);
23549 tree.registerNode(this);
23555 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23556 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23557 * @return {String} The path
23559 getPath : function(attr){
23560 attr = attr || "id";
23561 var p = this.parentNode;
23562 var b = [this.attributes[attr]];
23564 b.unshift(p.attributes[attr]);
23567 var sep = this.getOwnerTree().pathSeparator;
23568 return sep + b.join(sep);
23572 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23573 * function call will be the scope provided or the current node. The arguments to the function
23574 * will be the args provided or the current node. If the function returns false at any point,
23575 * the bubble is stopped.
23576 * @param {Function} fn The function to call
23577 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23578 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23580 bubble : function(fn, scope, args){
23583 if(fn.call(scope || p, args || p) === false){
23591 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23592 * function call will be the scope provided or the current node. The arguments to the function
23593 * will be the args provided or the current node. If the function returns false at any point,
23594 * the cascade is stopped on that branch.
23595 * @param {Function} fn The function to call
23596 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23597 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23599 cascade : function(fn, scope, args){
23600 if(fn.call(scope || this, args || this) !== false){
23601 var cs = this.childNodes;
23602 for(var i = 0, len = cs.length; i < len; i++) {
23603 cs[i].cascade(fn, scope, args);
23609 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23610 * function call will be the scope provided or the current node. The arguments to the function
23611 * will be the args provided or the current node. If the function returns false at any point,
23612 * the iteration stops.
23613 * @param {Function} fn The function to call
23614 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23615 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23617 eachChild : function(fn, scope, args){
23618 var cs = this.childNodes;
23619 for(var i = 0, len = cs.length; i < len; i++) {
23620 if(fn.call(scope || this, args || cs[i]) === false){
23627 * Finds the first child that has the attribute with the specified value.
23628 * @param {String} attribute The attribute name
23629 * @param {Mixed} value The value to search for
23630 * @return {Node} The found child or null if none was found
23632 findChild : function(attribute, value){
23633 var cs = this.childNodes;
23634 for(var i = 0, len = cs.length; i < len; i++) {
23635 if(cs[i].attributes[attribute] == value){
23643 * Finds the first child by a custom function. The child matches if the function passed
23645 * @param {Function} fn
23646 * @param {Object} scope (optional)
23647 * @return {Node} The found child or null if none was found
23649 findChildBy : function(fn, scope){
23650 var cs = this.childNodes;
23651 for(var i = 0, len = cs.length; i < len; i++) {
23652 if(fn.call(scope||cs[i], cs[i]) === true){
23660 * Sorts this nodes children using the supplied sort function
23661 * @param {Function} fn
23662 * @param {Object} scope (optional)
23664 sort : function(fn, scope){
23665 var cs = this.childNodes;
23666 var len = cs.length;
23668 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23670 for(var i = 0; i < len; i++){
23672 n.previousSibling = cs[i-1];
23673 n.nextSibling = cs[i+1];
23675 this.setFirstChild(n);
23678 this.setLastChild(n);
23685 * Returns true if this node is an ancestor (at any point) of the passed node.
23686 * @param {Node} node
23687 * @return {Boolean}
23689 contains : function(node){
23690 return node.isAncestor(this);
23694 * Returns true if the passed node is an ancestor (at any point) of this node.
23695 * @param {Node} node
23696 * @return {Boolean}
23698 isAncestor : function(node){
23699 var p = this.parentNode;
23709 toString : function(){
23710 return "[Node"+(this.id?" "+this.id:"")+"]";
23714 * Ext JS Library 1.1.1
23715 * Copyright(c) 2006-2007, Ext JS, LLC.
23717 * Originally Released Under LGPL - original licence link has changed is not relivant.
23720 * <script type="text/javascript">
23725 * @extends Roo.Element
23726 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23727 * automatic maintaining of shadow/shim positions.
23728 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23729 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23730 * you can pass a string with a CSS class name. False turns off the shadow.
23731 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23732 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23733 * @cfg {String} cls CSS class to add to the element
23734 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23735 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23737 * @param {Object} config An object with config options.
23738 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23741 Roo.Layer = function(config, existingEl){
23742 config = config || {};
23743 var dh = Roo.DomHelper;
23744 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23746 this.dom = Roo.getDom(existingEl);
23749 var o = config.dh || {tag: "div", cls: "x-layer"};
23750 this.dom = dh.append(pel, o);
23753 this.addClass(config.cls);
23755 this.constrain = config.constrain !== false;
23756 this.visibilityMode = Roo.Element.VISIBILITY;
23758 this.id = this.dom.id = config.id;
23760 this.id = Roo.id(this.dom);
23762 this.zindex = config.zindex || this.getZIndex();
23763 this.position("absolute", this.zindex);
23765 this.shadowOffset = config.shadowOffset || 4;
23766 this.shadow = new Roo.Shadow({
23767 offset : this.shadowOffset,
23768 mode : config.shadow
23771 this.shadowOffset = 0;
23773 this.useShim = config.shim !== false && Roo.useShims;
23774 this.useDisplay = config.useDisplay;
23778 var supr = Roo.Element.prototype;
23780 // shims are shared among layer to keep from having 100 iframes
23783 Roo.extend(Roo.Layer, Roo.Element, {
23785 getZIndex : function(){
23786 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23789 getShim : function(){
23796 var shim = shims.shift();
23798 shim = this.createShim();
23799 shim.enableDisplayMode('block');
23800 shim.dom.style.display = 'none';
23801 shim.dom.style.visibility = 'visible';
23803 var pn = this.dom.parentNode;
23804 if(shim.dom.parentNode != pn){
23805 pn.insertBefore(shim.dom, this.dom);
23807 shim.setStyle('z-index', this.getZIndex()-2);
23812 hideShim : function(){
23814 this.shim.setDisplayed(false);
23815 shims.push(this.shim);
23820 disableShadow : function(){
23822 this.shadowDisabled = true;
23823 this.shadow.hide();
23824 this.lastShadowOffset = this.shadowOffset;
23825 this.shadowOffset = 0;
23829 enableShadow : function(show){
23831 this.shadowDisabled = false;
23832 this.shadowOffset = this.lastShadowOffset;
23833 delete this.lastShadowOffset;
23841 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23842 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23843 sync : function(doShow){
23844 var sw = this.shadow;
23845 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23846 var sh = this.getShim();
23848 var w = this.getWidth(),
23849 h = this.getHeight();
23851 var l = this.getLeft(true),
23852 t = this.getTop(true);
23854 if(sw && !this.shadowDisabled){
23855 if(doShow && !sw.isVisible()){
23858 sw.realign(l, t, w, h);
23864 // fit the shim behind the shadow, so it is shimmed too
23865 var a = sw.adjusts, s = sh.dom.style;
23866 s.left = (Math.min(l, l+a.l))+"px";
23867 s.top = (Math.min(t, t+a.t))+"px";
23868 s.width = (w+a.w)+"px";
23869 s.height = (h+a.h)+"px";
23876 sh.setLeftTop(l, t);
23883 destroy : function(){
23886 this.shadow.hide();
23888 this.removeAllListeners();
23889 var pn = this.dom.parentNode;
23891 pn.removeChild(this.dom);
23893 Roo.Element.uncache(this.id);
23896 remove : function(){
23901 beginUpdate : function(){
23902 this.updating = true;
23906 endUpdate : function(){
23907 this.updating = false;
23912 hideUnders : function(negOffset){
23914 this.shadow.hide();
23920 constrainXY : function(){
23921 if(this.constrain){
23922 var vw = Roo.lib.Dom.getViewWidth(),
23923 vh = Roo.lib.Dom.getViewHeight();
23924 var s = Roo.get(document).getScroll();
23926 var xy = this.getXY();
23927 var x = xy[0], y = xy[1];
23928 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23929 // only move it if it needs it
23931 // first validate right/bottom
23932 if((x + w) > vw+s.left){
23933 x = vw - w - this.shadowOffset;
23936 if((y + h) > vh+s.top){
23937 y = vh - h - this.shadowOffset;
23940 // then make sure top/left isn't negative
23951 var ay = this.avoidY;
23952 if(y <= ay && (y+h) >= ay){
23958 supr.setXY.call(this, xy);
23964 isVisible : function(){
23965 return this.visible;
23969 showAction : function(){
23970 this.visible = true; // track visibility to prevent getStyle calls
23971 if(this.useDisplay === true){
23972 this.setDisplayed("");
23973 }else if(this.lastXY){
23974 supr.setXY.call(this, this.lastXY);
23975 }else if(this.lastLT){
23976 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23981 hideAction : function(){
23982 this.visible = false;
23983 if(this.useDisplay === true){
23984 this.setDisplayed(false);
23986 this.setLeftTop(-10000,-10000);
23990 // overridden Element method
23991 setVisible : function(v, a, d, c, e){
23996 var cb = function(){
24001 }.createDelegate(this);
24002 supr.setVisible.call(this, true, true, d, cb, e);
24005 this.hideUnders(true);
24014 }.createDelegate(this);
24016 supr.setVisible.call(this, v, a, d, cb, e);
24025 storeXY : function(xy){
24026 delete this.lastLT;
24030 storeLeftTop : function(left, top){
24031 delete this.lastXY;
24032 this.lastLT = [left, top];
24036 beforeFx : function(){
24037 this.beforeAction();
24038 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24042 afterFx : function(){
24043 Roo.Layer.superclass.afterFx.apply(this, arguments);
24044 this.sync(this.isVisible());
24048 beforeAction : function(){
24049 if(!this.updating && this.shadow){
24050 this.shadow.hide();
24054 // overridden Element method
24055 setLeft : function(left){
24056 this.storeLeftTop(left, this.getTop(true));
24057 supr.setLeft.apply(this, arguments);
24061 setTop : function(top){
24062 this.storeLeftTop(this.getLeft(true), top);
24063 supr.setTop.apply(this, arguments);
24067 setLeftTop : function(left, top){
24068 this.storeLeftTop(left, top);
24069 supr.setLeftTop.apply(this, arguments);
24073 setXY : function(xy, a, d, c, e){
24075 this.beforeAction();
24077 var cb = this.createCB(c);
24078 supr.setXY.call(this, xy, a, d, cb, e);
24085 createCB : function(c){
24096 // overridden Element method
24097 setX : function(x, a, d, c, e){
24098 this.setXY([x, this.getY()], a, d, c, e);
24101 // overridden Element method
24102 setY : function(y, a, d, c, e){
24103 this.setXY([this.getX(), y], a, d, c, e);
24106 // overridden Element method
24107 setSize : function(w, h, a, d, c, e){
24108 this.beforeAction();
24109 var cb = this.createCB(c);
24110 supr.setSize.call(this, w, h, a, d, cb, e);
24116 // overridden Element method
24117 setWidth : function(w, a, d, c, e){
24118 this.beforeAction();
24119 var cb = this.createCB(c);
24120 supr.setWidth.call(this, w, a, d, cb, e);
24126 // overridden Element method
24127 setHeight : function(h, a, d, c, e){
24128 this.beforeAction();
24129 var cb = this.createCB(c);
24130 supr.setHeight.call(this, h, a, d, cb, e);
24136 // overridden Element method
24137 setBounds : function(x, y, w, h, a, d, c, e){
24138 this.beforeAction();
24139 var cb = this.createCB(c);
24141 this.storeXY([x, y]);
24142 supr.setXY.call(this, [x, y]);
24143 supr.setSize.call(this, w, h, a, d, cb, e);
24146 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24152 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24153 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24154 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24155 * @param {Number} zindex The new z-index to set
24156 * @return {this} The Layer
24158 setZIndex : function(zindex){
24159 this.zindex = zindex;
24160 this.setStyle("z-index", zindex + 2);
24162 this.shadow.setZIndex(zindex + 1);
24165 this.shim.setStyle("z-index", zindex);
24171 * Ext JS Library 1.1.1
24172 * Copyright(c) 2006-2007, Ext JS, LLC.
24174 * Originally Released Under LGPL - original licence link has changed is not relivant.
24177 * <script type="text/javascript">
24182 * @class Roo.Shadow
24183 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24184 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24185 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24187 * Create a new Shadow
24188 * @param {Object} config The config object
24190 Roo.Shadow = function(config){
24191 Roo.apply(this, config);
24192 if(typeof this.mode != "string"){
24193 this.mode = this.defaultMode;
24195 var o = this.offset, a = {h: 0};
24196 var rad = Math.floor(this.offset/2);
24197 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24203 a.l -= this.offset + rad;
24204 a.t -= this.offset + rad;
24215 a.l -= (this.offset - rad);
24216 a.t -= this.offset + rad;
24218 a.w -= (this.offset - rad)*2;
24229 a.l -= (this.offset - rad);
24230 a.t -= (this.offset - rad);
24232 a.w -= (this.offset + rad + 1);
24233 a.h -= (this.offset + rad);
24242 Roo.Shadow.prototype = {
24244 * @cfg {String} mode
24245 * The shadow display mode. Supports the following options:<br />
24246 * sides: Shadow displays on both sides and bottom only<br />
24247 * frame: Shadow displays equally on all four sides<br />
24248 * drop: Traditional bottom-right drop shadow (default)
24251 * @cfg {String} offset
24252 * The number of pixels to offset the shadow from the element (defaults to 4)
24257 defaultMode: "drop",
24260 * Displays the shadow under the target element
24261 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24263 show : function(target){
24264 target = Roo.get(target);
24266 this.el = Roo.Shadow.Pool.pull();
24267 if(this.el.dom.nextSibling != target.dom){
24268 this.el.insertBefore(target);
24271 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24273 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24276 target.getLeft(true),
24277 target.getTop(true),
24281 this.el.dom.style.display = "block";
24285 * Returns true if the shadow is visible, else false
24287 isVisible : function(){
24288 return this.el ? true : false;
24292 * Direct alignment when values are already available. Show must be called at least once before
24293 * calling this method to ensure it is initialized.
24294 * @param {Number} left The target element left position
24295 * @param {Number} top The target element top position
24296 * @param {Number} width The target element width
24297 * @param {Number} height The target element height
24299 realign : function(l, t, w, h){
24303 var a = this.adjusts, d = this.el.dom, s = d.style;
24305 s.left = (l+a.l)+"px";
24306 s.top = (t+a.t)+"px";
24307 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24309 if(s.width != sws || s.height != shs){
24313 var cn = d.childNodes;
24314 var sww = Math.max(0, (sw-12))+"px";
24315 cn[0].childNodes[1].style.width = sww;
24316 cn[1].childNodes[1].style.width = sww;
24317 cn[2].childNodes[1].style.width = sww;
24318 cn[1].style.height = Math.max(0, (sh-12))+"px";
24324 * Hides this shadow
24328 this.el.dom.style.display = "none";
24329 Roo.Shadow.Pool.push(this.el);
24335 * Adjust the z-index of this shadow
24336 * @param {Number} zindex The new z-index
24338 setZIndex : function(z){
24341 this.el.setStyle("z-index", z);
24346 // Private utility class that manages the internal Shadow cache
24347 Roo.Shadow.Pool = function(){
24349 var markup = Roo.isIE ?
24350 '<div class="x-ie-shadow"></div>' :
24351 '<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>';
24354 var sh = p.shift();
24356 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24357 sh.autoBoxAdjust = false;
24362 push : function(sh){
24368 * Ext JS Library 1.1.1
24369 * Copyright(c) 2006-2007, Ext JS, LLC.
24371 * Originally Released Under LGPL - original licence link has changed is not relivant.
24374 * <script type="text/javascript">
24379 * @class Roo.SplitBar
24380 * @extends Roo.util.Observable
24381 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24385 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24386 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24387 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24388 split.minSize = 100;
24389 split.maxSize = 600;
24390 split.animate = true;
24391 split.on('moved', splitterMoved);
24394 * Create a new SplitBar
24395 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24396 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24397 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24398 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24399 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24400 position of the SplitBar).
24402 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24405 this.el = Roo.get(dragElement, true);
24406 this.el.dom.unselectable = "on";
24408 this.resizingEl = Roo.get(resizingElement, true);
24412 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24413 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24416 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24419 * The minimum size of the resizing element. (Defaults to 0)
24425 * The maximum size of the resizing element. (Defaults to 2000)
24428 this.maxSize = 2000;
24431 * Whether to animate the transition to the new size
24434 this.animate = false;
24437 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24440 this.useShim = false;
24445 if(!existingProxy){
24447 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24449 this.proxy = Roo.get(existingProxy).dom;
24452 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24455 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24458 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24461 this.dragSpecs = {};
24464 * @private The adapter to use to positon and resize elements
24466 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24467 this.adapter.init(this);
24469 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24471 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24472 this.el.addClass("x-splitbar-h");
24475 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24476 this.el.addClass("x-splitbar-v");
24482 * Fires when the splitter is moved (alias for {@link #event-moved})
24483 * @param {Roo.SplitBar} this
24484 * @param {Number} newSize the new width or height
24489 * Fires when the splitter is moved
24490 * @param {Roo.SplitBar} this
24491 * @param {Number} newSize the new width or height
24495 * @event beforeresize
24496 * Fires before the splitter is dragged
24497 * @param {Roo.SplitBar} this
24499 "beforeresize" : true,
24501 "beforeapply" : true
24504 Roo.util.Observable.call(this);
24507 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24508 onStartProxyDrag : function(x, y){
24509 this.fireEvent("beforeresize", this);
24511 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24513 o.enableDisplayMode("block");
24514 // all splitbars share the same overlay
24515 Roo.SplitBar.prototype.overlay = o;
24517 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24518 this.overlay.show();
24519 Roo.get(this.proxy).setDisplayed("block");
24520 var size = this.adapter.getElementSize(this);
24521 this.activeMinSize = this.getMinimumSize();;
24522 this.activeMaxSize = this.getMaximumSize();;
24523 var c1 = size - this.activeMinSize;
24524 var c2 = Math.max(this.activeMaxSize - size, 0);
24525 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24526 this.dd.resetConstraints();
24527 this.dd.setXConstraint(
24528 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24529 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24531 this.dd.setYConstraint(0, 0);
24533 this.dd.resetConstraints();
24534 this.dd.setXConstraint(0, 0);
24535 this.dd.setYConstraint(
24536 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24537 this.placement == Roo.SplitBar.TOP ? c2 : c1
24540 this.dragSpecs.startSize = size;
24541 this.dragSpecs.startPoint = [x, y];
24542 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24546 * @private Called after the drag operation by the DDProxy
24548 onEndProxyDrag : function(e){
24549 Roo.get(this.proxy).setDisplayed(false);
24550 var endPoint = Roo.lib.Event.getXY(e);
24552 this.overlay.hide();
24555 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24556 newSize = this.dragSpecs.startSize +
24557 (this.placement == Roo.SplitBar.LEFT ?
24558 endPoint[0] - this.dragSpecs.startPoint[0] :
24559 this.dragSpecs.startPoint[0] - endPoint[0]
24562 newSize = this.dragSpecs.startSize +
24563 (this.placement == Roo.SplitBar.TOP ?
24564 endPoint[1] - this.dragSpecs.startPoint[1] :
24565 this.dragSpecs.startPoint[1] - endPoint[1]
24568 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24569 if(newSize != this.dragSpecs.startSize){
24570 if(this.fireEvent('beforeapply', this, newSize) !== false){
24571 this.adapter.setElementSize(this, newSize);
24572 this.fireEvent("moved", this, newSize);
24573 this.fireEvent("resize", this, newSize);
24579 * Get the adapter this SplitBar uses
24580 * @return The adapter object
24582 getAdapter : function(){
24583 return this.adapter;
24587 * Set the adapter this SplitBar uses
24588 * @param {Object} adapter A SplitBar adapter object
24590 setAdapter : function(adapter){
24591 this.adapter = adapter;
24592 this.adapter.init(this);
24596 * Gets the minimum size for the resizing element
24597 * @return {Number} The minimum size
24599 getMinimumSize : function(){
24600 return this.minSize;
24604 * Sets the minimum size for the resizing element
24605 * @param {Number} minSize The minimum size
24607 setMinimumSize : function(minSize){
24608 this.minSize = minSize;
24612 * Gets the maximum size for the resizing element
24613 * @return {Number} The maximum size
24615 getMaximumSize : function(){
24616 return this.maxSize;
24620 * Sets the maximum size for the resizing element
24621 * @param {Number} maxSize The maximum size
24623 setMaximumSize : function(maxSize){
24624 this.maxSize = maxSize;
24628 * Sets the initialize size for the resizing element
24629 * @param {Number} size The initial size
24631 setCurrentSize : function(size){
24632 var oldAnimate = this.animate;
24633 this.animate = false;
24634 this.adapter.setElementSize(this, size);
24635 this.animate = oldAnimate;
24639 * Destroy this splitbar.
24640 * @param {Boolean} removeEl True to remove the element
24642 destroy : function(removeEl){
24644 this.shim.remove();
24647 this.proxy.parentNode.removeChild(this.proxy);
24655 * @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.
24657 Roo.SplitBar.createProxy = function(dir){
24658 var proxy = new Roo.Element(document.createElement("div"));
24659 proxy.unselectable();
24660 var cls = 'x-splitbar-proxy';
24661 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24662 document.body.appendChild(proxy.dom);
24667 * @class Roo.SplitBar.BasicLayoutAdapter
24668 * Default Adapter. It assumes the splitter and resizing element are not positioned
24669 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24671 Roo.SplitBar.BasicLayoutAdapter = function(){
24674 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24675 // do nothing for now
24676 init : function(s){
24680 * Called before drag operations to get the current size of the resizing element.
24681 * @param {Roo.SplitBar} s The SplitBar using this adapter
24683 getElementSize : function(s){
24684 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24685 return s.resizingEl.getWidth();
24687 return s.resizingEl.getHeight();
24692 * Called after drag operations to set the size of the resizing element.
24693 * @param {Roo.SplitBar} s The SplitBar using this adapter
24694 * @param {Number} newSize The new size to set
24695 * @param {Function} onComplete A function to be invoked when resizing is complete
24697 setElementSize : function(s, newSize, onComplete){
24698 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24700 s.resizingEl.setWidth(newSize);
24702 onComplete(s, newSize);
24705 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24710 s.resizingEl.setHeight(newSize);
24712 onComplete(s, newSize);
24715 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24722 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24723 * @extends Roo.SplitBar.BasicLayoutAdapter
24724 * Adapter that moves the splitter element to align with the resized sizing element.
24725 * Used with an absolute positioned SplitBar.
24726 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24727 * document.body, make sure you assign an id to the body element.
24729 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24730 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24731 this.container = Roo.get(container);
24734 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24735 init : function(s){
24736 this.basic.init(s);
24739 getElementSize : function(s){
24740 return this.basic.getElementSize(s);
24743 setElementSize : function(s, newSize, onComplete){
24744 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24747 moveSplitter : function(s){
24748 var yes = Roo.SplitBar;
24749 switch(s.placement){
24751 s.el.setX(s.resizingEl.getRight());
24754 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24757 s.el.setY(s.resizingEl.getBottom());
24760 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24767 * Orientation constant - Create a vertical SplitBar
24771 Roo.SplitBar.VERTICAL = 1;
24774 * Orientation constant - Create a horizontal SplitBar
24778 Roo.SplitBar.HORIZONTAL = 2;
24781 * Placement constant - The resizing element is to the left of the splitter element
24785 Roo.SplitBar.LEFT = 1;
24788 * Placement constant - The resizing element is to the right of the splitter element
24792 Roo.SplitBar.RIGHT = 2;
24795 * Placement constant - The resizing element is positioned above the splitter element
24799 Roo.SplitBar.TOP = 3;
24802 * Placement constant - The resizing element is positioned under splitter element
24806 Roo.SplitBar.BOTTOM = 4;
24809 * Ext JS Library 1.1.1
24810 * Copyright(c) 2006-2007, Ext JS, LLC.
24812 * Originally Released Under LGPL - original licence link has changed is not relivant.
24815 * <script type="text/javascript">
24820 * @extends Roo.util.Observable
24821 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24822 * This class also supports single and multi selection modes. <br>
24823 * Create a data model bound view:
24825 var store = new Roo.data.Store(...);
24827 var view = new Roo.View({
24829 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24831 singleSelect: true,
24832 selectedClass: "ydataview-selected",
24836 // listen for node click?
24837 view.on("click", function(vw, index, node, e){
24838 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24842 dataModel.load("foobar.xml");
24844 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24846 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24847 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24849 * Note: old style constructor is still suported (container, template, config)
24852 * Create a new View
24853 * @param {Object} config The config object
24856 Roo.View = function(config, depreciated_tpl, depreciated_config){
24858 this.parent = false;
24860 if (typeof(depreciated_tpl) == 'undefined') {
24861 // new way.. - universal constructor.
24862 Roo.apply(this, config);
24863 this.el = Roo.get(this.el);
24866 this.el = Roo.get(config);
24867 this.tpl = depreciated_tpl;
24868 Roo.apply(this, depreciated_config);
24870 this.wrapEl = this.el.wrap().wrap();
24871 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24874 if(typeof(this.tpl) == "string"){
24875 this.tpl = new Roo.Template(this.tpl);
24877 // support xtype ctors..
24878 this.tpl = new Roo.factory(this.tpl, Roo);
24882 this.tpl.compile();
24887 * @event beforeclick
24888 * Fires before a click is processed. Returns false to cancel the default action.
24889 * @param {Roo.View} this
24890 * @param {Number} index The index of the target node
24891 * @param {HTMLElement} node The target node
24892 * @param {Roo.EventObject} e The raw event object
24894 "beforeclick" : true,
24897 * Fires when a template node is clicked.
24898 * @param {Roo.View} this
24899 * @param {Number} index The index of the target node
24900 * @param {HTMLElement} node The target node
24901 * @param {Roo.EventObject} e The raw event object
24906 * Fires when a template node is double clicked.
24907 * @param {Roo.View} this
24908 * @param {Number} index The index of the target node
24909 * @param {HTMLElement} node The target node
24910 * @param {Roo.EventObject} e The raw event object
24914 * @event contextmenu
24915 * Fires when a template node is right clicked.
24916 * @param {Roo.View} this
24917 * @param {Number} index The index of the target node
24918 * @param {HTMLElement} node The target node
24919 * @param {Roo.EventObject} e The raw event object
24921 "contextmenu" : true,
24923 * @event selectionchange
24924 * Fires when the selected nodes change.
24925 * @param {Roo.View} this
24926 * @param {Array} selections Array of the selected nodes
24928 "selectionchange" : true,
24931 * @event beforeselect
24932 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24933 * @param {Roo.View} this
24934 * @param {HTMLElement} node The node to be selected
24935 * @param {Array} selections Array of currently selected nodes
24937 "beforeselect" : true,
24939 * @event preparedata
24940 * Fires on every row to render, to allow you to change the data.
24941 * @param {Roo.View} this
24942 * @param {Object} data to be rendered (change this)
24944 "preparedata" : true
24952 "click": this.onClick,
24953 "dblclick": this.onDblClick,
24954 "contextmenu": this.onContextMenu,
24958 this.selections = [];
24960 this.cmp = new Roo.CompositeElementLite([]);
24962 this.store = Roo.factory(this.store, Roo.data);
24963 this.setStore(this.store, true);
24966 if ( this.footer && this.footer.xtype) {
24968 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24970 this.footer.dataSource = this.store
24971 this.footer.container = fctr;
24972 this.footer = Roo.factory(this.footer, Roo);
24973 fctr.insertFirst(this.el);
24975 // this is a bit insane - as the paging toolbar seems to detach the el..
24976 // dom.parentNode.parentNode.parentNode
24977 // they get detached?
24981 Roo.View.superclass.constructor.call(this);
24986 Roo.extend(Roo.View, Roo.util.Observable, {
24989 * @cfg {Roo.data.Store} store Data store to load data from.
24994 * @cfg {String|Roo.Element} el The container element.
24999 * @cfg {String|Roo.Template} tpl The template used by this View
25003 * @cfg {String} dataName the named area of the template to use as the data area
25004 * Works with domtemplates roo-name="name"
25008 * @cfg {String} selectedClass The css class to add to selected nodes
25010 selectedClass : "x-view-selected",
25012 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25017 * @cfg {String} text to display on mask (default Loading)
25021 * @cfg {Boolean} multiSelect Allow multiple selection
25023 multiSelect : false,
25025 * @cfg {Boolean} singleSelect Allow single selection
25027 singleSelect: false,
25030 * @cfg {Boolean} toggleSelect - selecting
25032 toggleSelect : false,
25035 * @cfg {Boolean} tickable - selecting
25040 * Returns the element this view is bound to.
25041 * @return {Roo.Element}
25043 getEl : function(){
25044 return this.wrapEl;
25050 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25052 refresh : function(){
25053 Roo.log('refresh');
25056 // if we are using something like 'domtemplate', then
25057 // the what gets used is:
25058 // t.applySubtemplate(NAME, data, wrapping data..)
25059 // the outer template then get' applied with
25060 // the store 'extra data'
25061 // and the body get's added to the
25062 // roo-name="data" node?
25063 // <span class='roo-tpl-{name}'></span> ?????
25067 this.clearSelections();
25068 this.el.update("");
25070 var records = this.store.getRange();
25071 if(records.length < 1) {
25073 // is this valid?? = should it render a template??
25075 this.el.update(this.emptyText);
25079 if (this.dataName) {
25080 this.el.update(t.apply(this.store.meta)); //????
25081 el = this.el.child('.roo-tpl-' + this.dataName);
25084 for(var i = 0, len = records.length; i < len; i++){
25085 var data = this.prepareData(records[i].data, i, records[i]);
25086 this.fireEvent("preparedata", this, data, i, records[i]);
25088 var d = Roo.apply({}, data);
25091 Roo.apply(d, {'roo-id' : Roo.id()});
25095 Roo.each(this.parent.item, function(item){
25096 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25099 Roo.apply(d, {'roo-data-checked' : 'checked'});
25103 html[html.length] = Roo.util.Format.trim(
25105 t.applySubtemplate(this.dataName, d, this.store.meta) :
25112 el.update(html.join(""));
25113 this.nodes = el.dom.childNodes;
25114 this.updateIndexes(0);
25119 * Function to override to reformat the data that is sent to
25120 * the template for each node.
25121 * DEPRICATED - use the preparedata event handler.
25122 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25123 * a JSON object for an UpdateManager bound view).
25125 prepareData : function(data, index, record)
25127 this.fireEvent("preparedata", this, data, index, record);
25131 onUpdate : function(ds, record){
25132 Roo.log('on update');
25133 this.clearSelections();
25134 var index = this.store.indexOf(record);
25135 var n = this.nodes[index];
25136 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25137 n.parentNode.removeChild(n);
25138 this.updateIndexes(index, index);
25144 onAdd : function(ds, records, index)
25146 Roo.log(['on Add', ds, records, index] );
25147 this.clearSelections();
25148 if(this.nodes.length == 0){
25152 var n = this.nodes[index];
25153 for(var i = 0, len = records.length; i < len; i++){
25154 var d = this.prepareData(records[i].data, i, records[i]);
25156 this.tpl.insertBefore(n, d);
25159 this.tpl.append(this.el, d);
25162 this.updateIndexes(index);
25165 onRemove : function(ds, record, index){
25166 Roo.log('onRemove');
25167 this.clearSelections();
25168 var el = this.dataName ?
25169 this.el.child('.roo-tpl-' + this.dataName) :
25172 el.dom.removeChild(this.nodes[index]);
25173 this.updateIndexes(index);
25177 * Refresh an individual node.
25178 * @param {Number} index
25180 refreshNode : function(index){
25181 this.onUpdate(this.store, this.store.getAt(index));
25184 updateIndexes : function(startIndex, endIndex){
25185 var ns = this.nodes;
25186 startIndex = startIndex || 0;
25187 endIndex = endIndex || ns.length - 1;
25188 for(var i = startIndex; i <= endIndex; i++){
25189 ns[i].nodeIndex = i;
25194 * Changes the data store this view uses and refresh the view.
25195 * @param {Store} store
25197 setStore : function(store, initial){
25198 if(!initial && this.store){
25199 this.store.un("datachanged", this.refresh);
25200 this.store.un("add", this.onAdd);
25201 this.store.un("remove", this.onRemove);
25202 this.store.un("update", this.onUpdate);
25203 this.store.un("clear", this.refresh);
25204 this.store.un("beforeload", this.onBeforeLoad);
25205 this.store.un("load", this.onLoad);
25206 this.store.un("loadexception", this.onLoad);
25210 store.on("datachanged", this.refresh, this);
25211 store.on("add", this.onAdd, this);
25212 store.on("remove", this.onRemove, this);
25213 store.on("update", this.onUpdate, this);
25214 store.on("clear", this.refresh, this);
25215 store.on("beforeload", this.onBeforeLoad, this);
25216 store.on("load", this.onLoad, this);
25217 store.on("loadexception", this.onLoad, this);
25225 * onbeforeLoad - masks the loading area.
25228 onBeforeLoad : function(store,opts)
25230 Roo.log('onBeforeLoad');
25232 this.el.update("");
25234 this.el.mask(this.mask ? this.mask : "Loading" );
25236 onLoad : function ()
25243 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25244 * @param {HTMLElement} node
25245 * @return {HTMLElement} The template node
25247 findItemFromChild : function(node){
25248 var el = this.dataName ?
25249 this.el.child('.roo-tpl-' + this.dataName,true) :
25252 if(!node || node.parentNode == el){
25255 var p = node.parentNode;
25256 while(p && p != el){
25257 if(p.parentNode == el){
25266 onClick : function(e){
25267 var item = this.findItemFromChild(e.getTarget());
25269 var index = this.indexOf(item);
25270 if(this.onItemClick(item, index, e) !== false){
25271 this.fireEvent("click", this, index, item, e);
25274 this.clearSelections();
25279 onContextMenu : function(e){
25280 var item = this.findItemFromChild(e.getTarget());
25282 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25287 onDblClick : function(e){
25288 var item = this.findItemFromChild(e.getTarget());
25290 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25294 onItemClick : function(item, index, e)
25296 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25299 if (this.toggleSelect) {
25300 var m = this.isSelected(item) ? 'unselect' : 'select';
25303 _t[m](item, true, false);
25306 if(this.multiSelect || this.singleSelect){
25307 if(this.multiSelect && e.shiftKey && this.lastSelection){
25308 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25310 this.select(item, this.multiSelect && e.ctrlKey);
25311 this.lastSelection = item;
25314 if(!this.tickable){
25315 e.preventDefault();
25323 * Get the number of selected nodes.
25326 getSelectionCount : function(){
25327 return this.selections.length;
25331 * Get the currently selected nodes.
25332 * @return {Array} An array of HTMLElements
25334 getSelectedNodes : function(){
25335 return this.selections;
25339 * Get the indexes of the selected nodes.
25342 getSelectedIndexes : function(){
25343 var indexes = [], s = this.selections;
25344 for(var i = 0, len = s.length; i < len; i++){
25345 indexes.push(s[i].nodeIndex);
25351 * Clear all selections
25352 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25354 clearSelections : function(suppressEvent){
25355 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25356 this.cmp.elements = this.selections;
25357 this.cmp.removeClass(this.selectedClass);
25358 this.selections = [];
25359 if(!suppressEvent){
25360 this.fireEvent("selectionchange", this, this.selections);
25366 * Returns true if the passed node is selected
25367 * @param {HTMLElement/Number} node The node or node index
25368 * @return {Boolean}
25370 isSelected : function(node){
25371 var s = this.selections;
25375 node = this.getNode(node);
25376 return s.indexOf(node) !== -1;
25381 * @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
25382 * @param {Boolean} keepExisting (optional) true to keep existing selections
25383 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25385 select : function(nodeInfo, keepExisting, suppressEvent){
25386 if(nodeInfo instanceof Array){
25388 this.clearSelections(true);
25390 for(var i = 0, len = nodeInfo.length; i < len; i++){
25391 this.select(nodeInfo[i], true, true);
25395 var node = this.getNode(nodeInfo);
25396 if(!node || this.isSelected(node)){
25397 return; // already selected.
25400 this.clearSelections(true);
25402 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25403 Roo.fly(node).addClass(this.selectedClass);
25404 this.selections.push(node);
25405 if(!suppressEvent){
25406 this.fireEvent("selectionchange", this, this.selections);
25414 * @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
25415 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25416 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25418 unselect : function(nodeInfo, keepExisting, suppressEvent)
25420 if(nodeInfo instanceof Array){
25421 Roo.each(this.selections, function(s) {
25422 this.unselect(s, nodeInfo);
25426 var node = this.getNode(nodeInfo);
25427 if(!node || !this.isSelected(node)){
25428 Roo.log("not selected");
25429 return; // not selected.
25433 Roo.each(this.selections, function(s) {
25435 Roo.fly(node).removeClass(this.selectedClass);
25442 this.selections= ns;
25443 this.fireEvent("selectionchange", this, this.selections);
25447 * Gets a template node.
25448 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25449 * @return {HTMLElement} The node or null if it wasn't found
25451 getNode : function(nodeInfo){
25452 if(typeof nodeInfo == "string"){
25453 return document.getElementById(nodeInfo);
25454 }else if(typeof nodeInfo == "number"){
25455 return this.nodes[nodeInfo];
25461 * Gets a range template nodes.
25462 * @param {Number} startIndex
25463 * @param {Number} endIndex
25464 * @return {Array} An array of nodes
25466 getNodes : function(start, end){
25467 var ns = this.nodes;
25468 start = start || 0;
25469 end = typeof end == "undefined" ? ns.length - 1 : end;
25472 for(var i = start; i <= end; i++){
25476 for(var i = start; i >= end; i--){
25484 * Finds the index of the passed node
25485 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25486 * @return {Number} The index of the node or -1
25488 indexOf : function(node){
25489 node = this.getNode(node);
25490 if(typeof node.nodeIndex == "number"){
25491 return node.nodeIndex;
25493 var ns = this.nodes;
25494 for(var i = 0, len = ns.length; i < len; i++){
25504 * Ext JS Library 1.1.1
25505 * Copyright(c) 2006-2007, Ext JS, LLC.
25507 * Originally Released Under LGPL - original licence link has changed is not relivant.
25510 * <script type="text/javascript">
25514 * @class Roo.JsonView
25515 * @extends Roo.View
25516 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25518 var view = new Roo.JsonView({
25519 container: "my-element",
25520 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25525 // listen for node click?
25526 view.on("click", function(vw, index, node, e){
25527 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25530 // direct load of JSON data
25531 view.load("foobar.php");
25533 // Example from my blog list
25534 var tpl = new Roo.Template(
25535 '<div class="entry">' +
25536 '<a class="entry-title" href="{link}">{title}</a>' +
25537 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25538 "</div><hr />"
25541 var moreView = new Roo.JsonView({
25542 container : "entry-list",
25546 moreView.on("beforerender", this.sortEntries, this);
25548 url: "/blog/get-posts.php",
25549 params: "allposts=true",
25550 text: "Loading Blog Entries..."
25554 * Note: old code is supported with arguments : (container, template, config)
25558 * Create a new JsonView
25560 * @param {Object} config The config object
25563 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25566 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25568 var um = this.el.getUpdateManager();
25569 um.setRenderer(this);
25570 um.on("update", this.onLoad, this);
25571 um.on("failure", this.onLoadException, this);
25574 * @event beforerender
25575 * Fires before rendering of the downloaded JSON data.
25576 * @param {Roo.JsonView} this
25577 * @param {Object} data The JSON data loaded
25581 * Fires when data is loaded.
25582 * @param {Roo.JsonView} this
25583 * @param {Object} data The JSON data loaded
25584 * @param {Object} response The raw Connect response object
25587 * @event loadexception
25588 * Fires when loading fails.
25589 * @param {Roo.JsonView} this
25590 * @param {Object} response The raw Connect response object
25593 'beforerender' : true,
25595 'loadexception' : true
25598 Roo.extend(Roo.JsonView, Roo.View, {
25600 * @type {String} The root property in the loaded JSON object that contains the data
25605 * Refreshes the view.
25607 refresh : function(){
25608 this.clearSelections();
25609 this.el.update("");
25611 var o = this.jsonData;
25612 if(o && o.length > 0){
25613 for(var i = 0, len = o.length; i < len; i++){
25614 var data = this.prepareData(o[i], i, o);
25615 html[html.length] = this.tpl.apply(data);
25618 html.push(this.emptyText);
25620 this.el.update(html.join(""));
25621 this.nodes = this.el.dom.childNodes;
25622 this.updateIndexes(0);
25626 * 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.
25627 * @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:
25630 url: "your-url.php",
25631 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25632 callback: yourFunction,
25633 scope: yourObject, //(optional scope)
25636 text: "Loading...",
25641 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25642 * 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.
25643 * @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}
25644 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25645 * @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.
25648 var um = this.el.getUpdateManager();
25649 um.update.apply(um, arguments);
25652 render : function(el, response){
25653 this.clearSelections();
25654 this.el.update("");
25657 o = Roo.util.JSON.decode(response.responseText);
25660 o = o[this.jsonRoot];
25665 * The current JSON data or null
25668 this.beforeRender();
25673 * Get the number of records in the current JSON dataset
25676 getCount : function(){
25677 return this.jsonData ? this.jsonData.length : 0;
25681 * Returns the JSON object for the specified node(s)
25682 * @param {HTMLElement/Array} node The node or an array of nodes
25683 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25684 * you get the JSON object for the node
25686 getNodeData : function(node){
25687 if(node instanceof Array){
25689 for(var i = 0, len = node.length; i < len; i++){
25690 data.push(this.getNodeData(node[i]));
25694 return this.jsonData[this.indexOf(node)] || null;
25697 beforeRender : function(){
25698 this.snapshot = this.jsonData;
25700 this.sort.apply(this, this.sortInfo);
25702 this.fireEvent("beforerender", this, this.jsonData);
25705 onLoad : function(el, o){
25706 this.fireEvent("load", this, this.jsonData, o);
25709 onLoadException : function(el, o){
25710 this.fireEvent("loadexception", this, o);
25714 * Filter the data by a specific property.
25715 * @param {String} property A property on your JSON objects
25716 * @param {String/RegExp} value Either string that the property values
25717 * should start with, or a RegExp to test against the property
25719 filter : function(property, value){
25722 var ss = this.snapshot;
25723 if(typeof value == "string"){
25724 var vlen = value.length;
25726 this.clearFilter();
25729 value = value.toLowerCase();
25730 for(var i = 0, len = ss.length; i < len; i++){
25732 if(o[property].substr(0, vlen).toLowerCase() == value){
25736 } else if(value.exec){ // regex?
25737 for(var i = 0, len = ss.length; i < len; i++){
25739 if(value.test(o[property])){
25746 this.jsonData = data;
25752 * Filter by a function. The passed function will be called with each
25753 * object in the current dataset. If the function returns true the value is kept,
25754 * otherwise it is filtered.
25755 * @param {Function} fn
25756 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25758 filterBy : function(fn, scope){
25761 var ss = this.snapshot;
25762 for(var i = 0, len = ss.length; i < len; i++){
25764 if(fn.call(scope || this, o)){
25768 this.jsonData = data;
25774 * Clears the current filter.
25776 clearFilter : function(){
25777 if(this.snapshot && this.jsonData != this.snapshot){
25778 this.jsonData = this.snapshot;
25785 * Sorts the data for this view and refreshes it.
25786 * @param {String} property A property on your JSON objects to sort on
25787 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25788 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25790 sort : function(property, dir, sortType){
25791 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25794 var dsc = dir && dir.toLowerCase() == "desc";
25795 var f = function(o1, o2){
25796 var v1 = sortType ? sortType(o1[p]) : o1[p];
25797 var v2 = sortType ? sortType(o2[p]) : o2[p];
25800 return dsc ? +1 : -1;
25801 } else if(v1 > v2){
25802 return dsc ? -1 : +1;
25807 this.jsonData.sort(f);
25809 if(this.jsonData != this.snapshot){
25810 this.snapshot.sort(f);
25816 * Ext JS Library 1.1.1
25817 * Copyright(c) 2006-2007, Ext JS, LLC.
25819 * Originally Released Under LGPL - original licence link has changed is not relivant.
25822 * <script type="text/javascript">
25827 * @class Roo.ColorPalette
25828 * @extends Roo.Component
25829 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25830 * Here's an example of typical usage:
25832 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25833 cp.render('my-div');
25835 cp.on('select', function(palette, selColor){
25836 // do something with selColor
25840 * Create a new ColorPalette
25841 * @param {Object} config The config object
25843 Roo.ColorPalette = function(config){
25844 Roo.ColorPalette.superclass.constructor.call(this, config);
25848 * Fires when a color is selected
25849 * @param {ColorPalette} this
25850 * @param {String} color The 6-digit color hex code (without the # symbol)
25856 this.on("select", this.handler, this.scope, true);
25859 Roo.extend(Roo.ColorPalette, Roo.Component, {
25861 * @cfg {String} itemCls
25862 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25864 itemCls : "x-color-palette",
25866 * @cfg {String} value
25867 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25868 * the hex codes are case-sensitive.
25871 clickEvent:'click',
25873 ctype: "Roo.ColorPalette",
25876 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25878 allowReselect : false,
25881 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25882 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25883 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25884 * of colors with the width setting until the box is symmetrical.</p>
25885 * <p>You can override individual colors if needed:</p>
25887 var cp = new Roo.ColorPalette();
25888 cp.colors[0] = "FF0000"; // change the first box to red
25891 Or you can provide a custom array of your own for complete control:
25893 var cp = new Roo.ColorPalette();
25894 cp.colors = ["000000", "993300", "333300"];
25899 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25900 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25901 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25902 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25903 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25907 onRender : function(container, position){
25908 var t = new Roo.MasterTemplate(
25909 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25911 var c = this.colors;
25912 for(var i = 0, len = c.length; i < len; i++){
25915 var el = document.createElement("div");
25916 el.className = this.itemCls;
25918 container.dom.insertBefore(el, position);
25919 this.el = Roo.get(el);
25920 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25921 if(this.clickEvent != 'click'){
25922 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25927 afterRender : function(){
25928 Roo.ColorPalette.superclass.afterRender.call(this);
25930 var s = this.value;
25937 handleClick : function(e, t){
25938 e.preventDefault();
25939 if(!this.disabled){
25940 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25941 this.select(c.toUpperCase());
25946 * Selects the specified color in the palette (fires the select event)
25947 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25949 select : function(color){
25950 color = color.replace("#", "");
25951 if(color != this.value || this.allowReselect){
25954 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25956 el.child("a.color-"+color).addClass("x-color-palette-sel");
25957 this.value = color;
25958 this.fireEvent("select", this, color);
25963 * Ext JS Library 1.1.1
25964 * Copyright(c) 2006-2007, Ext JS, LLC.
25966 * Originally Released Under LGPL - original licence link has changed is not relivant.
25969 * <script type="text/javascript">
25973 * @class Roo.DatePicker
25974 * @extends Roo.Component
25975 * Simple date picker class.
25977 * Create a new DatePicker
25978 * @param {Object} config The config object
25980 Roo.DatePicker = function(config){
25981 Roo.DatePicker.superclass.constructor.call(this, config);
25983 this.value = config && config.value ?
25984 config.value.clearTime() : new Date().clearTime();
25989 * Fires when a date is selected
25990 * @param {DatePicker} this
25991 * @param {Date} date The selected date
25995 * @event monthchange
25996 * Fires when the displayed month changes
25997 * @param {DatePicker} this
25998 * @param {Date} date The selected month
26000 'monthchange': true
26004 this.on("select", this.handler, this.scope || this);
26006 // build the disabledDatesRE
26007 if(!this.disabledDatesRE && this.disabledDates){
26008 var dd = this.disabledDates;
26010 for(var i = 0; i < dd.length; i++){
26012 if(i != dd.length-1) re += "|";
26014 this.disabledDatesRE = new RegExp(re + ")");
26018 Roo.extend(Roo.DatePicker, Roo.Component, {
26020 * @cfg {String} todayText
26021 * The text to display on the button that selects the current date (defaults to "Today")
26023 todayText : "Today",
26025 * @cfg {String} okText
26026 * The text to display on the ok button
26028 okText : " OK ", //   to give the user extra clicking room
26030 * @cfg {String} cancelText
26031 * The text to display on the cancel button
26033 cancelText : "Cancel",
26035 * @cfg {String} todayTip
26036 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26038 todayTip : "{0} (Spacebar)",
26040 * @cfg {Date} minDate
26041 * Minimum allowable date (JavaScript date object, defaults to null)
26045 * @cfg {Date} maxDate
26046 * Maximum allowable date (JavaScript date object, defaults to null)
26050 * @cfg {String} minText
26051 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26053 minText : "This date is before the minimum date",
26055 * @cfg {String} maxText
26056 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26058 maxText : "This date is after the maximum date",
26060 * @cfg {String} format
26061 * The default date format string which can be overriden for localization support. The format must be
26062 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26066 * @cfg {Array} disabledDays
26067 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26069 disabledDays : null,
26071 * @cfg {String} disabledDaysText
26072 * The tooltip to display when the date falls on a disabled day (defaults to "")
26074 disabledDaysText : "",
26076 * @cfg {RegExp} disabledDatesRE
26077 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26079 disabledDatesRE : null,
26081 * @cfg {String} disabledDatesText
26082 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26084 disabledDatesText : "",
26086 * @cfg {Boolean} constrainToViewport
26087 * True to constrain the date picker to the viewport (defaults to true)
26089 constrainToViewport : true,
26091 * @cfg {Array} monthNames
26092 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26094 monthNames : Date.monthNames,
26096 * @cfg {Array} dayNames
26097 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26099 dayNames : Date.dayNames,
26101 * @cfg {String} nextText
26102 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26104 nextText: 'Next Month (Control+Right)',
26106 * @cfg {String} prevText
26107 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26109 prevText: 'Previous Month (Control+Left)',
26111 * @cfg {String} monthYearText
26112 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26114 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26116 * @cfg {Number} startDay
26117 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26121 * @cfg {Bool} showClear
26122 * Show a clear button (usefull for date form elements that can be blank.)
26128 * Sets the value of the date field
26129 * @param {Date} value The date to set
26131 setValue : function(value){
26132 var old = this.value;
26134 if (typeof(value) == 'string') {
26136 value = Date.parseDate(value, this.format);
26139 value = new Date();
26142 this.value = value.clearTime(true);
26144 this.update(this.value);
26149 * Gets the current selected value of the date field
26150 * @return {Date} The selected date
26152 getValue : function(){
26157 focus : function(){
26159 this.update(this.activeDate);
26164 onRender : function(container, position){
26167 '<table cellspacing="0">',
26168 '<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>',
26169 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26170 var dn = this.dayNames;
26171 for(var i = 0; i < 7; i++){
26172 var d = this.startDay+i;
26176 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26178 m[m.length] = "</tr></thead><tbody><tr>";
26179 for(var i = 0; i < 42; i++) {
26180 if(i % 7 == 0 && i != 0){
26181 m[m.length] = "</tr><tr>";
26183 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26185 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26186 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26188 var el = document.createElement("div");
26189 el.className = "x-date-picker";
26190 el.innerHTML = m.join("");
26192 container.dom.insertBefore(el, position);
26194 this.el = Roo.get(el);
26195 this.eventEl = Roo.get(el.firstChild);
26197 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26198 handler: this.showPrevMonth,
26200 preventDefault:true,
26204 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26205 handler: this.showNextMonth,
26207 preventDefault:true,
26211 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26213 this.monthPicker = this.el.down('div.x-date-mp');
26214 this.monthPicker.enableDisplayMode('block');
26216 var kn = new Roo.KeyNav(this.eventEl, {
26217 "left" : function(e){
26219 this.showPrevMonth() :
26220 this.update(this.activeDate.add("d", -1));
26223 "right" : function(e){
26225 this.showNextMonth() :
26226 this.update(this.activeDate.add("d", 1));
26229 "up" : function(e){
26231 this.showNextYear() :
26232 this.update(this.activeDate.add("d", -7));
26235 "down" : function(e){
26237 this.showPrevYear() :
26238 this.update(this.activeDate.add("d", 7));
26241 "pageUp" : function(e){
26242 this.showNextMonth();
26245 "pageDown" : function(e){
26246 this.showPrevMonth();
26249 "enter" : function(e){
26250 e.stopPropagation();
26257 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26259 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26261 this.el.unselectable();
26263 this.cells = this.el.select("table.x-date-inner tbody td");
26264 this.textNodes = this.el.query("table.x-date-inner tbody span");
26266 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26268 tooltip: this.monthYearText
26271 this.mbtn.on('click', this.showMonthPicker, this);
26272 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26275 var today = (new Date()).dateFormat(this.format);
26277 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26278 if (this.showClear) {
26279 baseTb.add( new Roo.Toolbar.Fill());
26282 text: String.format(this.todayText, today),
26283 tooltip: String.format(this.todayTip, today),
26284 handler: this.selectToday,
26288 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26291 if (this.showClear) {
26293 baseTb.add( new Roo.Toolbar.Fill());
26296 cls: 'x-btn-icon x-btn-clear',
26297 handler: function() {
26299 this.fireEvent("select", this, '');
26309 this.update(this.value);
26312 createMonthPicker : function(){
26313 if(!this.monthPicker.dom.firstChild){
26314 var buf = ['<table border="0" cellspacing="0">'];
26315 for(var i = 0; i < 6; i++){
26317 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26318 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26320 '<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>' :
26321 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26325 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26327 '</button><button type="button" class="x-date-mp-cancel">',
26329 '</button></td></tr>',
26332 this.monthPicker.update(buf.join(''));
26333 this.monthPicker.on('click', this.onMonthClick, this);
26334 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26336 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26337 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26339 this.mpMonths.each(function(m, a, i){
26342 m.dom.xmonth = 5 + Math.round(i * .5);
26344 m.dom.xmonth = Math.round((i-1) * .5);
26350 showMonthPicker : function(){
26351 this.createMonthPicker();
26352 var size = this.el.getSize();
26353 this.monthPicker.setSize(size);
26354 this.monthPicker.child('table').setSize(size);
26356 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26357 this.updateMPMonth(this.mpSelMonth);
26358 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26359 this.updateMPYear(this.mpSelYear);
26361 this.monthPicker.slideIn('t', {duration:.2});
26364 updateMPYear : function(y){
26366 var ys = this.mpYears.elements;
26367 for(var i = 1; i <= 10; i++){
26368 var td = ys[i-1], y2;
26370 y2 = y + Math.round(i * .5);
26371 td.firstChild.innerHTML = y2;
26374 y2 = y - (5-Math.round(i * .5));
26375 td.firstChild.innerHTML = y2;
26378 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26382 updateMPMonth : function(sm){
26383 this.mpMonths.each(function(m, a, i){
26384 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26388 selectMPMonth: function(m){
26392 onMonthClick : function(e, t){
26394 var el = new Roo.Element(t), pn;
26395 if(el.is('button.x-date-mp-cancel')){
26396 this.hideMonthPicker();
26398 else if(el.is('button.x-date-mp-ok')){
26399 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26400 this.hideMonthPicker();
26402 else if(pn = el.up('td.x-date-mp-month', 2)){
26403 this.mpMonths.removeClass('x-date-mp-sel');
26404 pn.addClass('x-date-mp-sel');
26405 this.mpSelMonth = pn.dom.xmonth;
26407 else if(pn = el.up('td.x-date-mp-year', 2)){
26408 this.mpYears.removeClass('x-date-mp-sel');
26409 pn.addClass('x-date-mp-sel');
26410 this.mpSelYear = pn.dom.xyear;
26412 else if(el.is('a.x-date-mp-prev')){
26413 this.updateMPYear(this.mpyear-10);
26415 else if(el.is('a.x-date-mp-next')){
26416 this.updateMPYear(this.mpyear+10);
26420 onMonthDblClick : function(e, t){
26422 var el = new Roo.Element(t), pn;
26423 if(pn = el.up('td.x-date-mp-month', 2)){
26424 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26425 this.hideMonthPicker();
26427 else if(pn = el.up('td.x-date-mp-year', 2)){
26428 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26429 this.hideMonthPicker();
26433 hideMonthPicker : function(disableAnim){
26434 if(this.monthPicker){
26435 if(disableAnim === true){
26436 this.monthPicker.hide();
26438 this.monthPicker.slideOut('t', {duration:.2});
26444 showPrevMonth : function(e){
26445 this.update(this.activeDate.add("mo", -1));
26449 showNextMonth : function(e){
26450 this.update(this.activeDate.add("mo", 1));
26454 showPrevYear : function(){
26455 this.update(this.activeDate.add("y", -1));
26459 showNextYear : function(){
26460 this.update(this.activeDate.add("y", 1));
26464 handleMouseWheel : function(e){
26465 var delta = e.getWheelDelta();
26467 this.showPrevMonth();
26469 } else if(delta < 0){
26470 this.showNextMonth();
26476 handleDateClick : function(e, t){
26478 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26479 this.setValue(new Date(t.dateValue));
26480 this.fireEvent("select", this, this.value);
26485 selectToday : function(){
26486 this.setValue(new Date().clearTime());
26487 this.fireEvent("select", this, this.value);
26491 update : function(date)
26493 var vd = this.activeDate;
26494 this.activeDate = date;
26496 var t = date.getTime();
26497 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26498 this.cells.removeClass("x-date-selected");
26499 this.cells.each(function(c){
26500 if(c.dom.firstChild.dateValue == t){
26501 c.addClass("x-date-selected");
26502 setTimeout(function(){
26503 try{c.dom.firstChild.focus();}catch(e){}
26512 var days = date.getDaysInMonth();
26513 var firstOfMonth = date.getFirstDateOfMonth();
26514 var startingPos = firstOfMonth.getDay()-this.startDay;
26516 if(startingPos <= this.startDay){
26520 var pm = date.add("mo", -1);
26521 var prevStart = pm.getDaysInMonth()-startingPos;
26523 var cells = this.cells.elements;
26524 var textEls = this.textNodes;
26525 days += startingPos;
26527 // convert everything to numbers so it's fast
26528 var day = 86400000;
26529 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26530 var today = new Date().clearTime().getTime();
26531 var sel = date.clearTime().getTime();
26532 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26533 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26534 var ddMatch = this.disabledDatesRE;
26535 var ddText = this.disabledDatesText;
26536 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26537 var ddaysText = this.disabledDaysText;
26538 var format = this.format;
26540 var setCellClass = function(cal, cell){
26542 var t = d.getTime();
26543 cell.firstChild.dateValue = t;
26545 cell.className += " x-date-today";
26546 cell.title = cal.todayText;
26549 cell.className += " x-date-selected";
26550 setTimeout(function(){
26551 try{cell.firstChild.focus();}catch(e){}
26556 cell.className = " x-date-disabled";
26557 cell.title = cal.minText;
26561 cell.className = " x-date-disabled";
26562 cell.title = cal.maxText;
26566 if(ddays.indexOf(d.getDay()) != -1){
26567 cell.title = ddaysText;
26568 cell.className = " x-date-disabled";
26571 if(ddMatch && format){
26572 var fvalue = d.dateFormat(format);
26573 if(ddMatch.test(fvalue)){
26574 cell.title = ddText.replace("%0", fvalue);
26575 cell.className = " x-date-disabled";
26581 for(; i < startingPos; i++) {
26582 textEls[i].innerHTML = (++prevStart);
26583 d.setDate(d.getDate()+1);
26584 cells[i].className = "x-date-prevday";
26585 setCellClass(this, cells[i]);
26587 for(; i < days; i++){
26588 intDay = i - startingPos + 1;
26589 textEls[i].innerHTML = (intDay);
26590 d.setDate(d.getDate()+1);
26591 cells[i].className = "x-date-active";
26592 setCellClass(this, cells[i]);
26595 for(; i < 42; i++) {
26596 textEls[i].innerHTML = (++extraDays);
26597 d.setDate(d.getDate()+1);
26598 cells[i].className = "x-date-nextday";
26599 setCellClass(this, cells[i]);
26602 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26603 this.fireEvent('monthchange', this, date);
26605 if(!this.internalRender){
26606 var main = this.el.dom.firstChild;
26607 var w = main.offsetWidth;
26608 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26609 Roo.fly(main).setWidth(w);
26610 this.internalRender = true;
26611 // opera does not respect the auto grow header center column
26612 // then, after it gets a width opera refuses to recalculate
26613 // without a second pass
26614 if(Roo.isOpera && !this.secondPass){
26615 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26616 this.secondPass = true;
26617 this.update.defer(10, this, [date]);
26625 * Ext JS Library 1.1.1
26626 * Copyright(c) 2006-2007, Ext JS, LLC.
26628 * Originally Released Under LGPL - original licence link has changed is not relivant.
26631 * <script type="text/javascript">
26634 * @class Roo.TabPanel
26635 * @extends Roo.util.Observable
26636 * A lightweight tab container.
26640 // basic tabs 1, built from existing content
26641 var tabs = new Roo.TabPanel("tabs1");
26642 tabs.addTab("script", "View Script");
26643 tabs.addTab("markup", "View Markup");
26644 tabs.activate("script");
26646 // more advanced tabs, built from javascript
26647 var jtabs = new Roo.TabPanel("jtabs");
26648 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26650 // set up the UpdateManager
26651 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26652 var updater = tab2.getUpdateManager();
26653 updater.setDefaultUrl("ajax1.htm");
26654 tab2.on('activate', updater.refresh, updater, true);
26656 // Use setUrl for Ajax loading
26657 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26658 tab3.setUrl("ajax2.htm", null, true);
26661 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26664 jtabs.activate("jtabs-1");
26667 * Create a new TabPanel.
26668 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26669 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26671 Roo.TabPanel = function(container, config){
26673 * The container element for this TabPanel.
26674 * @type Roo.Element
26676 this.el = Roo.get(container, true);
26678 if(typeof config == "boolean"){
26679 this.tabPosition = config ? "bottom" : "top";
26681 Roo.apply(this, config);
26684 if(this.tabPosition == "bottom"){
26685 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26686 this.el.addClass("x-tabs-bottom");
26688 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26689 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26690 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26692 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26694 if(this.tabPosition != "bottom"){
26695 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26696 * @type Roo.Element
26698 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26699 this.el.addClass("x-tabs-top");
26703 this.bodyEl.setStyle("position", "relative");
26705 this.active = null;
26706 this.activateDelegate = this.activate.createDelegate(this);
26711 * Fires when the active tab changes
26712 * @param {Roo.TabPanel} this
26713 * @param {Roo.TabPanelItem} activePanel The new active tab
26717 * @event beforetabchange
26718 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26719 * @param {Roo.TabPanel} this
26720 * @param {Object} e Set cancel to true on this object to cancel the tab change
26721 * @param {Roo.TabPanelItem} tab The tab being changed to
26723 "beforetabchange" : true
26726 Roo.EventManager.onWindowResize(this.onResize, this);
26727 this.cpad = this.el.getPadding("lr");
26728 this.hiddenCount = 0;
26731 // toolbar on the tabbar support...
26732 if (this.toolbar) {
26733 var tcfg = this.toolbar;
26734 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26735 this.toolbar = new Roo.Toolbar(tcfg);
26736 if (Roo.isSafari) {
26737 var tbl = tcfg.container.child('table', true);
26738 tbl.setAttribute('width', '100%');
26745 Roo.TabPanel.superclass.constructor.call(this);
26748 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26750 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26752 tabPosition : "top",
26754 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26756 currentTabWidth : 0,
26758 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26762 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26766 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26768 preferredTabWidth : 175,
26770 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26772 resizeTabs : false,
26774 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26776 monitorResize : true,
26778 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26783 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26784 * @param {String} id The id of the div to use <b>or create</b>
26785 * @param {String} text The text for the tab
26786 * @param {String} content (optional) Content to put in the TabPanelItem body
26787 * @param {Boolean} closable (optional) True to create a close icon on the tab
26788 * @return {Roo.TabPanelItem} The created TabPanelItem
26790 addTab : function(id, text, content, closable){
26791 var item = new Roo.TabPanelItem(this, id, text, closable);
26792 this.addTabItem(item);
26794 item.setContent(content);
26800 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26801 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26802 * @return {Roo.TabPanelItem}
26804 getTab : function(id){
26805 return this.items[id];
26809 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26810 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26812 hideTab : function(id){
26813 var t = this.items[id];
26816 this.hiddenCount++;
26817 this.autoSizeTabs();
26822 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26823 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26825 unhideTab : function(id){
26826 var t = this.items[id];
26828 t.setHidden(false);
26829 this.hiddenCount--;
26830 this.autoSizeTabs();
26835 * Adds an existing {@link Roo.TabPanelItem}.
26836 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26838 addTabItem : function(item){
26839 this.items[item.id] = item;
26840 this.items.push(item);
26841 if(this.resizeTabs){
26842 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26843 this.autoSizeTabs();
26850 * Removes a {@link Roo.TabPanelItem}.
26851 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26853 removeTab : function(id){
26854 var items = this.items;
26855 var tab = items[id];
26856 if(!tab) { return; }
26857 var index = items.indexOf(tab);
26858 if(this.active == tab && items.length > 1){
26859 var newTab = this.getNextAvailable(index);
26864 this.stripEl.dom.removeChild(tab.pnode.dom);
26865 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26866 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26868 items.splice(index, 1);
26869 delete this.items[tab.id];
26870 tab.fireEvent("close", tab);
26871 tab.purgeListeners();
26872 this.autoSizeTabs();
26875 getNextAvailable : function(start){
26876 var items = this.items;
26878 // look for a next tab that will slide over to
26879 // replace the one being removed
26880 while(index < items.length){
26881 var item = items[++index];
26882 if(item && !item.isHidden()){
26886 // if one isn't found select the previous tab (on the left)
26889 var item = items[--index];
26890 if(item && !item.isHidden()){
26898 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26899 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26901 disableTab : function(id){
26902 var tab = this.items[id];
26903 if(tab && this.active != tab){
26909 * Enables a {@link Roo.TabPanelItem} that is disabled.
26910 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26912 enableTab : function(id){
26913 var tab = this.items[id];
26918 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26919 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26920 * @return {Roo.TabPanelItem} The TabPanelItem.
26922 activate : function(id){
26923 var tab = this.items[id];
26927 if(tab == this.active || tab.disabled){
26931 this.fireEvent("beforetabchange", this, e, tab);
26932 if(e.cancel !== true && !tab.disabled){
26934 this.active.hide();
26936 this.active = this.items[id];
26937 this.active.show();
26938 this.fireEvent("tabchange", this, this.active);
26944 * Gets the active {@link Roo.TabPanelItem}.
26945 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26947 getActiveTab : function(){
26948 return this.active;
26952 * Updates the tab body element to fit the height of the container element
26953 * for overflow scrolling
26954 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26956 syncHeight : function(targetHeight){
26957 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26958 var bm = this.bodyEl.getMargins();
26959 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26960 this.bodyEl.setHeight(newHeight);
26964 onResize : function(){
26965 if(this.monitorResize){
26966 this.autoSizeTabs();
26971 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26973 beginUpdate : function(){
26974 this.updating = true;
26978 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26980 endUpdate : function(){
26981 this.updating = false;
26982 this.autoSizeTabs();
26986 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26988 autoSizeTabs : function(){
26989 var count = this.items.length;
26990 var vcount = count - this.hiddenCount;
26991 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26992 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26993 var availWidth = Math.floor(w / vcount);
26994 var b = this.stripBody;
26995 if(b.getWidth() > w){
26996 var tabs = this.items;
26997 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26998 if(availWidth < this.minTabWidth){
26999 /*if(!this.sleft){ // incomplete scrolling code
27000 this.createScrollButtons();
27003 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27006 if(this.currentTabWidth < this.preferredTabWidth){
27007 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27013 * Returns the number of tabs in this TabPanel.
27016 getCount : function(){
27017 return this.items.length;
27021 * Resizes all the tabs to the passed width
27022 * @param {Number} The new width
27024 setTabWidth : function(width){
27025 this.currentTabWidth = width;
27026 for(var i = 0, len = this.items.length; i < len; i++) {
27027 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27032 * Destroys this TabPanel
27033 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27035 destroy : function(removeEl){
27036 Roo.EventManager.removeResizeListener(this.onResize, this);
27037 for(var i = 0, len = this.items.length; i < len; i++){
27038 this.items[i].purgeListeners();
27040 if(removeEl === true){
27041 this.el.update("");
27048 * @class Roo.TabPanelItem
27049 * @extends Roo.util.Observable
27050 * Represents an individual item (tab plus body) in a TabPanel.
27051 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27052 * @param {String} id The id of this TabPanelItem
27053 * @param {String} text The text for the tab of this TabPanelItem
27054 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27056 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27058 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27059 * @type Roo.TabPanel
27061 this.tabPanel = tabPanel;
27063 * The id for this TabPanelItem
27068 this.disabled = false;
27072 this.loaded = false;
27073 this.closable = closable;
27076 * The body element for this TabPanelItem.
27077 * @type Roo.Element
27079 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27080 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27081 this.bodyEl.setStyle("display", "block");
27082 this.bodyEl.setStyle("zoom", "1");
27085 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27087 this.el = Roo.get(els.el, true);
27088 this.inner = Roo.get(els.inner, true);
27089 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27090 this.pnode = Roo.get(els.el.parentNode, true);
27091 this.el.on("mousedown", this.onTabMouseDown, this);
27092 this.el.on("click", this.onTabClick, this);
27095 var c = Roo.get(els.close, true);
27096 c.dom.title = this.closeText;
27097 c.addClassOnOver("close-over");
27098 c.on("click", this.closeClick, this);
27104 * Fires when this tab becomes the active tab.
27105 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27106 * @param {Roo.TabPanelItem} this
27110 * @event beforeclose
27111 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27112 * @param {Roo.TabPanelItem} this
27113 * @param {Object} e Set cancel to true on this object to cancel the close.
27115 "beforeclose": true,
27118 * Fires when this tab is closed.
27119 * @param {Roo.TabPanelItem} this
27123 * @event deactivate
27124 * Fires when this tab is no longer the active tab.
27125 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27126 * @param {Roo.TabPanelItem} this
27128 "deactivate" : true
27130 this.hidden = false;
27132 Roo.TabPanelItem.superclass.constructor.call(this);
27135 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27136 purgeListeners : function(){
27137 Roo.util.Observable.prototype.purgeListeners.call(this);
27138 this.el.removeAllListeners();
27141 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27144 this.pnode.addClass("on");
27147 this.tabPanel.stripWrap.repaint();
27149 this.fireEvent("activate", this.tabPanel, this);
27153 * Returns true if this tab is the active tab.
27154 * @return {Boolean}
27156 isActive : function(){
27157 return this.tabPanel.getActiveTab() == this;
27161 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27164 this.pnode.removeClass("on");
27166 this.fireEvent("deactivate", this.tabPanel, this);
27169 hideAction : function(){
27170 this.bodyEl.hide();
27171 this.bodyEl.setStyle("position", "absolute");
27172 this.bodyEl.setLeft("-20000px");
27173 this.bodyEl.setTop("-20000px");
27176 showAction : function(){
27177 this.bodyEl.setStyle("position", "relative");
27178 this.bodyEl.setTop("");
27179 this.bodyEl.setLeft("");
27180 this.bodyEl.show();
27184 * Set the tooltip for the tab.
27185 * @param {String} tooltip The tab's tooltip
27187 setTooltip : function(text){
27188 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27189 this.textEl.dom.qtip = text;
27190 this.textEl.dom.removeAttribute('title');
27192 this.textEl.dom.title = text;
27196 onTabClick : function(e){
27197 e.preventDefault();
27198 this.tabPanel.activate(this.id);
27201 onTabMouseDown : function(e){
27202 e.preventDefault();
27203 this.tabPanel.activate(this.id);
27206 getWidth : function(){
27207 return this.inner.getWidth();
27210 setWidth : function(width){
27211 var iwidth = width - this.pnode.getPadding("lr");
27212 this.inner.setWidth(iwidth);
27213 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27214 this.pnode.setWidth(width);
27218 * Show or hide the tab
27219 * @param {Boolean} hidden True to hide or false to show.
27221 setHidden : function(hidden){
27222 this.hidden = hidden;
27223 this.pnode.setStyle("display", hidden ? "none" : "");
27227 * Returns true if this tab is "hidden"
27228 * @return {Boolean}
27230 isHidden : function(){
27231 return this.hidden;
27235 * Returns the text for this tab
27238 getText : function(){
27242 autoSize : function(){
27243 //this.el.beginMeasure();
27244 this.textEl.setWidth(1);
27246 * #2804 [new] Tabs in Roojs
27247 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27249 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27250 //this.el.endMeasure();
27254 * Sets the text for the tab (Note: this also sets the tooltip text)
27255 * @param {String} text The tab's text and tooltip
27257 setText : function(text){
27259 this.textEl.update(text);
27260 this.setTooltip(text);
27261 if(!this.tabPanel.resizeTabs){
27266 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27268 activate : function(){
27269 this.tabPanel.activate(this.id);
27273 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27275 disable : function(){
27276 if(this.tabPanel.active != this){
27277 this.disabled = true;
27278 this.pnode.addClass("disabled");
27283 * Enables this TabPanelItem if it was previously disabled.
27285 enable : function(){
27286 this.disabled = false;
27287 this.pnode.removeClass("disabled");
27291 * Sets the content for this TabPanelItem.
27292 * @param {String} content The content
27293 * @param {Boolean} loadScripts true to look for and load scripts
27295 setContent : function(content, loadScripts){
27296 this.bodyEl.update(content, loadScripts);
27300 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27301 * @return {Roo.UpdateManager} The UpdateManager
27303 getUpdateManager : function(){
27304 return this.bodyEl.getUpdateManager();
27308 * Set a URL to be used to load the content for this TabPanelItem.
27309 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27310 * @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)
27311 * @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)
27312 * @return {Roo.UpdateManager} The UpdateManager
27314 setUrl : function(url, params, loadOnce){
27315 if(this.refreshDelegate){
27316 this.un('activate', this.refreshDelegate);
27318 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27319 this.on("activate", this.refreshDelegate);
27320 return this.bodyEl.getUpdateManager();
27324 _handleRefresh : function(url, params, loadOnce){
27325 if(!loadOnce || !this.loaded){
27326 var updater = this.bodyEl.getUpdateManager();
27327 updater.update(url, params, this._setLoaded.createDelegate(this));
27332 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27333 * Will fail silently if the setUrl method has not been called.
27334 * This does not activate the panel, just updates its content.
27336 refresh : function(){
27337 if(this.refreshDelegate){
27338 this.loaded = false;
27339 this.refreshDelegate();
27344 _setLoaded : function(){
27345 this.loaded = true;
27349 closeClick : function(e){
27352 this.fireEvent("beforeclose", this, o);
27353 if(o.cancel !== true){
27354 this.tabPanel.removeTab(this.id);
27358 * The text displayed in the tooltip for the close icon.
27361 closeText : "Close this tab"
27365 Roo.TabPanel.prototype.createStrip = function(container){
27366 var strip = document.createElement("div");
27367 strip.className = "x-tabs-wrap";
27368 container.appendChild(strip);
27372 Roo.TabPanel.prototype.createStripList = function(strip){
27373 // div wrapper for retard IE
27374 // returns the "tr" element.
27375 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27376 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27377 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27378 return strip.firstChild.firstChild.firstChild.firstChild;
27381 Roo.TabPanel.prototype.createBody = function(container){
27382 var body = document.createElement("div");
27383 Roo.id(body, "tab-body");
27384 Roo.fly(body).addClass("x-tabs-body");
27385 container.appendChild(body);
27389 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27390 var body = Roo.getDom(id);
27392 body = document.createElement("div");
27395 Roo.fly(body).addClass("x-tabs-item-body");
27396 bodyEl.insertBefore(body, bodyEl.firstChild);
27400 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27401 var td = document.createElement("td");
27402 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27403 //stripEl.appendChild(td);
27405 td.className = "x-tabs-closable";
27406 if(!this.closeTpl){
27407 this.closeTpl = new Roo.Template(
27408 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27409 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27410 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27413 var el = this.closeTpl.overwrite(td, {"text": text});
27414 var close = el.getElementsByTagName("div")[0];
27415 var inner = el.getElementsByTagName("em")[0];
27416 return {"el": el, "close": close, "inner": inner};
27419 this.tabTpl = new Roo.Template(
27420 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27421 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27424 var el = this.tabTpl.overwrite(td, {"text": text});
27425 var inner = el.getElementsByTagName("em")[0];
27426 return {"el": el, "inner": inner};
27430 * Ext JS Library 1.1.1
27431 * Copyright(c) 2006-2007, Ext JS, LLC.
27433 * Originally Released Under LGPL - original licence link has changed is not relivant.
27436 * <script type="text/javascript">
27440 * @class Roo.Button
27441 * @extends Roo.util.Observable
27442 * Simple Button class
27443 * @cfg {String} text The button text
27444 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27445 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27446 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27447 * @cfg {Object} scope The scope of the handler
27448 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27449 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27450 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27451 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27452 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27453 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27454 applies if enableToggle = true)
27455 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27456 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27457 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27459 * Create a new button
27460 * @param {Object} config The config object
27462 Roo.Button = function(renderTo, config)
27466 renderTo = config.renderTo || false;
27469 Roo.apply(this, config);
27473 * Fires when this button is clicked
27474 * @param {Button} this
27475 * @param {EventObject} e The click event
27480 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27481 * @param {Button} this
27482 * @param {Boolean} pressed
27487 * Fires when the mouse hovers over the button
27488 * @param {Button} this
27489 * @param {Event} e The event object
27491 'mouseover' : true,
27494 * Fires when the mouse exits the button
27495 * @param {Button} this
27496 * @param {Event} e The event object
27501 * Fires when the button is rendered
27502 * @param {Button} this
27507 this.menu = Roo.menu.MenuMgr.get(this.menu);
27509 // register listeners first!! - so render can be captured..
27510 Roo.util.Observable.call(this);
27512 this.render(renderTo);
27518 Roo.extend(Roo.Button, Roo.util.Observable, {
27524 * Read-only. True if this button is hidden
27529 * Read-only. True if this button is disabled
27534 * Read-only. True if this button is pressed (only if enableToggle = true)
27540 * @cfg {Number} tabIndex
27541 * The DOM tabIndex for this button (defaults to undefined)
27543 tabIndex : undefined,
27546 * @cfg {Boolean} enableToggle
27547 * True to enable pressed/not pressed toggling (defaults to false)
27549 enableToggle: false,
27551 * @cfg {Mixed} menu
27552 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27556 * @cfg {String} menuAlign
27557 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27559 menuAlign : "tl-bl?",
27562 * @cfg {String} iconCls
27563 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27565 iconCls : undefined,
27567 * @cfg {String} type
27568 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27573 menuClassTarget: 'tr',
27576 * @cfg {String} clickEvent
27577 * The type of event to map to the button's event handler (defaults to 'click')
27579 clickEvent : 'click',
27582 * @cfg {Boolean} handleMouseEvents
27583 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27585 handleMouseEvents : true,
27588 * @cfg {String} tooltipType
27589 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27591 tooltipType : 'qtip',
27594 * @cfg {String} cls
27595 * A CSS class to apply to the button's main element.
27599 * @cfg {Roo.Template} template (Optional)
27600 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27601 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27602 * require code modifications if required elements (e.g. a button) aren't present.
27606 render : function(renderTo){
27608 if(this.hideParent){
27609 this.parentEl = Roo.get(renderTo);
27611 if(!this.dhconfig){
27612 if(!this.template){
27613 if(!Roo.Button.buttonTemplate){
27614 // hideous table template
27615 Roo.Button.buttonTemplate = new Roo.Template(
27616 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27617 '<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>',
27618 "</tr></tbody></table>");
27620 this.template = Roo.Button.buttonTemplate;
27622 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27623 var btnEl = btn.child("button:first");
27624 btnEl.on('focus', this.onFocus, this);
27625 btnEl.on('blur', this.onBlur, this);
27627 btn.addClass(this.cls);
27630 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27633 btnEl.addClass(this.iconCls);
27635 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27638 if(this.tabIndex !== undefined){
27639 btnEl.dom.tabIndex = this.tabIndex;
27642 if(typeof this.tooltip == 'object'){
27643 Roo.QuickTips.tips(Roo.apply({
27647 btnEl.dom[this.tooltipType] = this.tooltip;
27651 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27655 this.el.dom.id = this.el.id = this.id;
27658 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27659 this.menu.on("show", this.onMenuShow, this);
27660 this.menu.on("hide", this.onMenuHide, this);
27662 btn.addClass("x-btn");
27663 if(Roo.isIE && !Roo.isIE7){
27664 this.autoWidth.defer(1, this);
27668 if(this.handleMouseEvents){
27669 btn.on("mouseover", this.onMouseOver, this);
27670 btn.on("mouseout", this.onMouseOut, this);
27671 btn.on("mousedown", this.onMouseDown, this);
27673 btn.on(this.clickEvent, this.onClick, this);
27674 //btn.on("mouseup", this.onMouseUp, this);
27681 Roo.ButtonToggleMgr.register(this);
27683 this.el.addClass("x-btn-pressed");
27686 var repeater = new Roo.util.ClickRepeater(btn,
27687 typeof this.repeat == "object" ? this.repeat : {}
27689 repeater.on("click", this.onClick, this);
27692 this.fireEvent('render', this);
27696 * Returns the button's underlying element
27697 * @return {Roo.Element} The element
27699 getEl : function(){
27704 * Destroys this Button and removes any listeners.
27706 destroy : function(){
27707 Roo.ButtonToggleMgr.unregister(this);
27708 this.el.removeAllListeners();
27709 this.purgeListeners();
27714 autoWidth : function(){
27716 this.el.setWidth("auto");
27717 if(Roo.isIE7 && Roo.isStrict){
27718 var ib = this.el.child('button');
27719 if(ib && ib.getWidth() > 20){
27721 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27726 this.el.beginMeasure();
27728 if(this.el.getWidth() < this.minWidth){
27729 this.el.setWidth(this.minWidth);
27732 this.el.endMeasure();
27739 * Assigns this button's click handler
27740 * @param {Function} handler The function to call when the button is clicked
27741 * @param {Object} scope (optional) Scope for the function passed in
27743 setHandler : function(handler, scope){
27744 this.handler = handler;
27745 this.scope = scope;
27749 * Sets this button's text
27750 * @param {String} text The button text
27752 setText : function(text){
27755 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27761 * Gets the text for this button
27762 * @return {String} The button text
27764 getText : function(){
27772 this.hidden = false;
27774 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27782 this.hidden = true;
27784 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27789 * Convenience function for boolean show/hide
27790 * @param {Boolean} visible True to show, false to hide
27792 setVisible: function(visible){
27801 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27802 * @param {Boolean} state (optional) Force a particular state
27804 toggle : function(state){
27805 state = state === undefined ? !this.pressed : state;
27806 if(state != this.pressed){
27808 this.el.addClass("x-btn-pressed");
27809 this.pressed = true;
27810 this.fireEvent("toggle", this, true);
27812 this.el.removeClass("x-btn-pressed");
27813 this.pressed = false;
27814 this.fireEvent("toggle", this, false);
27816 if(this.toggleHandler){
27817 this.toggleHandler.call(this.scope || this, this, state);
27825 focus : function(){
27826 this.el.child('button:first').focus();
27830 * Disable this button
27832 disable : function(){
27834 this.el.addClass("x-btn-disabled");
27836 this.disabled = true;
27840 * Enable this button
27842 enable : function(){
27844 this.el.removeClass("x-btn-disabled");
27846 this.disabled = false;
27850 * Convenience function for boolean enable/disable
27851 * @param {Boolean} enabled True to enable, false to disable
27853 setDisabled : function(v){
27854 this[v !== true ? "enable" : "disable"]();
27858 onClick : function(e){
27860 e.preventDefault();
27865 if(!this.disabled){
27866 if(this.enableToggle){
27869 if(this.menu && !this.menu.isVisible()){
27870 this.menu.show(this.el, this.menuAlign);
27872 this.fireEvent("click", this, e);
27874 this.el.removeClass("x-btn-over");
27875 this.handler.call(this.scope || this, this, e);
27880 onMouseOver : function(e){
27881 if(!this.disabled){
27882 this.el.addClass("x-btn-over");
27883 this.fireEvent('mouseover', this, e);
27887 onMouseOut : function(e){
27888 if(!e.within(this.el, true)){
27889 this.el.removeClass("x-btn-over");
27890 this.fireEvent('mouseout', this, e);
27894 onFocus : function(e){
27895 if(!this.disabled){
27896 this.el.addClass("x-btn-focus");
27900 onBlur : function(e){
27901 this.el.removeClass("x-btn-focus");
27904 onMouseDown : function(e){
27905 if(!this.disabled && e.button == 0){
27906 this.el.addClass("x-btn-click");
27907 Roo.get(document).on('mouseup', this.onMouseUp, this);
27911 onMouseUp : function(e){
27913 this.el.removeClass("x-btn-click");
27914 Roo.get(document).un('mouseup', this.onMouseUp, this);
27918 onMenuShow : function(e){
27919 this.el.addClass("x-btn-menu-active");
27922 onMenuHide : function(e){
27923 this.el.removeClass("x-btn-menu-active");
27927 // Private utility class used by Button
27928 Roo.ButtonToggleMgr = function(){
27931 function toggleGroup(btn, state){
27933 var g = groups[btn.toggleGroup];
27934 for(var i = 0, l = g.length; i < l; i++){
27936 g[i].toggle(false);
27943 register : function(btn){
27944 if(!btn.toggleGroup){
27947 var g = groups[btn.toggleGroup];
27949 g = groups[btn.toggleGroup] = [];
27952 btn.on("toggle", toggleGroup);
27955 unregister : function(btn){
27956 if(!btn.toggleGroup){
27959 var g = groups[btn.toggleGroup];
27962 btn.un("toggle", toggleGroup);
27968 * Ext JS Library 1.1.1
27969 * Copyright(c) 2006-2007, Ext JS, LLC.
27971 * Originally Released Under LGPL - original licence link has changed is not relivant.
27974 * <script type="text/javascript">
27978 * @class Roo.SplitButton
27979 * @extends Roo.Button
27980 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27981 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27982 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27983 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27984 * @cfg {String} arrowTooltip The title attribute of the arrow
27986 * Create a new menu button
27987 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27988 * @param {Object} config The config object
27990 Roo.SplitButton = function(renderTo, config){
27991 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27993 * @event arrowclick
27994 * Fires when this button's arrow is clicked
27995 * @param {SplitButton} this
27996 * @param {EventObject} e The click event
27998 this.addEvents({"arrowclick":true});
28001 Roo.extend(Roo.SplitButton, Roo.Button, {
28002 render : function(renderTo){
28003 // this is one sweet looking template!
28004 var tpl = new Roo.Template(
28005 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28006 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28007 '<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>',
28008 "</tbody></table></td><td>",
28009 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28010 '<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>',
28011 "</tbody></table></td></tr></table>"
28013 var btn = tpl.append(renderTo, [this.text, this.type], true);
28014 var btnEl = btn.child("button");
28016 btn.addClass(this.cls);
28019 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28022 btnEl.addClass(this.iconCls);
28024 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28028 if(this.handleMouseEvents){
28029 btn.on("mouseover", this.onMouseOver, this);
28030 btn.on("mouseout", this.onMouseOut, this);
28031 btn.on("mousedown", this.onMouseDown, this);
28032 btn.on("mouseup", this.onMouseUp, this);
28034 btn.on(this.clickEvent, this.onClick, this);
28036 if(typeof this.tooltip == 'object'){
28037 Roo.QuickTips.tips(Roo.apply({
28041 btnEl.dom[this.tooltipType] = this.tooltip;
28044 if(this.arrowTooltip){
28045 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28054 this.el.addClass("x-btn-pressed");
28056 if(Roo.isIE && !Roo.isIE7){
28057 this.autoWidth.defer(1, this);
28062 this.menu.on("show", this.onMenuShow, this);
28063 this.menu.on("hide", this.onMenuHide, this);
28065 this.fireEvent('render', this);
28069 autoWidth : function(){
28071 var tbl = this.el.child("table:first");
28072 var tbl2 = this.el.child("table:last");
28073 this.el.setWidth("auto");
28074 tbl.setWidth("auto");
28075 if(Roo.isIE7 && Roo.isStrict){
28076 var ib = this.el.child('button:first');
28077 if(ib && ib.getWidth() > 20){
28079 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28084 this.el.beginMeasure();
28086 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28087 tbl.setWidth(this.minWidth-tbl2.getWidth());
28090 this.el.endMeasure();
28093 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28097 * Sets this button's click handler
28098 * @param {Function} handler The function to call when the button is clicked
28099 * @param {Object} scope (optional) Scope for the function passed above
28101 setHandler : function(handler, scope){
28102 this.handler = handler;
28103 this.scope = scope;
28107 * Sets this button's arrow click handler
28108 * @param {Function} handler The function to call when the arrow is clicked
28109 * @param {Object} scope (optional) Scope for the function passed above
28111 setArrowHandler : function(handler, scope){
28112 this.arrowHandler = handler;
28113 this.scope = scope;
28119 focus : function(){
28121 this.el.child("button:first").focus();
28126 onClick : function(e){
28127 e.preventDefault();
28128 if(!this.disabled){
28129 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28130 if(this.menu && !this.menu.isVisible()){
28131 this.menu.show(this.el, this.menuAlign);
28133 this.fireEvent("arrowclick", this, e);
28134 if(this.arrowHandler){
28135 this.arrowHandler.call(this.scope || this, this, e);
28138 this.fireEvent("click", this, e);
28140 this.handler.call(this.scope || this, this, e);
28146 onMouseDown : function(e){
28147 if(!this.disabled){
28148 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28152 onMouseUp : function(e){
28153 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28158 // backwards compat
28159 Roo.MenuButton = Roo.SplitButton;/*
28161 * Ext JS Library 1.1.1
28162 * Copyright(c) 2006-2007, Ext JS, LLC.
28164 * Originally Released Under LGPL - original licence link has changed is not relivant.
28167 * <script type="text/javascript">
28171 * @class Roo.Toolbar
28172 * Basic Toolbar class.
28174 * Creates a new Toolbar
28175 * @param {Object} container The config object
28177 Roo.Toolbar = function(container, buttons, config)
28179 /// old consturctor format still supported..
28180 if(container instanceof Array){ // omit the container for later rendering
28181 buttons = container;
28185 if (typeof(container) == 'object' && container.xtype) {
28186 config = container;
28187 container = config.container;
28188 buttons = config.buttons || []; // not really - use items!!
28191 if (config && config.items) {
28192 xitems = config.items;
28193 delete config.items;
28195 Roo.apply(this, config);
28196 this.buttons = buttons;
28199 this.render(container);
28201 this.xitems = xitems;
28202 Roo.each(xitems, function(b) {
28208 Roo.Toolbar.prototype = {
28210 * @cfg {Array} items
28211 * array of button configs or elements to add (will be converted to a MixedCollection)
28215 * @cfg {String/HTMLElement/Element} container
28216 * The id or element that will contain the toolbar
28219 render : function(ct){
28220 this.el = Roo.get(ct);
28222 this.el.addClass(this.cls);
28224 // using a table allows for vertical alignment
28225 // 100% width is needed by Safari...
28226 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28227 this.tr = this.el.child("tr", true);
28229 this.items = new Roo.util.MixedCollection(false, function(o){
28230 return o.id || ("item" + (++autoId));
28233 this.add.apply(this, this.buttons);
28234 delete this.buttons;
28239 * Adds element(s) to the toolbar -- this function takes a variable number of
28240 * arguments of mixed type and adds them to the toolbar.
28241 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28243 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28244 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28245 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28246 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28247 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28248 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28249 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28250 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28251 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28253 * @param {Mixed} arg2
28254 * @param {Mixed} etc.
28257 var a = arguments, l = a.length;
28258 for(var i = 0; i < l; i++){
28263 _add : function(el) {
28266 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28269 if (el.applyTo){ // some kind of form field
28270 return this.addField(el);
28272 if (el.render){ // some kind of Toolbar.Item
28273 return this.addItem(el);
28275 if (typeof el == "string"){ // string
28276 if(el == "separator" || el == "-"){
28277 return this.addSeparator();
28280 return this.addSpacer();
28283 return this.addFill();
28285 return this.addText(el);
28288 if(el.tagName){ // element
28289 return this.addElement(el);
28291 if(typeof el == "object"){ // must be button config?
28292 return this.addButton(el);
28294 // and now what?!?!
28300 * Add an Xtype element
28301 * @param {Object} xtype Xtype Object
28302 * @return {Object} created Object
28304 addxtype : function(e){
28305 return this.add(e);
28309 * Returns the Element for this toolbar.
28310 * @return {Roo.Element}
28312 getEl : function(){
28318 * @return {Roo.Toolbar.Item} The separator item
28320 addSeparator : function(){
28321 return this.addItem(new Roo.Toolbar.Separator());
28325 * Adds a spacer element
28326 * @return {Roo.Toolbar.Spacer} The spacer item
28328 addSpacer : function(){
28329 return this.addItem(new Roo.Toolbar.Spacer());
28333 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28334 * @return {Roo.Toolbar.Fill} The fill item
28336 addFill : function(){
28337 return this.addItem(new Roo.Toolbar.Fill());
28341 * Adds any standard HTML element to the toolbar
28342 * @param {String/HTMLElement/Element} el The element or id of the element to add
28343 * @return {Roo.Toolbar.Item} The element's item
28345 addElement : function(el){
28346 return this.addItem(new Roo.Toolbar.Item(el));
28349 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28350 * @type Roo.util.MixedCollection
28355 * Adds any Toolbar.Item or subclass
28356 * @param {Roo.Toolbar.Item} item
28357 * @return {Roo.Toolbar.Item} The item
28359 addItem : function(item){
28360 var td = this.nextBlock();
28362 this.items.add(item);
28367 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28368 * @param {Object/Array} config A button config or array of configs
28369 * @return {Roo.Toolbar.Button/Array}
28371 addButton : function(config){
28372 if(config instanceof Array){
28374 for(var i = 0, len = config.length; i < len; i++) {
28375 buttons.push(this.addButton(config[i]));
28380 if(!(config instanceof Roo.Toolbar.Button)){
28382 new Roo.Toolbar.SplitButton(config) :
28383 new Roo.Toolbar.Button(config);
28385 var td = this.nextBlock();
28392 * Adds text to the toolbar
28393 * @param {String} text The text to add
28394 * @return {Roo.Toolbar.Item} The element's item
28396 addText : function(text){
28397 return this.addItem(new Roo.Toolbar.TextItem(text));
28401 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28402 * @param {Number} index The index where the item is to be inserted
28403 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28404 * @return {Roo.Toolbar.Button/Item}
28406 insertButton : function(index, item){
28407 if(item instanceof Array){
28409 for(var i = 0, len = item.length; i < len; i++) {
28410 buttons.push(this.insertButton(index + i, item[i]));
28414 if (!(item instanceof Roo.Toolbar.Button)){
28415 item = new Roo.Toolbar.Button(item);
28417 var td = document.createElement("td");
28418 this.tr.insertBefore(td, this.tr.childNodes[index]);
28420 this.items.insert(index, item);
28425 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28426 * @param {Object} config
28427 * @return {Roo.Toolbar.Item} The element's item
28429 addDom : function(config, returnEl){
28430 var td = this.nextBlock();
28431 Roo.DomHelper.overwrite(td, config);
28432 var ti = new Roo.Toolbar.Item(td.firstChild);
28434 this.items.add(ti);
28439 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28440 * @type Roo.util.MixedCollection
28445 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28446 * Note: the field should not have been rendered yet. For a field that has already been
28447 * rendered, use {@link #addElement}.
28448 * @param {Roo.form.Field} field
28449 * @return {Roo.ToolbarItem}
28453 addField : function(field) {
28454 if (!this.fields) {
28456 this.fields = new Roo.util.MixedCollection(false, function(o){
28457 return o.id || ("item" + (++autoId));
28462 var td = this.nextBlock();
28464 var ti = new Roo.Toolbar.Item(td.firstChild);
28466 this.items.add(ti);
28467 this.fields.add(field);
28478 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28479 this.el.child('div').hide();
28487 this.el.child('div').show();
28491 nextBlock : function(){
28492 var td = document.createElement("td");
28493 this.tr.appendChild(td);
28498 destroy : function(){
28499 if(this.items){ // rendered?
28500 Roo.destroy.apply(Roo, this.items.items);
28502 if(this.fields){ // rendered?
28503 Roo.destroy.apply(Roo, this.fields.items);
28505 Roo.Element.uncache(this.el, this.tr);
28510 * @class Roo.Toolbar.Item
28511 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28513 * Creates a new Item
28514 * @param {HTMLElement} el
28516 Roo.Toolbar.Item = function(el){
28517 this.el = Roo.getDom(el);
28518 this.id = Roo.id(this.el);
28519 this.hidden = false;
28522 Roo.Toolbar.Item.prototype = {
28525 * Get this item's HTML Element
28526 * @return {HTMLElement}
28528 getEl : function(){
28533 render : function(td){
28535 td.appendChild(this.el);
28539 * Removes and destroys this item.
28541 destroy : function(){
28542 this.td.parentNode.removeChild(this.td);
28549 this.hidden = false;
28550 this.td.style.display = "";
28557 this.hidden = true;
28558 this.td.style.display = "none";
28562 * Convenience function for boolean show/hide.
28563 * @param {Boolean} visible true to show/false to hide
28565 setVisible: function(visible){
28574 * Try to focus this item.
28576 focus : function(){
28577 Roo.fly(this.el).focus();
28581 * Disables this item.
28583 disable : function(){
28584 Roo.fly(this.td).addClass("x-item-disabled");
28585 this.disabled = true;
28586 this.el.disabled = true;
28590 * Enables this item.
28592 enable : function(){
28593 Roo.fly(this.td).removeClass("x-item-disabled");
28594 this.disabled = false;
28595 this.el.disabled = false;
28601 * @class Roo.Toolbar.Separator
28602 * @extends Roo.Toolbar.Item
28603 * A simple toolbar separator class
28605 * Creates a new Separator
28607 Roo.Toolbar.Separator = function(){
28608 var s = document.createElement("span");
28609 s.className = "ytb-sep";
28610 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28612 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28613 enable:Roo.emptyFn,
28614 disable:Roo.emptyFn,
28619 * @class Roo.Toolbar.Spacer
28620 * @extends Roo.Toolbar.Item
28621 * A simple element that adds extra horizontal space to a toolbar.
28623 * Creates a new Spacer
28625 Roo.Toolbar.Spacer = function(){
28626 var s = document.createElement("div");
28627 s.className = "ytb-spacer";
28628 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28630 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28631 enable:Roo.emptyFn,
28632 disable:Roo.emptyFn,
28637 * @class Roo.Toolbar.Fill
28638 * @extends Roo.Toolbar.Spacer
28639 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28641 * Creates a new Spacer
28643 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28645 render : function(td){
28646 td.style.width = '100%';
28647 Roo.Toolbar.Fill.superclass.render.call(this, td);
28652 * @class Roo.Toolbar.TextItem
28653 * @extends Roo.Toolbar.Item
28654 * A simple class that renders text directly into a toolbar.
28656 * Creates a new TextItem
28657 * @param {String} text
28659 Roo.Toolbar.TextItem = function(text){
28660 if (typeof(text) == 'object') {
28663 var s = document.createElement("span");
28664 s.className = "ytb-text";
28665 s.innerHTML = text;
28666 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28668 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28669 enable:Roo.emptyFn,
28670 disable:Roo.emptyFn,
28675 * @class Roo.Toolbar.Button
28676 * @extends Roo.Button
28677 * A button that renders into a toolbar.
28679 * Creates a new Button
28680 * @param {Object} config A standard {@link Roo.Button} config object
28682 Roo.Toolbar.Button = function(config){
28683 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28685 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28686 render : function(td){
28688 Roo.Toolbar.Button.superclass.render.call(this, td);
28692 * Removes and destroys this button
28694 destroy : function(){
28695 Roo.Toolbar.Button.superclass.destroy.call(this);
28696 this.td.parentNode.removeChild(this.td);
28700 * Shows this button
28703 this.hidden = false;
28704 this.td.style.display = "";
28708 * Hides this button
28711 this.hidden = true;
28712 this.td.style.display = "none";
28716 * Disables this item
28718 disable : function(){
28719 Roo.fly(this.td).addClass("x-item-disabled");
28720 this.disabled = true;
28724 * Enables this item
28726 enable : function(){
28727 Roo.fly(this.td).removeClass("x-item-disabled");
28728 this.disabled = false;
28731 // backwards compat
28732 Roo.ToolbarButton = Roo.Toolbar.Button;
28735 * @class Roo.Toolbar.SplitButton
28736 * @extends Roo.SplitButton
28737 * A menu button that renders into a toolbar.
28739 * Creates a new SplitButton
28740 * @param {Object} config A standard {@link Roo.SplitButton} config object
28742 Roo.Toolbar.SplitButton = function(config){
28743 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28745 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28746 render : function(td){
28748 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28752 * Removes and destroys this button
28754 destroy : function(){
28755 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28756 this.td.parentNode.removeChild(this.td);
28760 * Shows this button
28763 this.hidden = false;
28764 this.td.style.display = "";
28768 * Hides this button
28771 this.hidden = true;
28772 this.td.style.display = "none";
28776 // backwards compat
28777 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28779 * Ext JS Library 1.1.1
28780 * Copyright(c) 2006-2007, Ext JS, LLC.
28782 * Originally Released Under LGPL - original licence link has changed is not relivant.
28785 * <script type="text/javascript">
28789 * @class Roo.PagingToolbar
28790 * @extends Roo.Toolbar
28791 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28793 * Create a new PagingToolbar
28794 * @param {Object} config The config object
28796 Roo.PagingToolbar = function(el, ds, config)
28798 // old args format still supported... - xtype is prefered..
28799 if (typeof(el) == 'object' && el.xtype) {
28800 // created from xtype...
28802 ds = el.dataSource;
28803 el = config.container;
28806 if (config.items) {
28807 items = config.items;
28811 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28814 this.renderButtons(this.el);
28817 // supprot items array.
28819 Roo.each(items, function(e) {
28820 this.add(Roo.factory(e));
28825 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28827 * @cfg {Roo.data.Store} dataSource
28828 * The underlying data store providing the paged data
28831 * @cfg {String/HTMLElement/Element} container
28832 * container The id or element that will contain the toolbar
28835 * @cfg {Boolean} displayInfo
28836 * True to display the displayMsg (defaults to false)
28839 * @cfg {Number} pageSize
28840 * The number of records to display per page (defaults to 20)
28844 * @cfg {String} displayMsg
28845 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28847 displayMsg : 'Displaying {0} - {1} of {2}',
28849 * @cfg {String} emptyMsg
28850 * The message to display when no records are found (defaults to "No data to display")
28852 emptyMsg : 'No data to display',
28854 * Customizable piece of the default paging text (defaults to "Page")
28857 beforePageText : "Page",
28859 * Customizable piece of the default paging text (defaults to "of %0")
28862 afterPageText : "of {0}",
28864 * Customizable piece of the default paging text (defaults to "First Page")
28867 firstText : "First Page",
28869 * Customizable piece of the default paging text (defaults to "Previous Page")
28872 prevText : "Previous Page",
28874 * Customizable piece of the default paging text (defaults to "Next Page")
28877 nextText : "Next Page",
28879 * Customizable piece of the default paging text (defaults to "Last Page")
28882 lastText : "Last Page",
28884 * Customizable piece of the default paging text (defaults to "Refresh")
28887 refreshText : "Refresh",
28890 renderButtons : function(el){
28891 Roo.PagingToolbar.superclass.render.call(this, el);
28892 this.first = this.addButton({
28893 tooltip: this.firstText,
28894 cls: "x-btn-icon x-grid-page-first",
28896 handler: this.onClick.createDelegate(this, ["first"])
28898 this.prev = this.addButton({
28899 tooltip: this.prevText,
28900 cls: "x-btn-icon x-grid-page-prev",
28902 handler: this.onClick.createDelegate(this, ["prev"])
28904 //this.addSeparator();
28905 this.add(this.beforePageText);
28906 this.field = Roo.get(this.addDom({
28911 cls: "x-grid-page-number"
28913 this.field.on("keydown", this.onPagingKeydown, this);
28914 this.field.on("focus", function(){this.dom.select();});
28915 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28916 this.field.setHeight(18);
28917 //this.addSeparator();
28918 this.next = this.addButton({
28919 tooltip: this.nextText,
28920 cls: "x-btn-icon x-grid-page-next",
28922 handler: this.onClick.createDelegate(this, ["next"])
28924 this.last = this.addButton({
28925 tooltip: this.lastText,
28926 cls: "x-btn-icon x-grid-page-last",
28928 handler: this.onClick.createDelegate(this, ["last"])
28930 //this.addSeparator();
28931 this.loading = this.addButton({
28932 tooltip: this.refreshText,
28933 cls: "x-btn-icon x-grid-loading",
28934 handler: this.onClick.createDelegate(this, ["refresh"])
28937 if(this.displayInfo){
28938 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28943 updateInfo : function(){
28944 if(this.displayEl){
28945 var count = this.ds.getCount();
28946 var msg = count == 0 ?
28950 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28952 this.displayEl.update(msg);
28957 onLoad : function(ds, r, o){
28958 this.cursor = o.params ? o.params.start : 0;
28959 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28961 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28962 this.field.dom.value = ap;
28963 this.first.setDisabled(ap == 1);
28964 this.prev.setDisabled(ap == 1);
28965 this.next.setDisabled(ap == ps);
28966 this.last.setDisabled(ap == ps);
28967 this.loading.enable();
28972 getPageData : function(){
28973 var total = this.ds.getTotalCount();
28976 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28977 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28982 onLoadError : function(){
28983 this.loading.enable();
28987 onPagingKeydown : function(e){
28988 var k = e.getKey();
28989 var d = this.getPageData();
28991 var v = this.field.dom.value, pageNum;
28992 if(!v || isNaN(pageNum = parseInt(v, 10))){
28993 this.field.dom.value = d.activePage;
28996 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28997 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29000 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))
29002 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29003 this.field.dom.value = pageNum;
29004 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29007 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29009 var v = this.field.dom.value, pageNum;
29010 var increment = (e.shiftKey) ? 10 : 1;
29011 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29013 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29014 this.field.dom.value = d.activePage;
29017 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29019 this.field.dom.value = parseInt(v, 10) + increment;
29020 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29021 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29028 beforeLoad : function(){
29030 this.loading.disable();
29035 onClick : function(which){
29039 ds.load({params:{start: 0, limit: this.pageSize}});
29042 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29045 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29048 var total = ds.getTotalCount();
29049 var extra = total % this.pageSize;
29050 var lastStart = extra ? (total - extra) : total-this.pageSize;
29051 ds.load({params:{start: lastStart, limit: this.pageSize}});
29054 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29060 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29061 * @param {Roo.data.Store} store The data store to unbind
29063 unbind : function(ds){
29064 ds.un("beforeload", this.beforeLoad, this);
29065 ds.un("load", this.onLoad, this);
29066 ds.un("loadexception", this.onLoadError, this);
29067 ds.un("remove", this.updateInfo, this);
29068 ds.un("add", this.updateInfo, this);
29069 this.ds = undefined;
29073 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29074 * @param {Roo.data.Store} store The data store to bind
29076 bind : function(ds){
29077 ds.on("beforeload", this.beforeLoad, this);
29078 ds.on("load", this.onLoad, this);
29079 ds.on("loadexception", this.onLoadError, this);
29080 ds.on("remove", this.updateInfo, this);
29081 ds.on("add", this.updateInfo, this);
29086 * Ext JS Library 1.1.1
29087 * Copyright(c) 2006-2007, Ext JS, LLC.
29089 * Originally Released Under LGPL - original licence link has changed is not relivant.
29092 * <script type="text/javascript">
29096 * @class Roo.Resizable
29097 * @extends Roo.util.Observable
29098 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29099 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29100 * 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
29101 * the element will be wrapped for you automatically.</p>
29102 * <p>Here is the list of valid resize handles:</p>
29105 ------ -------------------
29114 'hd' horizontal drag
29117 * <p>Here's an example showing the creation of a typical Resizable:</p>
29119 var resizer = new Roo.Resizable("element-id", {
29127 resizer.on("resize", myHandler);
29129 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29130 * resizer.east.setDisplayed(false);</p>
29131 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29132 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29133 * resize operation's new size (defaults to [0, 0])
29134 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29135 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29136 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29137 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29138 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29139 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29140 * @cfg {Number} width The width of the element in pixels (defaults to null)
29141 * @cfg {Number} height The height of the element in pixels (defaults to null)
29142 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29143 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29144 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29145 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29146 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29147 * in favor of the handles config option (defaults to false)
29148 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29149 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29150 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29151 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29152 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29153 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29154 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29155 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29156 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29157 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29158 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29160 * Create a new resizable component
29161 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29162 * @param {Object} config configuration options
29164 Roo.Resizable = function(el, config)
29166 this.el = Roo.get(el);
29168 if(config && config.wrap){
29169 config.resizeChild = this.el;
29170 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29171 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29172 this.el.setStyle("overflow", "hidden");
29173 this.el.setPositioning(config.resizeChild.getPositioning());
29174 config.resizeChild.clearPositioning();
29175 if(!config.width || !config.height){
29176 var csize = config.resizeChild.getSize();
29177 this.el.setSize(csize.width, csize.height);
29179 if(config.pinned && !config.adjustments){
29180 config.adjustments = "auto";
29184 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29185 this.proxy.unselectable();
29186 this.proxy.enableDisplayMode('block');
29188 Roo.apply(this, config);
29191 this.disableTrackOver = true;
29192 this.el.addClass("x-resizable-pinned");
29194 // if the element isn't positioned, make it relative
29195 var position = this.el.getStyle("position");
29196 if(position != "absolute" && position != "fixed"){
29197 this.el.setStyle("position", "relative");
29199 if(!this.handles){ // no handles passed, must be legacy style
29200 this.handles = 's,e,se';
29201 if(this.multiDirectional){
29202 this.handles += ',n,w';
29205 if(this.handles == "all"){
29206 this.handles = "n s e w ne nw se sw";
29208 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29209 var ps = Roo.Resizable.positions;
29210 for(var i = 0, len = hs.length; i < len; i++){
29211 if(hs[i] && ps[hs[i]]){
29212 var pos = ps[hs[i]];
29213 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29217 this.corner = this.southeast;
29219 // updateBox = the box can move..
29220 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29221 this.updateBox = true;
29224 this.activeHandle = null;
29226 if(this.resizeChild){
29227 if(typeof this.resizeChild == "boolean"){
29228 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29230 this.resizeChild = Roo.get(this.resizeChild, true);
29234 if(this.adjustments == "auto"){
29235 var rc = this.resizeChild;
29236 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29237 if(rc && (hw || hn)){
29238 rc.position("relative");
29239 rc.setLeft(hw ? hw.el.getWidth() : 0);
29240 rc.setTop(hn ? hn.el.getHeight() : 0);
29242 this.adjustments = [
29243 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29244 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29248 if(this.draggable){
29249 this.dd = this.dynamic ?
29250 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29251 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29257 * @event beforeresize
29258 * Fired before resize is allowed. Set enabled to false to cancel resize.
29259 * @param {Roo.Resizable} this
29260 * @param {Roo.EventObject} e The mousedown event
29262 "beforeresize" : true,
29265 * Fired a resizing.
29266 * @param {Roo.Resizable} this
29267 * @param {Number} x The new x position
29268 * @param {Number} y The new y position
29269 * @param {Number} w The new w width
29270 * @param {Number} h The new h hight
29271 * @param {Roo.EventObject} e The mouseup event
29276 * Fired after a resize.
29277 * @param {Roo.Resizable} this
29278 * @param {Number} width The new width
29279 * @param {Number} height The new height
29280 * @param {Roo.EventObject} e The mouseup event
29285 if(this.width !== null && this.height !== null){
29286 this.resizeTo(this.width, this.height);
29288 this.updateChildSize();
29291 this.el.dom.style.zoom = 1;
29293 Roo.Resizable.superclass.constructor.call(this);
29296 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29297 resizeChild : false,
29298 adjustments : [0, 0],
29308 multiDirectional : false,
29309 disableTrackOver : false,
29310 easing : 'easeOutStrong',
29311 widthIncrement : 0,
29312 heightIncrement : 0,
29316 preserveRatio : false,
29317 transparent: false,
29323 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29325 constrainTo: undefined,
29327 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29329 resizeRegion: undefined,
29333 * Perform a manual resize
29334 * @param {Number} width
29335 * @param {Number} height
29337 resizeTo : function(width, height){
29338 this.el.setSize(width, height);
29339 this.updateChildSize();
29340 this.fireEvent("resize", this, width, height, null);
29344 startSizing : function(e, handle){
29345 this.fireEvent("beforeresize", this, e);
29346 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29349 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29350 this.overlay.unselectable();
29351 this.overlay.enableDisplayMode("block");
29352 this.overlay.on("mousemove", this.onMouseMove, this);
29353 this.overlay.on("mouseup", this.onMouseUp, this);
29355 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29357 this.resizing = true;
29358 this.startBox = this.el.getBox();
29359 this.startPoint = e.getXY();
29360 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29361 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29363 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29364 this.overlay.show();
29366 if(this.constrainTo) {
29367 var ct = Roo.get(this.constrainTo);
29368 this.resizeRegion = ct.getRegion().adjust(
29369 ct.getFrameWidth('t'),
29370 ct.getFrameWidth('l'),
29371 -ct.getFrameWidth('b'),
29372 -ct.getFrameWidth('r')
29376 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29378 this.proxy.setBox(this.startBox);
29380 this.proxy.setStyle('visibility', 'visible');
29386 onMouseDown : function(handle, e){
29389 this.activeHandle = handle;
29390 this.startSizing(e, handle);
29395 onMouseUp : function(e){
29396 var size = this.resizeElement();
29397 this.resizing = false;
29399 this.overlay.hide();
29401 this.fireEvent("resize", this, size.width, size.height, e);
29405 updateChildSize : function(){
29407 if(this.resizeChild){
29409 var child = this.resizeChild;
29410 var adj = this.adjustments;
29411 if(el.dom.offsetWidth){
29412 var b = el.getSize(true);
29413 child.setSize(b.width+adj[0], b.height+adj[1]);
29415 // Second call here for IE
29416 // The first call enables instant resizing and
29417 // the second call corrects scroll bars if they
29420 setTimeout(function(){
29421 if(el.dom.offsetWidth){
29422 var b = el.getSize(true);
29423 child.setSize(b.width+adj[0], b.height+adj[1]);
29431 snap : function(value, inc, min){
29432 if(!inc || !value) return value;
29433 var newValue = value;
29434 var m = value % inc;
29437 newValue = value + (inc-m);
29439 newValue = value - m;
29442 return Math.max(min, newValue);
29446 resizeElement : function(){
29447 var box = this.proxy.getBox();
29448 if(this.updateBox){
29449 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29451 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29453 this.updateChildSize();
29461 constrain : function(v, diff, m, mx){
29464 }else if(v - diff > mx){
29471 onMouseMove : function(e){
29474 try{// try catch so if something goes wrong the user doesn't get hung
29476 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29480 //var curXY = this.startPoint;
29481 var curSize = this.curSize || this.startBox;
29482 var x = this.startBox.x, y = this.startBox.y;
29483 var ox = x, oy = y;
29484 var w = curSize.width, h = curSize.height;
29485 var ow = w, oh = h;
29486 var mw = this.minWidth, mh = this.minHeight;
29487 var mxw = this.maxWidth, mxh = this.maxHeight;
29488 var wi = this.widthIncrement;
29489 var hi = this.heightIncrement;
29491 var eventXY = e.getXY();
29492 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29493 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29495 var pos = this.activeHandle.position;
29500 w = Math.min(Math.max(mw, w), mxw);
29505 h = Math.min(Math.max(mh, h), mxh);
29510 w = Math.min(Math.max(mw, w), mxw);
29511 h = Math.min(Math.max(mh, h), mxh);
29514 diffY = this.constrain(h, diffY, mh, mxh);
29521 var adiffX = Math.abs(diffX);
29522 var sub = (adiffX % wi); // how much
29523 if (sub > (wi/2)) { // far enough to snap
29524 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29526 // remove difference..
29527 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29531 x = Math.max(this.minX, x);
29534 diffX = this.constrain(w, diffX, mw, mxw);
29540 w = Math.min(Math.max(mw, w), mxw);
29541 diffY = this.constrain(h, diffY, mh, mxh);
29546 diffX = this.constrain(w, diffX, mw, mxw);
29547 diffY = this.constrain(h, diffY, mh, mxh);
29554 diffX = this.constrain(w, diffX, mw, mxw);
29556 h = Math.min(Math.max(mh, h), mxh);
29562 var sw = this.snap(w, wi, mw);
29563 var sh = this.snap(h, hi, mh);
29564 if(sw != w || sh != h){
29587 if(this.preserveRatio){
29592 h = Math.min(Math.max(mh, h), mxh);
29597 w = Math.min(Math.max(mw, w), mxw);
29602 w = Math.min(Math.max(mw, w), mxw);
29608 w = Math.min(Math.max(mw, w), mxw);
29614 h = Math.min(Math.max(mh, h), mxh);
29622 h = Math.min(Math.max(mh, h), mxh);
29632 h = Math.min(Math.max(mh, h), mxh);
29640 if (pos == 'hdrag') {
29643 this.proxy.setBounds(x, y, w, h);
29645 this.resizeElement();
29649 this.fireEvent("resizing", this, x, y, w, h, e);
29653 handleOver : function(){
29655 this.el.addClass("x-resizable-over");
29660 handleOut : function(){
29661 if(!this.resizing){
29662 this.el.removeClass("x-resizable-over");
29667 * Returns the element this component is bound to.
29668 * @return {Roo.Element}
29670 getEl : function(){
29675 * Returns the resizeChild element (or null).
29676 * @return {Roo.Element}
29678 getResizeChild : function(){
29679 return this.resizeChild;
29681 groupHandler : function()
29686 * Destroys this resizable. If the element was wrapped and
29687 * removeEl is not true then the element remains.
29688 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29690 destroy : function(removeEl){
29691 this.proxy.remove();
29693 this.overlay.removeAllListeners();
29694 this.overlay.remove();
29696 var ps = Roo.Resizable.positions;
29698 if(typeof ps[k] != "function" && this[ps[k]]){
29699 var h = this[ps[k]];
29700 h.el.removeAllListeners();
29705 this.el.update("");
29712 // hash to map config positions to true positions
29713 Roo.Resizable.positions = {
29714 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29719 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29721 // only initialize the template if resizable is used
29722 var tpl = Roo.DomHelper.createTemplate(
29723 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29726 Roo.Resizable.Handle.prototype.tpl = tpl;
29728 this.position = pos;
29730 // show north drag fro topdra
29731 var handlepos = pos == 'hdrag' ? 'north' : pos;
29733 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29734 if (pos == 'hdrag') {
29735 this.el.setStyle('cursor', 'pointer');
29737 this.el.unselectable();
29739 this.el.setOpacity(0);
29741 this.el.on("mousedown", this.onMouseDown, this);
29742 if(!disableTrackOver){
29743 this.el.on("mouseover", this.onMouseOver, this);
29744 this.el.on("mouseout", this.onMouseOut, this);
29749 Roo.Resizable.Handle.prototype = {
29750 afterResize : function(rz){
29755 onMouseDown : function(e){
29756 this.rz.onMouseDown(this, e);
29759 onMouseOver : function(e){
29760 this.rz.handleOver(this, e);
29763 onMouseOut : function(e){
29764 this.rz.handleOut(this, e);
29768 * Ext JS Library 1.1.1
29769 * Copyright(c) 2006-2007, Ext JS, LLC.
29771 * Originally Released Under LGPL - original licence link has changed is not relivant.
29774 * <script type="text/javascript">
29778 * @class Roo.Editor
29779 * @extends Roo.Component
29780 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29782 * Create a new Editor
29783 * @param {Roo.form.Field} field The Field object (or descendant)
29784 * @param {Object} config The config object
29786 Roo.Editor = function(field, config){
29787 Roo.Editor.superclass.constructor.call(this, config);
29788 this.field = field;
29791 * @event beforestartedit
29792 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29793 * false from the handler of this event.
29794 * @param {Editor} this
29795 * @param {Roo.Element} boundEl The underlying element bound to this editor
29796 * @param {Mixed} value The field value being set
29798 "beforestartedit" : true,
29801 * Fires when this editor is displayed
29802 * @param {Roo.Element} boundEl The underlying element bound to this editor
29803 * @param {Mixed} value The starting field value
29805 "startedit" : true,
29807 * @event beforecomplete
29808 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29809 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29810 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29811 * event will not fire since no edit actually occurred.
29812 * @param {Editor} this
29813 * @param {Mixed} value The current field value
29814 * @param {Mixed} startValue The original field value
29816 "beforecomplete" : true,
29819 * Fires after editing is complete and any changed value has been written to the underlying field.
29820 * @param {Editor} this
29821 * @param {Mixed} value The current field value
29822 * @param {Mixed} startValue The original field value
29826 * @event specialkey
29827 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29828 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29829 * @param {Roo.form.Field} this
29830 * @param {Roo.EventObject} e The event object
29832 "specialkey" : true
29836 Roo.extend(Roo.Editor, Roo.Component, {
29838 * @cfg {Boolean/String} autosize
29839 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29840 * or "height" to adopt the height only (defaults to false)
29843 * @cfg {Boolean} revertInvalid
29844 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29845 * validation fails (defaults to true)
29848 * @cfg {Boolean} ignoreNoChange
29849 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29850 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29851 * will never be ignored.
29854 * @cfg {Boolean} hideEl
29855 * False to keep the bound element visible while the editor is displayed (defaults to true)
29858 * @cfg {Mixed} value
29859 * The data value of the underlying field (defaults to "")
29863 * @cfg {String} alignment
29864 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29868 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29869 * for bottom-right shadow (defaults to "frame")
29873 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29877 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29879 completeOnEnter : false,
29881 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29883 cancelOnEsc : false,
29885 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29890 onRender : function(ct, position){
29891 this.el = new Roo.Layer({
29892 shadow: this.shadow,
29898 constrain: this.constrain
29900 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29901 if(this.field.msgTarget != 'title'){
29902 this.field.msgTarget = 'qtip';
29904 this.field.render(this.el);
29906 this.field.el.dom.setAttribute('autocomplete', 'off');
29908 this.field.on("specialkey", this.onSpecialKey, this);
29909 if(this.swallowKeys){
29910 this.field.el.swallowEvent(['keydown','keypress']);
29913 this.field.on("blur", this.onBlur, this);
29914 if(this.field.grow){
29915 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29919 onSpecialKey : function(field, e)
29921 //Roo.log('editor onSpecialKey');
29922 if(this.completeOnEnter && e.getKey() == e.ENTER){
29924 this.completeEdit();
29927 // do not fire special key otherwise it might hide close the editor...
29928 if(e.getKey() == e.ENTER){
29931 if(this.cancelOnEsc && e.getKey() == e.ESC){
29935 this.fireEvent('specialkey', field, e);
29940 * Starts the editing process and shows the editor.
29941 * @param {String/HTMLElement/Element} el The element to edit
29942 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29943 * to the innerHTML of el.
29945 startEdit : function(el, value){
29947 this.completeEdit();
29949 this.boundEl = Roo.get(el);
29950 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29951 if(!this.rendered){
29952 this.render(this.parentEl || document.body);
29954 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29957 this.startValue = v;
29958 this.field.setValue(v);
29960 var sz = this.boundEl.getSize();
29961 switch(this.autoSize){
29963 this.setSize(sz.width, "");
29966 this.setSize("", sz.height);
29969 this.setSize(sz.width, sz.height);
29972 this.el.alignTo(this.boundEl, this.alignment);
29973 this.editing = true;
29975 Roo.QuickTips.disable();
29981 * Sets the height and width of this editor.
29982 * @param {Number} width The new width
29983 * @param {Number} height The new height
29985 setSize : function(w, h){
29986 this.field.setSize(w, h);
29993 * Realigns the editor to the bound field based on the current alignment config value.
29995 realign : function(){
29996 this.el.alignTo(this.boundEl, this.alignment);
30000 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30001 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30003 completeEdit : function(remainVisible){
30007 var v = this.getValue();
30008 if(this.revertInvalid !== false && !this.field.isValid()){
30009 v = this.startValue;
30010 this.cancelEdit(true);
30012 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30013 this.editing = false;
30017 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30018 this.editing = false;
30019 if(this.updateEl && this.boundEl){
30020 this.boundEl.update(v);
30022 if(remainVisible !== true){
30025 this.fireEvent("complete", this, v, this.startValue);
30030 onShow : function(){
30032 if(this.hideEl !== false){
30033 this.boundEl.hide();
30036 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30037 this.fixIEFocus = true;
30038 this.deferredFocus.defer(50, this);
30040 this.field.focus();
30042 this.fireEvent("startedit", this.boundEl, this.startValue);
30045 deferredFocus : function(){
30047 this.field.focus();
30052 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30053 * reverted to the original starting value.
30054 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30055 * cancel (defaults to false)
30057 cancelEdit : function(remainVisible){
30059 this.setValue(this.startValue);
30060 if(remainVisible !== true){
30067 onBlur : function(){
30068 if(this.allowBlur !== true && this.editing){
30069 this.completeEdit();
30074 onHide : function(){
30076 this.completeEdit();
30080 if(this.field.collapse){
30081 this.field.collapse();
30084 if(this.hideEl !== false){
30085 this.boundEl.show();
30088 Roo.QuickTips.enable();
30093 * Sets the data value of the editor
30094 * @param {Mixed} value Any valid value supported by the underlying field
30096 setValue : function(v){
30097 this.field.setValue(v);
30101 * Gets the data value of the editor
30102 * @return {Mixed} The data value
30104 getValue : function(){
30105 return this.field.getValue();
30109 * Ext JS Library 1.1.1
30110 * Copyright(c) 2006-2007, Ext JS, LLC.
30112 * Originally Released Under LGPL - original licence link has changed is not relivant.
30115 * <script type="text/javascript">
30119 * @class Roo.BasicDialog
30120 * @extends Roo.util.Observable
30121 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30123 var dlg = new Roo.BasicDialog("my-dlg", {
30132 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30133 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30134 dlg.addButton('Cancel', dlg.hide, dlg);
30137 <b>A Dialog should always be a direct child of the body element.</b>
30138 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30139 * @cfg {String} title Default text to display in the title bar (defaults to null)
30140 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30141 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30142 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30143 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30144 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30145 * (defaults to null with no animation)
30146 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30147 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30148 * property for valid values (defaults to 'all')
30149 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30150 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30151 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30152 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30153 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30154 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30155 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30156 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30157 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30158 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30159 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30160 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30161 * draggable = true (defaults to false)
30162 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30163 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30164 * shadow (defaults to false)
30165 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30166 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30167 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30168 * @cfg {Array} buttons Array of buttons
30169 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30171 * Create a new BasicDialog.
30172 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30173 * @param {Object} config Configuration options
30175 Roo.BasicDialog = function(el, config){
30176 this.el = Roo.get(el);
30177 var dh = Roo.DomHelper;
30178 if(!this.el && config && config.autoCreate){
30179 if(typeof config.autoCreate == "object"){
30180 if(!config.autoCreate.id){
30181 config.autoCreate.id = el;
30183 this.el = dh.append(document.body,
30184 config.autoCreate, true);
30186 this.el = dh.append(document.body,
30187 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30191 el.setDisplayed(true);
30192 el.hide = this.hideAction;
30194 el.addClass("x-dlg");
30196 Roo.apply(this, config);
30198 this.proxy = el.createProxy("x-dlg-proxy");
30199 this.proxy.hide = this.hideAction;
30200 this.proxy.setOpacity(.5);
30204 el.setWidth(config.width);
30207 el.setHeight(config.height);
30209 this.size = el.getSize();
30210 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30211 this.xy = [config.x,config.y];
30213 this.xy = el.getCenterXY(true);
30215 /** The header element @type Roo.Element */
30216 this.header = el.child("> .x-dlg-hd");
30217 /** The body element @type Roo.Element */
30218 this.body = el.child("> .x-dlg-bd");
30219 /** The footer element @type Roo.Element */
30220 this.footer = el.child("> .x-dlg-ft");
30223 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30226 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30229 this.header.unselectable();
30231 this.header.update(this.title);
30233 // this element allows the dialog to be focused for keyboard event
30234 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30235 this.focusEl.swallowEvent("click", true);
30237 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30239 // wrap the body and footer for special rendering
30240 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30242 this.bwrap.dom.appendChild(this.footer.dom);
30245 this.bg = this.el.createChild({
30246 tag: "div", cls:"x-dlg-bg",
30247 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30249 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30252 if(this.autoScroll !== false && !this.autoTabs){
30253 this.body.setStyle("overflow", "auto");
30256 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30258 if(this.closable !== false){
30259 this.el.addClass("x-dlg-closable");
30260 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30261 this.close.on("click", this.closeClick, this);
30262 this.close.addClassOnOver("x-dlg-close-over");
30264 if(this.collapsible !== false){
30265 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30266 this.collapseBtn.on("click", this.collapseClick, this);
30267 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30268 this.header.on("dblclick", this.collapseClick, this);
30270 if(this.resizable !== false){
30271 this.el.addClass("x-dlg-resizable");
30272 this.resizer = new Roo.Resizable(el, {
30273 minWidth: this.minWidth || 80,
30274 minHeight:this.minHeight || 80,
30275 handles: this.resizeHandles || "all",
30278 this.resizer.on("beforeresize", this.beforeResize, this);
30279 this.resizer.on("resize", this.onResize, this);
30281 if(this.draggable !== false){
30282 el.addClass("x-dlg-draggable");
30283 if (!this.proxyDrag) {
30284 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30287 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30289 dd.setHandleElId(this.header.id);
30290 dd.endDrag = this.endMove.createDelegate(this);
30291 dd.startDrag = this.startMove.createDelegate(this);
30292 dd.onDrag = this.onDrag.createDelegate(this);
30297 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30298 this.mask.enableDisplayMode("block");
30300 this.el.addClass("x-dlg-modal");
30303 this.shadow = new Roo.Shadow({
30304 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30305 offset : this.shadowOffset
30308 this.shadowOffset = 0;
30310 if(Roo.useShims && this.shim !== false){
30311 this.shim = this.el.createShim();
30312 this.shim.hide = this.hideAction;
30320 if (this.buttons) {
30321 var bts= this.buttons;
30323 Roo.each(bts, function(b) {
30332 * Fires when a key is pressed
30333 * @param {Roo.BasicDialog} this
30334 * @param {Roo.EventObject} e
30339 * Fires when this dialog is moved by the user.
30340 * @param {Roo.BasicDialog} this
30341 * @param {Number} x The new page X
30342 * @param {Number} y The new page Y
30347 * Fires when this dialog is resized by the user.
30348 * @param {Roo.BasicDialog} this
30349 * @param {Number} width The new width
30350 * @param {Number} height The new height
30354 * @event beforehide
30355 * Fires before this dialog is hidden.
30356 * @param {Roo.BasicDialog} this
30358 "beforehide" : true,
30361 * Fires when this dialog is hidden.
30362 * @param {Roo.BasicDialog} this
30366 * @event beforeshow
30367 * Fires before this dialog is shown.
30368 * @param {Roo.BasicDialog} this
30370 "beforeshow" : true,
30373 * Fires when this dialog is shown.
30374 * @param {Roo.BasicDialog} this
30378 el.on("keydown", this.onKeyDown, this);
30379 el.on("mousedown", this.toFront, this);
30380 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30382 Roo.DialogManager.register(this);
30383 Roo.BasicDialog.superclass.constructor.call(this);
30386 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30387 shadowOffset: Roo.isIE ? 6 : 5,
30390 minButtonWidth: 75,
30391 defaultButton: null,
30392 buttonAlign: "right",
30397 * Sets the dialog title text
30398 * @param {String} text The title text to display
30399 * @return {Roo.BasicDialog} this
30401 setTitle : function(text){
30402 this.header.update(text);
30407 closeClick : function(){
30412 collapseClick : function(){
30413 this[this.collapsed ? "expand" : "collapse"]();
30417 * Collapses the dialog to its minimized state (only the title bar is visible).
30418 * Equivalent to the user clicking the collapse dialog button.
30420 collapse : function(){
30421 if(!this.collapsed){
30422 this.collapsed = true;
30423 this.el.addClass("x-dlg-collapsed");
30424 this.restoreHeight = this.el.getHeight();
30425 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30430 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30431 * clicking the expand dialog button.
30433 expand : function(){
30434 if(this.collapsed){
30435 this.collapsed = false;
30436 this.el.removeClass("x-dlg-collapsed");
30437 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30442 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30443 * @return {Roo.TabPanel} The tabs component
30445 initTabs : function(){
30446 var tabs = this.getTabs();
30447 while(tabs.getTab(0)){
30450 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30452 tabs.addTab(Roo.id(dom), dom.title);
30460 beforeResize : function(){
30461 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30465 onResize : function(){
30466 this.refreshSize();
30467 this.syncBodyHeight();
30468 this.adjustAssets();
30470 this.fireEvent("resize", this, this.size.width, this.size.height);
30474 onKeyDown : function(e){
30475 if(this.isVisible()){
30476 this.fireEvent("keydown", this, e);
30481 * Resizes the dialog.
30482 * @param {Number} width
30483 * @param {Number} height
30484 * @return {Roo.BasicDialog} this
30486 resizeTo : function(width, height){
30487 this.el.setSize(width, height);
30488 this.size = {width: width, height: height};
30489 this.syncBodyHeight();
30490 if(this.fixedcenter){
30493 if(this.isVisible()){
30494 this.constrainXY();
30495 this.adjustAssets();
30497 this.fireEvent("resize", this, width, height);
30503 * Resizes the dialog to fit the specified content size.
30504 * @param {Number} width
30505 * @param {Number} height
30506 * @return {Roo.BasicDialog} this
30508 setContentSize : function(w, h){
30509 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30510 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30511 //if(!this.el.isBorderBox()){
30512 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30513 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30516 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30517 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30519 this.resizeTo(w, h);
30524 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30525 * executed in response to a particular key being pressed while the dialog is active.
30526 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30527 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30528 * @param {Function} fn The function to call
30529 * @param {Object} scope (optional) The scope of the function
30530 * @return {Roo.BasicDialog} this
30532 addKeyListener : function(key, fn, scope){
30533 var keyCode, shift, ctrl, alt;
30534 if(typeof key == "object" && !(key instanceof Array)){
30535 keyCode = key["key"];
30536 shift = key["shift"];
30537 ctrl = key["ctrl"];
30542 var handler = function(dlg, e){
30543 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30544 var k = e.getKey();
30545 if(keyCode instanceof Array){
30546 for(var i = 0, len = keyCode.length; i < len; i++){
30547 if(keyCode[i] == k){
30548 fn.call(scope || window, dlg, k, e);
30554 fn.call(scope || window, dlg, k, e);
30559 this.on("keydown", handler);
30564 * Returns the TabPanel component (creates it if it doesn't exist).
30565 * Note: If you wish to simply check for the existence of tabs without creating them,
30566 * check for a null 'tabs' property.
30567 * @return {Roo.TabPanel} The tabs component
30569 getTabs : function(){
30571 this.el.addClass("x-dlg-auto-tabs");
30572 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30573 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30579 * Adds a button to the footer section of the dialog.
30580 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30581 * object or a valid Roo.DomHelper element config
30582 * @param {Function} handler The function called when the button is clicked
30583 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30584 * @return {Roo.Button} The new button
30586 addButton : function(config, handler, scope){
30587 var dh = Roo.DomHelper;
30589 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30591 if(!this.btnContainer){
30592 var tb = this.footer.createChild({
30594 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30595 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30597 this.btnContainer = tb.firstChild.firstChild.firstChild;
30602 minWidth: this.minButtonWidth,
30605 if(typeof config == "string"){
30606 bconfig.text = config;
30609 bconfig.dhconfig = config;
30611 Roo.apply(bconfig, config);
30615 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30616 bconfig.position = Math.max(0, bconfig.position);
30617 fc = this.btnContainer.childNodes[bconfig.position];
30620 var btn = new Roo.Button(
30622 this.btnContainer.insertBefore(document.createElement("td"),fc)
30623 : this.btnContainer.appendChild(document.createElement("td")),
30624 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30627 this.syncBodyHeight();
30630 * Array of all the buttons that have been added to this dialog via addButton
30635 this.buttons.push(btn);
30640 * Sets the default button to be focused when the dialog is displayed.
30641 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30642 * @return {Roo.BasicDialog} this
30644 setDefaultButton : function(btn){
30645 this.defaultButton = btn;
30650 getHeaderFooterHeight : function(safe){
30653 height += this.header.getHeight();
30656 var fm = this.footer.getMargins();
30657 height += (this.footer.getHeight()+fm.top+fm.bottom);
30659 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30660 height += this.centerBg.getPadding("tb");
30665 syncBodyHeight : function()
30667 var bd = this.body, // the text
30668 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30670 var height = this.size.height - this.getHeaderFooterHeight(false);
30671 bd.setHeight(height-bd.getMargins("tb"));
30672 var hh = this.header.getHeight();
30673 var h = this.size.height-hh;
30676 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30677 bw.setHeight(h-cb.getPadding("tb"));
30679 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30680 bd.setWidth(bw.getWidth(true));
30682 this.tabs.syncHeight();
30684 this.tabs.el.repaint();
30690 * Restores the previous state of the dialog if Roo.state is configured.
30691 * @return {Roo.BasicDialog} this
30693 restoreState : function(){
30694 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30695 if(box && box.width){
30696 this.xy = [box.x, box.y];
30697 this.resizeTo(box.width, box.height);
30703 beforeShow : function(){
30705 if(this.fixedcenter){
30706 this.xy = this.el.getCenterXY(true);
30709 Roo.get(document.body).addClass("x-body-masked");
30710 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30713 this.constrainXY();
30717 animShow : function(){
30718 var b = Roo.get(this.animateTarget).getBox();
30719 this.proxy.setSize(b.width, b.height);
30720 this.proxy.setLocation(b.x, b.y);
30722 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30723 true, .35, this.showEl.createDelegate(this));
30727 * Shows the dialog.
30728 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30729 * @return {Roo.BasicDialog} this
30731 show : function(animateTarget){
30732 if (this.fireEvent("beforeshow", this) === false){
30735 if(this.syncHeightBeforeShow){
30736 this.syncBodyHeight();
30737 }else if(this.firstShow){
30738 this.firstShow = false;
30739 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30741 this.animateTarget = animateTarget || this.animateTarget;
30742 if(!this.el.isVisible()){
30744 if(this.animateTarget && Roo.get(this.animateTarget)){
30754 showEl : function(){
30756 this.el.setXY(this.xy);
30758 this.adjustAssets(true);
30761 // IE peekaboo bug - fix found by Dave Fenwick
30765 this.fireEvent("show", this);
30769 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30770 * dialog itself will receive focus.
30772 focus : function(){
30773 if(this.defaultButton){
30774 this.defaultButton.focus();
30776 this.focusEl.focus();
30781 constrainXY : function(){
30782 if(this.constraintoviewport !== false){
30783 if(!this.viewSize){
30784 if(this.container){
30785 var s = this.container.getSize();
30786 this.viewSize = [s.width, s.height];
30788 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30791 var s = Roo.get(this.container||document).getScroll();
30793 var x = this.xy[0], y = this.xy[1];
30794 var w = this.size.width, h = this.size.height;
30795 var vw = this.viewSize[0], vh = this.viewSize[1];
30796 // only move it if it needs it
30798 // first validate right/bottom
30799 if(x + w > vw+s.left){
30803 if(y + h > vh+s.top){
30807 // then make sure top/left isn't negative
30819 if(this.isVisible()){
30820 this.el.setLocation(x, y);
30821 this.adjustAssets();
30828 onDrag : function(){
30829 if(!this.proxyDrag){
30830 this.xy = this.el.getXY();
30831 this.adjustAssets();
30836 adjustAssets : function(doShow){
30837 var x = this.xy[0], y = this.xy[1];
30838 var w = this.size.width, h = this.size.height;
30839 if(doShow === true){
30841 this.shadow.show(this.el);
30847 if(this.shadow && this.shadow.isVisible()){
30848 this.shadow.show(this.el);
30850 if(this.shim && this.shim.isVisible()){
30851 this.shim.setBounds(x, y, w, h);
30856 adjustViewport : function(w, h){
30858 w = Roo.lib.Dom.getViewWidth();
30859 h = Roo.lib.Dom.getViewHeight();
30862 this.viewSize = [w, h];
30863 if(this.modal && this.mask.isVisible()){
30864 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30865 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30867 if(this.isVisible()){
30868 this.constrainXY();
30873 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30874 * shadow, proxy, mask, etc.) Also removes all event listeners.
30875 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30877 destroy : function(removeEl){
30878 if(this.isVisible()){
30879 this.animateTarget = null;
30882 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30884 this.tabs.destroy(removeEl);
30897 for(var i = 0, len = this.buttons.length; i < len; i++){
30898 this.buttons[i].destroy();
30901 this.el.removeAllListeners();
30902 if(removeEl === true){
30903 this.el.update("");
30906 Roo.DialogManager.unregister(this);
30910 startMove : function(){
30911 if(this.proxyDrag){
30914 if(this.constraintoviewport !== false){
30915 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30920 endMove : function(){
30921 if(!this.proxyDrag){
30922 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30924 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30927 this.refreshSize();
30928 this.adjustAssets();
30930 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30934 * Brings this dialog to the front of any other visible dialogs
30935 * @return {Roo.BasicDialog} this
30937 toFront : function(){
30938 Roo.DialogManager.bringToFront(this);
30943 * Sends this dialog to the back (under) of any other visible dialogs
30944 * @return {Roo.BasicDialog} this
30946 toBack : function(){
30947 Roo.DialogManager.sendToBack(this);
30952 * Centers this dialog in the viewport
30953 * @return {Roo.BasicDialog} this
30955 center : function(){
30956 var xy = this.el.getCenterXY(true);
30957 this.moveTo(xy[0], xy[1]);
30962 * Moves the dialog's top-left corner to the specified point
30963 * @param {Number} x
30964 * @param {Number} y
30965 * @return {Roo.BasicDialog} this
30967 moveTo : function(x, y){
30969 if(this.isVisible()){
30970 this.el.setXY(this.xy);
30971 this.adjustAssets();
30977 * Aligns the dialog to the specified element
30978 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30979 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30980 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30981 * @return {Roo.BasicDialog} this
30983 alignTo : function(element, position, offsets){
30984 this.xy = this.el.getAlignToXY(element, position, offsets);
30985 if(this.isVisible()){
30986 this.el.setXY(this.xy);
30987 this.adjustAssets();
30993 * Anchors an element to another element and realigns it when the window is resized.
30994 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30995 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30996 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30997 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30998 * is a number, it is used as the buffer delay (defaults to 50ms).
30999 * @return {Roo.BasicDialog} this
31001 anchorTo : function(el, alignment, offsets, monitorScroll){
31002 var action = function(){
31003 this.alignTo(el, alignment, offsets);
31005 Roo.EventManager.onWindowResize(action, this);
31006 var tm = typeof monitorScroll;
31007 if(tm != 'undefined'){
31008 Roo.EventManager.on(window, 'scroll', action, this,
31009 {buffer: tm == 'number' ? monitorScroll : 50});
31016 * Returns true if the dialog is visible
31017 * @return {Boolean}
31019 isVisible : function(){
31020 return this.el.isVisible();
31024 animHide : function(callback){
31025 var b = Roo.get(this.animateTarget).getBox();
31027 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31029 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31030 this.hideEl.createDelegate(this, [callback]));
31034 * Hides the dialog.
31035 * @param {Function} callback (optional) Function to call when the dialog is hidden
31036 * @return {Roo.BasicDialog} this
31038 hide : function(callback){
31039 if (this.fireEvent("beforehide", this) === false){
31043 this.shadow.hide();
31048 // sometimes animateTarget seems to get set.. causing problems...
31049 // this just double checks..
31050 if(this.animateTarget && Roo.get(this.animateTarget)) {
31051 this.animHide(callback);
31054 this.hideEl(callback);
31060 hideEl : function(callback){
31064 Roo.get(document.body).removeClass("x-body-masked");
31066 this.fireEvent("hide", this);
31067 if(typeof callback == "function"){
31073 hideAction : function(){
31074 this.setLeft("-10000px");
31075 this.setTop("-10000px");
31076 this.setStyle("visibility", "hidden");
31080 refreshSize : function(){
31081 this.size = this.el.getSize();
31082 this.xy = this.el.getXY();
31083 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31087 // z-index is managed by the DialogManager and may be overwritten at any time
31088 setZIndex : function(index){
31090 this.mask.setStyle("z-index", index);
31093 this.shim.setStyle("z-index", ++index);
31096 this.shadow.setZIndex(++index);
31098 this.el.setStyle("z-index", ++index);
31100 this.proxy.setStyle("z-index", ++index);
31103 this.resizer.proxy.setStyle("z-index", ++index);
31106 this.lastZIndex = index;
31110 * Returns the element for this dialog
31111 * @return {Roo.Element} The underlying dialog Element
31113 getEl : function(){
31119 * @class Roo.DialogManager
31120 * Provides global access to BasicDialogs that have been created and
31121 * support for z-indexing (layering) multiple open dialogs.
31123 Roo.DialogManager = function(){
31125 var accessList = [];
31129 var sortDialogs = function(d1, d2){
31130 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31134 var orderDialogs = function(){
31135 accessList.sort(sortDialogs);
31136 var seed = Roo.DialogManager.zseed;
31137 for(var i = 0, len = accessList.length; i < len; i++){
31138 var dlg = accessList[i];
31140 dlg.setZIndex(seed + (i*10));
31147 * The starting z-index for BasicDialogs (defaults to 9000)
31148 * @type Number The z-index value
31153 register : function(dlg){
31154 list[dlg.id] = dlg;
31155 accessList.push(dlg);
31159 unregister : function(dlg){
31160 delete list[dlg.id];
31163 if(!accessList.indexOf){
31164 for( i = 0, len = accessList.length; i < len; i++){
31165 if(accessList[i] == dlg){
31166 accessList.splice(i, 1);
31171 i = accessList.indexOf(dlg);
31173 accessList.splice(i, 1);
31179 * Gets a registered dialog by id
31180 * @param {String/Object} id The id of the dialog or a dialog
31181 * @return {Roo.BasicDialog} this
31183 get : function(id){
31184 return typeof id == "object" ? id : list[id];
31188 * Brings the specified dialog to the front
31189 * @param {String/Object} dlg The id of the dialog or a dialog
31190 * @return {Roo.BasicDialog} this
31192 bringToFront : function(dlg){
31193 dlg = this.get(dlg);
31196 dlg._lastAccess = new Date().getTime();
31203 * Sends the specified dialog to the back
31204 * @param {String/Object} dlg The id of the dialog or a dialog
31205 * @return {Roo.BasicDialog} this
31207 sendToBack : function(dlg){
31208 dlg = this.get(dlg);
31209 dlg._lastAccess = -(new Date().getTime());
31215 * Hides all dialogs
31217 hideAll : function(){
31218 for(var id in list){
31219 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31228 * @class Roo.LayoutDialog
31229 * @extends Roo.BasicDialog
31230 * Dialog which provides adjustments for working with a layout in a Dialog.
31231 * Add your necessary layout config options to the dialog's config.<br>
31232 * Example usage (including a nested layout):
31235 dialog = new Roo.LayoutDialog("download-dlg", {
31244 // layout config merges with the dialog config
31246 tabPosition: "top",
31247 alwaysShowTabs: true
31250 dialog.addKeyListener(27, dialog.hide, dialog);
31251 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31252 dialog.addButton("Build It!", this.getDownload, this);
31254 // we can even add nested layouts
31255 var innerLayout = new Roo.BorderLayout("dl-inner", {
31265 innerLayout.beginUpdate();
31266 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31267 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31268 innerLayout.endUpdate(true);
31270 var layout = dialog.getLayout();
31271 layout.beginUpdate();
31272 layout.add("center", new Roo.ContentPanel("standard-panel",
31273 {title: "Download the Source", fitToFrame:true}));
31274 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31275 {title: "Build your own roo.js"}));
31276 layout.getRegion("center").showPanel(sp);
31277 layout.endUpdate();
31281 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31282 * @param {Object} config configuration options
31284 Roo.LayoutDialog = function(el, cfg){
31287 if (typeof(cfg) == 'undefined') {
31288 config = Roo.apply({}, el);
31289 // not sure why we use documentElement here.. - it should always be body.
31290 // IE7 borks horribly if we use documentElement.
31291 // webkit also does not like documentElement - it creates a body element...
31292 el = Roo.get( document.body || document.documentElement ).createChild();
31293 //config.autoCreate = true;
31297 config.autoTabs = false;
31298 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31299 this.body.setStyle({overflow:"hidden", position:"relative"});
31300 this.layout = new Roo.BorderLayout(this.body.dom, config);
31301 this.layout.monitorWindowResize = false;
31302 this.el.addClass("x-dlg-auto-layout");
31303 // fix case when center region overwrites center function
31304 this.center = Roo.BasicDialog.prototype.center;
31305 this.on("show", this.layout.layout, this.layout, true);
31306 if (config.items) {
31307 var xitems = config.items;
31308 delete config.items;
31309 Roo.each(xitems, this.addxtype, this);
31314 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31316 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31319 endUpdate : function(){
31320 this.layout.endUpdate();
31324 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31327 beginUpdate : function(){
31328 this.layout.beginUpdate();
31332 * Get the BorderLayout for this dialog
31333 * @return {Roo.BorderLayout}
31335 getLayout : function(){
31336 return this.layout;
31339 showEl : function(){
31340 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31342 this.layout.layout();
31347 // Use the syncHeightBeforeShow config option to control this automatically
31348 syncBodyHeight : function(){
31349 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31350 if(this.layout){this.layout.layout();}
31354 * Add an xtype element (actually adds to the layout.)
31355 * @return {Object} xdata xtype object data.
31358 addxtype : function(c) {
31359 return this.layout.addxtype(c);
31363 * Ext JS Library 1.1.1
31364 * Copyright(c) 2006-2007, Ext JS, LLC.
31366 * Originally Released Under LGPL - original licence link has changed is not relivant.
31369 * <script type="text/javascript">
31373 * @class Roo.MessageBox
31374 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31378 Roo.Msg.alert('Status', 'Changes saved successfully.');
31380 // Prompt for user data:
31381 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31383 // process text value...
31387 // Show a dialog using config options:
31389 title:'Save Changes?',
31390 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31391 buttons: Roo.Msg.YESNOCANCEL,
31398 Roo.MessageBox = function(){
31399 var dlg, opt, mask, waitTimer;
31400 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31401 var buttons, activeTextEl, bwidth;
31404 var handleButton = function(button){
31406 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31410 var handleHide = function(){
31411 if(opt && opt.cls){
31412 dlg.el.removeClass(opt.cls);
31415 Roo.TaskMgr.stop(waitTimer);
31421 var updateButtons = function(b){
31424 buttons["ok"].hide();
31425 buttons["cancel"].hide();
31426 buttons["yes"].hide();
31427 buttons["no"].hide();
31428 dlg.footer.dom.style.display = 'none';
31431 dlg.footer.dom.style.display = '';
31432 for(var k in buttons){
31433 if(typeof buttons[k] != "function"){
31436 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31437 width += buttons[k].el.getWidth()+15;
31447 var handleEsc = function(d, k, e){
31448 if(opt && opt.closable !== false){
31458 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31459 * @return {Roo.BasicDialog} The BasicDialog element
31461 getDialog : function(){
31463 dlg = new Roo.BasicDialog("x-msg-box", {
31468 constraintoviewport:false,
31470 collapsible : false,
31473 width:400, height:100,
31474 buttonAlign:"center",
31475 closeClick : function(){
31476 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31477 handleButton("no");
31479 handleButton("cancel");
31483 dlg.on("hide", handleHide);
31485 dlg.addKeyListener(27, handleEsc);
31487 var bt = this.buttonText;
31488 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31489 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31490 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31491 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31492 bodyEl = dlg.body.createChild({
31494 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>'
31496 msgEl = bodyEl.dom.firstChild;
31497 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31498 textboxEl.enableDisplayMode();
31499 textboxEl.addKeyListener([10,13], function(){
31500 if(dlg.isVisible() && opt && opt.buttons){
31501 if(opt.buttons.ok){
31502 handleButton("ok");
31503 }else if(opt.buttons.yes){
31504 handleButton("yes");
31508 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31509 textareaEl.enableDisplayMode();
31510 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31511 progressEl.enableDisplayMode();
31512 var pf = progressEl.dom.firstChild;
31514 pp = Roo.get(pf.firstChild);
31515 pp.setHeight(pf.offsetHeight);
31523 * Updates the message box body text
31524 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31525 * the XHTML-compliant non-breaking space character '&#160;')
31526 * @return {Roo.MessageBox} This message box
31528 updateText : function(text){
31529 if(!dlg.isVisible() && !opt.width){
31530 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31532 msgEl.innerHTML = text || ' ';
31534 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31535 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31537 Math.min(opt.width || cw , this.maxWidth),
31538 Math.max(opt.minWidth || this.minWidth, bwidth)
31541 activeTextEl.setWidth(w);
31543 if(dlg.isVisible()){
31544 dlg.fixedcenter = false;
31546 // to big, make it scroll. = But as usual stupid IE does not support
31549 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31550 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31551 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31553 bodyEl.dom.style.height = '';
31554 bodyEl.dom.style.overflowY = '';
31557 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31559 bodyEl.dom.style.overflowX = '';
31562 dlg.setContentSize(w, bodyEl.getHeight());
31563 if(dlg.isVisible()){
31564 dlg.fixedcenter = true;
31570 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31571 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31572 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31573 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31574 * @return {Roo.MessageBox} This message box
31576 updateProgress : function(value, text){
31578 this.updateText(text);
31580 if (pp) { // weird bug on my firefox - for some reason this is not defined
31581 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31587 * Returns true if the message box is currently displayed
31588 * @return {Boolean} True if the message box is visible, else false
31590 isVisible : function(){
31591 return dlg && dlg.isVisible();
31595 * Hides the message box if it is displayed
31598 if(this.isVisible()){
31604 * Displays a new message box, or reinitializes an existing message box, based on the config options
31605 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31606 * The following config object properties are supported:
31608 Property Type Description
31609 ---------- --------------- ------------------------------------------------------------------------------------
31610 animEl String/Element An id or Element from which the message box should animate as it opens and
31611 closes (defaults to undefined)
31612 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31613 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31614 closable Boolean False to hide the top-right close button (defaults to true). Note that
31615 progress and wait dialogs will ignore this property and always hide the
31616 close button as they can only be closed programmatically.
31617 cls String A custom CSS class to apply to the message box element
31618 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31619 displayed (defaults to 75)
31620 fn Function A callback function to execute after closing the dialog. The arguments to the
31621 function will be btn (the name of the button that was clicked, if applicable,
31622 e.g. "ok"), and text (the value of the active text field, if applicable).
31623 Progress and wait dialogs will ignore this option since they do not respond to
31624 user actions and can only be closed programmatically, so any required function
31625 should be called by the same code after it closes the dialog.
31626 icon String A CSS class that provides a background image to be used as an icon for
31627 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31628 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31629 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31630 modal Boolean False to allow user interaction with the page while the message box is
31631 displayed (defaults to true)
31632 msg String A string that will replace the existing message box body text (defaults
31633 to the XHTML-compliant non-breaking space character ' ')
31634 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31635 progress Boolean True to display a progress bar (defaults to false)
31636 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31637 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31638 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31639 title String The title text
31640 value String The string value to set into the active textbox element if displayed
31641 wait Boolean True to display a progress bar (defaults to false)
31642 width Number The width of the dialog in pixels
31649 msg: 'Please enter your address:',
31651 buttons: Roo.MessageBox.OKCANCEL,
31654 animEl: 'addAddressBtn'
31657 * @param {Object} config Configuration options
31658 * @return {Roo.MessageBox} This message box
31660 show : function(options)
31663 // this causes nightmares if you show one dialog after another
31664 // especially on callbacks..
31666 if(this.isVisible()){
31669 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31670 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31671 Roo.log("New Dialog Message:" + options.msg )
31672 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31673 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31676 var d = this.getDialog();
31678 d.setTitle(opt.title || " ");
31679 d.close.setDisplayed(opt.closable !== false);
31680 activeTextEl = textboxEl;
31681 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31686 textareaEl.setHeight(typeof opt.multiline == "number" ?
31687 opt.multiline : this.defaultTextHeight);
31688 activeTextEl = textareaEl;
31697 progressEl.setDisplayed(opt.progress === true);
31698 this.updateProgress(0);
31699 activeTextEl.dom.value = opt.value || "";
31701 dlg.setDefaultButton(activeTextEl);
31703 var bs = opt.buttons;
31706 db = buttons["ok"];
31707 }else if(bs && bs.yes){
31708 db = buttons["yes"];
31710 dlg.setDefaultButton(db);
31712 bwidth = updateButtons(opt.buttons);
31713 this.updateText(opt.msg);
31715 d.el.addClass(opt.cls);
31717 d.proxyDrag = opt.proxyDrag === true;
31718 d.modal = opt.modal !== false;
31719 d.mask = opt.modal !== false ? mask : false;
31720 if(!d.isVisible()){
31721 // force it to the end of the z-index stack so it gets a cursor in FF
31722 document.body.appendChild(dlg.el.dom);
31723 d.animateTarget = null;
31724 d.show(options.animEl);
31730 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31731 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31732 * and closing the message box when the process is complete.
31733 * @param {String} title The title bar text
31734 * @param {String} msg The message box body text
31735 * @return {Roo.MessageBox} This message box
31737 progress : function(title, msg){
31744 minWidth: this.minProgressWidth,
31751 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31752 * If a callback function is passed it will be called after the user clicks the button, and the
31753 * id of the button that was clicked will be passed as the only parameter to the callback
31754 * (could also be the top-right close button).
31755 * @param {String} title The title bar text
31756 * @param {String} msg The message box body text
31757 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31758 * @param {Object} scope (optional) The scope of the callback function
31759 * @return {Roo.MessageBox} This message box
31761 alert : function(title, msg, fn, scope){
31774 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31775 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31776 * You are responsible for closing the message box when the process is complete.
31777 * @param {String} msg The message box body text
31778 * @param {String} title (optional) The title bar text
31779 * @return {Roo.MessageBox} This message box
31781 wait : function(msg, title){
31792 waitTimer = Roo.TaskMgr.start({
31794 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31802 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31803 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31804 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31805 * @param {String} title The title bar text
31806 * @param {String} msg The message box body text
31807 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31808 * @param {Object} scope (optional) The scope of the callback function
31809 * @return {Roo.MessageBox} This message box
31811 confirm : function(title, msg, fn, scope){
31815 buttons: this.YESNO,
31824 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31825 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31826 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31827 * (could also be the top-right close button) and the text that was entered will be passed as the two
31828 * parameters to the callback.
31829 * @param {String} title The title bar text
31830 * @param {String} msg The message box body text
31831 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31832 * @param {Object} scope (optional) The scope of the callback function
31833 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31834 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31835 * @return {Roo.MessageBox} This message box
31837 prompt : function(title, msg, fn, scope, multiline){
31841 buttons: this.OKCANCEL,
31846 multiline: multiline,
31853 * Button config that displays a single OK button
31858 * Button config that displays Yes and No buttons
31861 YESNO : {yes:true, no:true},
31863 * Button config that displays OK and Cancel buttons
31866 OKCANCEL : {ok:true, cancel:true},
31868 * Button config that displays Yes, No and Cancel buttons
31871 YESNOCANCEL : {yes:true, no:true, cancel:true},
31874 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31877 defaultTextHeight : 75,
31879 * The maximum width in pixels of the message box (defaults to 600)
31884 * The minimum width in pixels of the message box (defaults to 100)
31889 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31890 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31893 minProgressWidth : 250,
31895 * An object containing the default button text strings that can be overriden for localized language support.
31896 * Supported properties are: ok, cancel, yes and no.
31897 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31910 * Shorthand for {@link Roo.MessageBox}
31912 Roo.Msg = Roo.MessageBox;/*
31914 * Ext JS Library 1.1.1
31915 * Copyright(c) 2006-2007, Ext JS, LLC.
31917 * Originally Released Under LGPL - original licence link has changed is not relivant.
31920 * <script type="text/javascript">
31923 * @class Roo.QuickTips
31924 * Provides attractive and customizable tooltips for any element.
31927 Roo.QuickTips = function(){
31928 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31929 var ce, bd, xy, dd;
31930 var visible = false, disabled = true, inited = false;
31931 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31933 var onOver = function(e){
31937 var t = e.getTarget();
31938 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31941 if(ce && t == ce.el){
31942 clearTimeout(hideProc);
31945 if(t && tagEls[t.id]){
31946 tagEls[t.id].el = t;
31947 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31950 var ttp, et = Roo.fly(t);
31951 var ns = cfg.namespace;
31952 if(tm.interceptTitles && t.title){
31955 t.removeAttribute("title");
31956 e.preventDefault();
31958 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31961 showProc = show.defer(tm.showDelay, tm, [{
31964 width: et.getAttributeNS(ns, cfg.width),
31965 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31966 title: et.getAttributeNS(ns, cfg.title),
31967 cls: et.getAttributeNS(ns, cfg.cls)
31972 var onOut = function(e){
31973 clearTimeout(showProc);
31974 var t = e.getTarget();
31975 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31976 hideProc = setTimeout(hide, tm.hideDelay);
31980 var onMove = function(e){
31986 if(tm.trackMouse && ce){
31991 var onDown = function(e){
31992 clearTimeout(showProc);
31993 clearTimeout(hideProc);
31995 if(tm.hideOnClick){
31998 tm.enable.defer(100, tm);
32003 var getPad = function(){
32004 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32007 var show = function(o){
32011 clearTimeout(dismissProc);
32013 if(removeCls){ // in case manually hidden
32014 el.removeClass(removeCls);
32018 el.addClass(ce.cls);
32019 removeCls = ce.cls;
32022 tipTitle.update(ce.title);
32025 tipTitle.update('');
32028 el.dom.style.width = tm.maxWidth+'px';
32029 //tipBody.dom.style.width = '';
32030 tipBodyText.update(o.text);
32031 var p = getPad(), w = ce.width;
32033 var td = tipBodyText.dom;
32034 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32035 if(aw > tm.maxWidth){
32037 }else if(aw < tm.minWidth){
32043 //tipBody.setWidth(w);
32044 el.setWidth(parseInt(w, 10) + p);
32045 if(ce.autoHide === false){
32046 close.setDisplayed(true);
32051 close.setDisplayed(false);
32057 el.avoidY = xy[1]-18;
32062 el.setStyle("visibility", "visible");
32063 el.fadeIn({callback: afterShow});
32069 var afterShow = function(){
32073 if(tm.autoDismiss && ce.autoHide !== false){
32074 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32079 var hide = function(noanim){
32080 clearTimeout(dismissProc);
32081 clearTimeout(hideProc);
32083 if(el.isVisible()){
32085 if(noanim !== true && tm.animate){
32086 el.fadeOut({callback: afterHide});
32093 var afterHide = function(){
32096 el.removeClass(removeCls);
32103 * @cfg {Number} minWidth
32104 * The minimum width of the quick tip (defaults to 40)
32108 * @cfg {Number} maxWidth
32109 * The maximum width of the quick tip (defaults to 300)
32113 * @cfg {Boolean} interceptTitles
32114 * True to automatically use the element's DOM title value if available (defaults to false)
32116 interceptTitles : false,
32118 * @cfg {Boolean} trackMouse
32119 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32121 trackMouse : false,
32123 * @cfg {Boolean} hideOnClick
32124 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32126 hideOnClick : true,
32128 * @cfg {Number} showDelay
32129 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32133 * @cfg {Number} hideDelay
32134 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32138 * @cfg {Boolean} autoHide
32139 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32140 * Used in conjunction with hideDelay.
32145 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32146 * (defaults to true). Used in conjunction with autoDismissDelay.
32148 autoDismiss : true,
32151 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32153 autoDismissDelay : 5000,
32155 * @cfg {Boolean} animate
32156 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32161 * @cfg {String} title
32162 * Title text to display (defaults to ''). This can be any valid HTML markup.
32166 * @cfg {String} text
32167 * Body text to display (defaults to ''). This can be any valid HTML markup.
32171 * @cfg {String} cls
32172 * A CSS class to apply to the base quick tip element (defaults to '').
32176 * @cfg {Number} width
32177 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32178 * minWidth or maxWidth.
32183 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32184 * or display QuickTips in a page.
32187 tm = Roo.QuickTips;
32188 cfg = tm.tagConfig;
32190 if(!Roo.isReady){ // allow calling of init() before onReady
32191 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32194 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32195 el.fxDefaults = {stopFx: true};
32196 // maximum custom styling
32197 //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>');
32198 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>');
32199 tipTitle = el.child('h3');
32200 tipTitle.enableDisplayMode("block");
32201 tipBody = el.child('div.x-tip-bd');
32202 tipBodyText = el.child('div.x-tip-bd-inner');
32203 //bdLeft = el.child('div.x-tip-bd-left');
32204 //bdRight = el.child('div.x-tip-bd-right');
32205 close = el.child('div.x-tip-close');
32206 close.enableDisplayMode("block");
32207 close.on("click", hide);
32208 var d = Roo.get(document);
32209 d.on("mousedown", onDown);
32210 d.on("mouseover", onOver);
32211 d.on("mouseout", onOut);
32212 d.on("mousemove", onMove);
32213 esc = d.addKeyListener(27, hide);
32216 dd = el.initDD("default", null, {
32217 onDrag : function(){
32221 dd.setHandleElId(tipTitle.id);
32230 * Configures a new quick tip instance and assigns it to a target element. The following config options
32233 Property Type Description
32234 ---------- --------------------- ------------------------------------------------------------------------
32235 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32237 * @param {Object} config The config object
32239 register : function(config){
32240 var cs = config instanceof Array ? config : arguments;
32241 for(var i = 0, len = cs.length; i < len; i++) {
32243 var target = c.target;
32245 if(target instanceof Array){
32246 for(var j = 0, jlen = target.length; j < jlen; j++){
32247 tagEls[target[j]] = c;
32250 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32257 * Removes this quick tip from its element and destroys it.
32258 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32260 unregister : function(el){
32261 delete tagEls[Roo.id(el)];
32265 * Enable this quick tip.
32267 enable : function(){
32268 if(inited && disabled){
32270 if(locks.length < 1){
32277 * Disable this quick tip.
32279 disable : function(){
32281 clearTimeout(showProc);
32282 clearTimeout(hideProc);
32283 clearTimeout(dismissProc);
32291 * Returns true if the quick tip is enabled, else false.
32293 isEnabled : function(){
32300 attribute : "qtip",
32310 // backwards compat
32311 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32313 * Ext JS Library 1.1.1
32314 * Copyright(c) 2006-2007, Ext JS, LLC.
32316 * Originally Released Under LGPL - original licence link has changed is not relivant.
32319 * <script type="text/javascript">
32324 * @class Roo.tree.TreePanel
32325 * @extends Roo.data.Tree
32327 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32328 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32329 * @cfg {Boolean} enableDD true to enable drag and drop
32330 * @cfg {Boolean} enableDrag true to enable just drag
32331 * @cfg {Boolean} enableDrop true to enable just drop
32332 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32333 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32334 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32335 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32336 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32337 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32338 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32339 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32340 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32341 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32342 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32343 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32344 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32345 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32346 * @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>
32347 * @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>
32350 * @param {String/HTMLElement/Element} el The container element
32351 * @param {Object} config
32353 Roo.tree.TreePanel = function(el, config){
32355 var loader = false;
32357 root = config.root;
32358 delete config.root;
32360 if (config.loader) {
32361 loader = config.loader;
32362 delete config.loader;
32365 Roo.apply(this, config);
32366 Roo.tree.TreePanel.superclass.constructor.call(this);
32367 this.el = Roo.get(el);
32368 this.el.addClass('x-tree');
32369 //console.log(root);
32371 this.setRootNode( Roo.factory(root, Roo.tree));
32374 this.loader = Roo.factory(loader, Roo.tree);
32377 * Read-only. The id of the container element becomes this TreePanel's id.
32379 this.id = this.el.id;
32382 * @event beforeload
32383 * Fires before a node is loaded, return false to cancel
32384 * @param {Node} node The node being loaded
32386 "beforeload" : true,
32389 * Fires when a node is loaded
32390 * @param {Node} node The node that was loaded
32394 * @event textchange
32395 * Fires when the text for a node is changed
32396 * @param {Node} node The node
32397 * @param {String} text The new text
32398 * @param {String} oldText The old text
32400 "textchange" : true,
32402 * @event beforeexpand
32403 * Fires before a node is expanded, return false to cancel.
32404 * @param {Node} node The node
32405 * @param {Boolean} deep
32406 * @param {Boolean} anim
32408 "beforeexpand" : true,
32410 * @event beforecollapse
32411 * Fires before a node is collapsed, return false to cancel.
32412 * @param {Node} node The node
32413 * @param {Boolean} deep
32414 * @param {Boolean} anim
32416 "beforecollapse" : true,
32419 * Fires when a node is expanded
32420 * @param {Node} node The node
32424 * @event disabledchange
32425 * Fires when the disabled status of a node changes
32426 * @param {Node} node The node
32427 * @param {Boolean} disabled
32429 "disabledchange" : true,
32432 * Fires when a node is collapsed
32433 * @param {Node} node The node
32437 * @event beforeclick
32438 * Fires before click processing on a node. Return false to cancel the default action.
32439 * @param {Node} node The node
32440 * @param {Roo.EventObject} e The event object
32442 "beforeclick":true,
32444 * @event checkchange
32445 * Fires when a node with a checkbox's checked property changes
32446 * @param {Node} this This node
32447 * @param {Boolean} checked
32449 "checkchange":true,
32452 * Fires when a node is clicked
32453 * @param {Node} node The node
32454 * @param {Roo.EventObject} e The event object
32459 * Fires when a node is double clicked
32460 * @param {Node} node The node
32461 * @param {Roo.EventObject} e The event object
32465 * @event contextmenu
32466 * Fires when a node is right clicked
32467 * @param {Node} node The node
32468 * @param {Roo.EventObject} e The event object
32470 "contextmenu":true,
32472 * @event beforechildrenrendered
32473 * Fires right before the child nodes for a node are rendered
32474 * @param {Node} node The node
32476 "beforechildrenrendered":true,
32479 * Fires when a node starts being dragged
32480 * @param {Roo.tree.TreePanel} this
32481 * @param {Roo.tree.TreeNode} node
32482 * @param {event} e The raw browser event
32484 "startdrag" : true,
32487 * Fires when a drag operation is complete
32488 * @param {Roo.tree.TreePanel} this
32489 * @param {Roo.tree.TreeNode} node
32490 * @param {event} e The raw browser event
32495 * Fires when a dragged node is dropped on a valid DD target
32496 * @param {Roo.tree.TreePanel} this
32497 * @param {Roo.tree.TreeNode} node
32498 * @param {DD} dd The dd it was dropped on
32499 * @param {event} e The raw browser event
32503 * @event beforenodedrop
32504 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32505 * passed to handlers has the following properties:<br />
32506 * <ul style="padding:5px;padding-left:16px;">
32507 * <li>tree - The TreePanel</li>
32508 * <li>target - The node being targeted for the drop</li>
32509 * <li>data - The drag data from the drag source</li>
32510 * <li>point - The point of the drop - append, above or below</li>
32511 * <li>source - The drag source</li>
32512 * <li>rawEvent - Raw mouse event</li>
32513 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32514 * to be inserted by setting them on this object.</li>
32515 * <li>cancel - Set this to true to cancel the drop.</li>
32517 * @param {Object} dropEvent
32519 "beforenodedrop" : true,
32522 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32523 * passed to handlers has the following properties:<br />
32524 * <ul style="padding:5px;padding-left:16px;">
32525 * <li>tree - The TreePanel</li>
32526 * <li>target - The node being targeted for the drop</li>
32527 * <li>data - The drag data from the drag source</li>
32528 * <li>point - The point of the drop - append, above or below</li>
32529 * <li>source - The drag source</li>
32530 * <li>rawEvent - Raw mouse event</li>
32531 * <li>dropNode - Dropped node(s).</li>
32533 * @param {Object} dropEvent
32537 * @event nodedragover
32538 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32539 * passed to handlers has the following properties:<br />
32540 * <ul style="padding:5px;padding-left:16px;">
32541 * <li>tree - The TreePanel</li>
32542 * <li>target - The node being targeted for the drop</li>
32543 * <li>data - The drag data from the drag source</li>
32544 * <li>point - The point of the drop - append, above or below</li>
32545 * <li>source - The drag source</li>
32546 * <li>rawEvent - Raw mouse event</li>
32547 * <li>dropNode - Drop node(s) provided by the source.</li>
32548 * <li>cancel - Set this to true to signal drop not allowed.</li>
32550 * @param {Object} dragOverEvent
32552 "nodedragover" : true
32555 if(this.singleExpand){
32556 this.on("beforeexpand", this.restrictExpand, this);
32559 this.editor.tree = this;
32560 this.editor = Roo.factory(this.editor, Roo.tree);
32563 if (this.selModel) {
32564 this.selModel = Roo.factory(this.selModel, Roo.tree);
32568 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32569 rootVisible : true,
32570 animate: Roo.enableFx,
32573 hlDrop : Roo.enableFx,
32577 rendererTip: false,
32579 restrictExpand : function(node){
32580 var p = node.parentNode;
32582 if(p.expandedChild && p.expandedChild.parentNode == p){
32583 p.expandedChild.collapse();
32585 p.expandedChild = node;
32589 // private override
32590 setRootNode : function(node){
32591 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32592 if(!this.rootVisible){
32593 node.ui = new Roo.tree.RootTreeNodeUI(node);
32599 * Returns the container element for this TreePanel
32601 getEl : function(){
32606 * Returns the default TreeLoader for this TreePanel
32608 getLoader : function(){
32609 return this.loader;
32615 expandAll : function(){
32616 this.root.expand(true);
32620 * Collapse all nodes
32622 collapseAll : function(){
32623 this.root.collapse(true);
32627 * Returns the selection model used by this TreePanel
32629 getSelectionModel : function(){
32630 if(!this.selModel){
32631 this.selModel = new Roo.tree.DefaultSelectionModel();
32633 return this.selModel;
32637 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32638 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32639 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32642 getChecked : function(a, startNode){
32643 startNode = startNode || this.root;
32645 var f = function(){
32646 if(this.attributes.checked){
32647 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32650 startNode.cascade(f);
32655 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32656 * @param {String} path
32657 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32658 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32659 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32661 expandPath : function(path, attr, callback){
32662 attr = attr || "id";
32663 var keys = path.split(this.pathSeparator);
32664 var curNode = this.root;
32665 if(curNode.attributes[attr] != keys[1]){ // invalid root
32667 callback(false, null);
32672 var f = function(){
32673 if(++index == keys.length){
32675 callback(true, curNode);
32679 var c = curNode.findChild(attr, keys[index]);
32682 callback(false, curNode);
32687 c.expand(false, false, f);
32689 curNode.expand(false, false, f);
32693 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32694 * @param {String} path
32695 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32696 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32697 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32699 selectPath : function(path, attr, callback){
32700 attr = attr || "id";
32701 var keys = path.split(this.pathSeparator);
32702 var v = keys.pop();
32703 if(keys.length > 0){
32704 var f = function(success, node){
32705 if(success && node){
32706 var n = node.findChild(attr, v);
32712 }else if(callback){
32713 callback(false, n);
32717 callback(false, n);
32721 this.expandPath(keys.join(this.pathSeparator), attr, f);
32723 this.root.select();
32725 callback(true, this.root);
32730 getTreeEl : function(){
32735 * Trigger rendering of this TreePanel
32737 render : function(){
32738 if (this.innerCt) {
32739 return this; // stop it rendering more than once!!
32742 this.innerCt = this.el.createChild({tag:"ul",
32743 cls:"x-tree-root-ct " +
32744 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32746 if(this.containerScroll){
32747 Roo.dd.ScrollManager.register(this.el);
32749 if((this.enableDD || this.enableDrop) && !this.dropZone){
32751 * The dropZone used by this tree if drop is enabled
32752 * @type Roo.tree.TreeDropZone
32754 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32755 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32758 if((this.enableDD || this.enableDrag) && !this.dragZone){
32760 * The dragZone used by this tree if drag is enabled
32761 * @type Roo.tree.TreeDragZone
32763 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32764 ddGroup: this.ddGroup || "TreeDD",
32765 scroll: this.ddScroll
32768 this.getSelectionModel().init(this);
32770 Roo.log("ROOT not set in tree");
32773 this.root.render();
32774 if(!this.rootVisible){
32775 this.root.renderChildren();
32781 * Ext JS Library 1.1.1
32782 * Copyright(c) 2006-2007, Ext JS, LLC.
32784 * Originally Released Under LGPL - original licence link has changed is not relivant.
32787 * <script type="text/javascript">
32792 * @class Roo.tree.DefaultSelectionModel
32793 * @extends Roo.util.Observable
32794 * The default single selection for a TreePanel.
32795 * @param {Object} cfg Configuration
32797 Roo.tree.DefaultSelectionModel = function(cfg){
32798 this.selNode = null;
32804 * @event selectionchange
32805 * Fires when the selected node changes
32806 * @param {DefaultSelectionModel} this
32807 * @param {TreeNode} node the new selection
32809 "selectionchange" : true,
32812 * @event beforeselect
32813 * Fires before the selected node changes, return false to cancel the change
32814 * @param {DefaultSelectionModel} this
32815 * @param {TreeNode} node the new selection
32816 * @param {TreeNode} node the old selection
32818 "beforeselect" : true
32821 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32824 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32825 init : function(tree){
32827 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32828 tree.on("click", this.onNodeClick, this);
32831 onNodeClick : function(node, e){
32832 if (e.ctrlKey && this.selNode == node) {
32833 this.unselect(node);
32841 * @param {TreeNode} node The node to select
32842 * @return {TreeNode} The selected node
32844 select : function(node){
32845 var last = this.selNode;
32846 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32848 last.ui.onSelectedChange(false);
32850 this.selNode = node;
32851 node.ui.onSelectedChange(true);
32852 this.fireEvent("selectionchange", this, node, last);
32859 * @param {TreeNode} node The node to unselect
32861 unselect : function(node){
32862 if(this.selNode == node){
32863 this.clearSelections();
32868 * Clear all selections
32870 clearSelections : function(){
32871 var n = this.selNode;
32873 n.ui.onSelectedChange(false);
32874 this.selNode = null;
32875 this.fireEvent("selectionchange", this, null);
32881 * Get the selected node
32882 * @return {TreeNode} The selected node
32884 getSelectedNode : function(){
32885 return this.selNode;
32889 * Returns true if the node is selected
32890 * @param {TreeNode} node The node to check
32891 * @return {Boolean}
32893 isSelected : function(node){
32894 return this.selNode == node;
32898 * Selects the node above the selected node in the tree, intelligently walking the nodes
32899 * @return TreeNode The new selection
32901 selectPrevious : function(){
32902 var s = this.selNode || this.lastSelNode;
32906 var ps = s.previousSibling;
32908 if(!ps.isExpanded() || ps.childNodes.length < 1){
32909 return this.select(ps);
32911 var lc = ps.lastChild;
32912 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32915 return this.select(lc);
32917 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32918 return this.select(s.parentNode);
32924 * Selects the node above the selected node in the tree, intelligently walking the nodes
32925 * @return TreeNode The new selection
32927 selectNext : function(){
32928 var s = this.selNode || this.lastSelNode;
32932 if(s.firstChild && s.isExpanded()){
32933 return this.select(s.firstChild);
32934 }else if(s.nextSibling){
32935 return this.select(s.nextSibling);
32936 }else if(s.parentNode){
32938 s.parentNode.bubble(function(){
32939 if(this.nextSibling){
32940 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32949 onKeyDown : function(e){
32950 var s = this.selNode || this.lastSelNode;
32951 // undesirable, but required
32956 var k = e.getKey();
32964 this.selectPrevious();
32967 e.preventDefault();
32968 if(s.hasChildNodes()){
32969 if(!s.isExpanded()){
32971 }else if(s.firstChild){
32972 this.select(s.firstChild, e);
32977 e.preventDefault();
32978 if(s.hasChildNodes() && s.isExpanded()){
32980 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32981 this.select(s.parentNode, e);
32989 * @class Roo.tree.MultiSelectionModel
32990 * @extends Roo.util.Observable
32991 * Multi selection for a TreePanel.
32992 * @param {Object} cfg Configuration
32994 Roo.tree.MultiSelectionModel = function(){
32995 this.selNodes = [];
32999 * @event selectionchange
33000 * Fires when the selected nodes change
33001 * @param {MultiSelectionModel} this
33002 * @param {Array} nodes Array of the selected nodes
33004 "selectionchange" : true
33006 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33010 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33011 init : function(tree){
33013 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33014 tree.on("click", this.onNodeClick, this);
33017 onNodeClick : function(node, e){
33018 this.select(node, e, e.ctrlKey);
33023 * @param {TreeNode} node The node to select
33024 * @param {EventObject} e (optional) An event associated with the selection
33025 * @param {Boolean} keepExisting True to retain existing selections
33026 * @return {TreeNode} The selected node
33028 select : function(node, e, keepExisting){
33029 if(keepExisting !== true){
33030 this.clearSelections(true);
33032 if(this.isSelected(node)){
33033 this.lastSelNode = node;
33036 this.selNodes.push(node);
33037 this.selMap[node.id] = node;
33038 this.lastSelNode = node;
33039 node.ui.onSelectedChange(true);
33040 this.fireEvent("selectionchange", this, this.selNodes);
33046 * @param {TreeNode} node The node to unselect
33048 unselect : function(node){
33049 if(this.selMap[node.id]){
33050 node.ui.onSelectedChange(false);
33051 var sn = this.selNodes;
33054 index = sn.indexOf(node);
33056 for(var i = 0, len = sn.length; i < len; i++){
33064 this.selNodes.splice(index, 1);
33066 delete this.selMap[node.id];
33067 this.fireEvent("selectionchange", this, this.selNodes);
33072 * Clear all selections
33074 clearSelections : function(suppressEvent){
33075 var sn = this.selNodes;
33077 for(var i = 0, len = sn.length; i < len; i++){
33078 sn[i].ui.onSelectedChange(false);
33080 this.selNodes = [];
33082 if(suppressEvent !== true){
33083 this.fireEvent("selectionchange", this, this.selNodes);
33089 * Returns true if the node is selected
33090 * @param {TreeNode} node The node to check
33091 * @return {Boolean}
33093 isSelected : function(node){
33094 return this.selMap[node.id] ? true : false;
33098 * Returns an array of the selected nodes
33101 getSelectedNodes : function(){
33102 return this.selNodes;
33105 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33107 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33109 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33112 * Ext JS Library 1.1.1
33113 * Copyright(c) 2006-2007, Ext JS, LLC.
33115 * Originally Released Under LGPL - original licence link has changed is not relivant.
33118 * <script type="text/javascript">
33122 * @class Roo.tree.TreeNode
33123 * @extends Roo.data.Node
33124 * @cfg {String} text The text for this node
33125 * @cfg {Boolean} expanded true to start the node expanded
33126 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33127 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33128 * @cfg {Boolean} disabled true to start the node disabled
33129 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33130 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33131 * @cfg {String} cls A css class to be added to the node
33132 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33133 * @cfg {String} href URL of the link used for the node (defaults to #)
33134 * @cfg {String} hrefTarget target frame for the link
33135 * @cfg {String} qtip An Ext QuickTip for the node
33136 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33137 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33138 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33139 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33140 * (defaults to undefined with no checkbox rendered)
33142 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33144 Roo.tree.TreeNode = function(attributes){
33145 attributes = attributes || {};
33146 if(typeof attributes == "string"){
33147 attributes = {text: attributes};
33149 this.childrenRendered = false;
33150 this.rendered = false;
33151 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33152 this.expanded = attributes.expanded === true;
33153 this.isTarget = attributes.isTarget !== false;
33154 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33155 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33158 * Read-only. The text for this node. To change it use setText().
33161 this.text = attributes.text;
33163 * True if this node is disabled.
33166 this.disabled = attributes.disabled === true;
33170 * @event textchange
33171 * Fires when the text for this node is changed
33172 * @param {Node} this This node
33173 * @param {String} text The new text
33174 * @param {String} oldText The old text
33176 "textchange" : true,
33178 * @event beforeexpand
33179 * Fires before this node is expanded, return false to cancel.
33180 * @param {Node} this This node
33181 * @param {Boolean} deep
33182 * @param {Boolean} anim
33184 "beforeexpand" : true,
33186 * @event beforecollapse
33187 * Fires before this node is collapsed, return false to cancel.
33188 * @param {Node} this This node
33189 * @param {Boolean} deep
33190 * @param {Boolean} anim
33192 "beforecollapse" : true,
33195 * Fires when this node is expanded
33196 * @param {Node} this This node
33200 * @event disabledchange
33201 * Fires when the disabled status of this node changes
33202 * @param {Node} this This node
33203 * @param {Boolean} disabled
33205 "disabledchange" : true,
33208 * Fires when this node is collapsed
33209 * @param {Node} this This node
33213 * @event beforeclick
33214 * Fires before click processing. Return false to cancel the default action.
33215 * @param {Node} this This node
33216 * @param {Roo.EventObject} e The event object
33218 "beforeclick":true,
33220 * @event checkchange
33221 * Fires when a node with a checkbox's checked property changes
33222 * @param {Node} this This node
33223 * @param {Boolean} checked
33225 "checkchange":true,
33228 * Fires when this node is clicked
33229 * @param {Node} this This node
33230 * @param {Roo.EventObject} e The event object
33235 * Fires when this node is double clicked
33236 * @param {Node} this This node
33237 * @param {Roo.EventObject} e The event object
33241 * @event contextmenu
33242 * Fires when this node is right clicked
33243 * @param {Node} this This node
33244 * @param {Roo.EventObject} e The event object
33246 "contextmenu":true,
33248 * @event beforechildrenrendered
33249 * Fires right before the child nodes for this node are rendered
33250 * @param {Node} this This node
33252 "beforechildrenrendered":true
33255 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33258 * Read-only. The UI for this node
33261 this.ui = new uiClass(this);
33263 // finally support items[]
33264 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33269 Roo.each(this.attributes.items, function(c) {
33270 this.appendChild(Roo.factory(c,Roo.Tree));
33272 delete this.attributes.items;
33277 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33278 preventHScroll: true,
33280 * Returns true if this node is expanded
33281 * @return {Boolean}
33283 isExpanded : function(){
33284 return this.expanded;
33288 * Returns the UI object for this node
33289 * @return {TreeNodeUI}
33291 getUI : function(){
33295 // private override
33296 setFirstChild : function(node){
33297 var of = this.firstChild;
33298 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33299 if(this.childrenRendered && of && node != of){
33300 of.renderIndent(true, true);
33303 this.renderIndent(true, true);
33307 // private override
33308 setLastChild : function(node){
33309 var ol = this.lastChild;
33310 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33311 if(this.childrenRendered && ol && node != ol){
33312 ol.renderIndent(true, true);
33315 this.renderIndent(true, true);
33319 // these methods are overridden to provide lazy rendering support
33320 // private override
33321 appendChild : function()
33323 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33324 if(node && this.childrenRendered){
33327 this.ui.updateExpandIcon();
33331 // private override
33332 removeChild : function(node){
33333 this.ownerTree.getSelectionModel().unselect(node);
33334 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33335 // if it's been rendered remove dom node
33336 if(this.childrenRendered){
33339 if(this.childNodes.length < 1){
33340 this.collapse(false, false);
33342 this.ui.updateExpandIcon();
33344 if(!this.firstChild) {
33345 this.childrenRendered = false;
33350 // private override
33351 insertBefore : function(node, refNode){
33352 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33353 if(newNode && refNode && this.childrenRendered){
33356 this.ui.updateExpandIcon();
33361 * Sets the text for this node
33362 * @param {String} text
33364 setText : function(text){
33365 var oldText = this.text;
33367 this.attributes.text = text;
33368 if(this.rendered){ // event without subscribing
33369 this.ui.onTextChange(this, text, oldText);
33371 this.fireEvent("textchange", this, text, oldText);
33375 * Triggers selection of this node
33377 select : function(){
33378 this.getOwnerTree().getSelectionModel().select(this);
33382 * Triggers deselection of this node
33384 unselect : function(){
33385 this.getOwnerTree().getSelectionModel().unselect(this);
33389 * Returns true if this node is selected
33390 * @return {Boolean}
33392 isSelected : function(){
33393 return this.getOwnerTree().getSelectionModel().isSelected(this);
33397 * Expand this node.
33398 * @param {Boolean} deep (optional) True to expand all children as well
33399 * @param {Boolean} anim (optional) false to cancel the default animation
33400 * @param {Function} callback (optional) A callback to be called when
33401 * expanding this node completes (does not wait for deep expand to complete).
33402 * Called with 1 parameter, this node.
33404 expand : function(deep, anim, callback){
33405 if(!this.expanded){
33406 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33409 if(!this.childrenRendered){
33410 this.renderChildren();
33412 this.expanded = true;
33413 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33414 this.ui.animExpand(function(){
33415 this.fireEvent("expand", this);
33416 if(typeof callback == "function"){
33420 this.expandChildNodes(true);
33422 }.createDelegate(this));
33426 this.fireEvent("expand", this);
33427 if(typeof callback == "function"){
33432 if(typeof callback == "function"){
33437 this.expandChildNodes(true);
33441 isHiddenRoot : function(){
33442 return this.isRoot && !this.getOwnerTree().rootVisible;
33446 * Collapse this node.
33447 * @param {Boolean} deep (optional) True to collapse all children as well
33448 * @param {Boolean} anim (optional) false to cancel the default animation
33450 collapse : function(deep, anim){
33451 if(this.expanded && !this.isHiddenRoot()){
33452 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33455 this.expanded = false;
33456 if((this.getOwnerTree().animate && anim !== false) || anim){
33457 this.ui.animCollapse(function(){
33458 this.fireEvent("collapse", this);
33460 this.collapseChildNodes(true);
33462 }.createDelegate(this));
33465 this.ui.collapse();
33466 this.fireEvent("collapse", this);
33470 var cs = this.childNodes;
33471 for(var i = 0, len = cs.length; i < len; i++) {
33472 cs[i].collapse(true, false);
33478 delayedExpand : function(delay){
33479 if(!this.expandProcId){
33480 this.expandProcId = this.expand.defer(delay, this);
33485 cancelExpand : function(){
33486 if(this.expandProcId){
33487 clearTimeout(this.expandProcId);
33489 this.expandProcId = false;
33493 * Toggles expanded/collapsed state of the node
33495 toggle : function(){
33504 * Ensures all parent nodes are expanded
33506 ensureVisible : function(callback){
33507 var tree = this.getOwnerTree();
33508 tree.expandPath(this.parentNode.getPath(), false, function(){
33509 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33510 Roo.callback(callback);
33511 }.createDelegate(this));
33515 * Expand all child nodes
33516 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33518 expandChildNodes : function(deep){
33519 var cs = this.childNodes;
33520 for(var i = 0, len = cs.length; i < len; i++) {
33521 cs[i].expand(deep);
33526 * Collapse all child nodes
33527 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33529 collapseChildNodes : function(deep){
33530 var cs = this.childNodes;
33531 for(var i = 0, len = cs.length; i < len; i++) {
33532 cs[i].collapse(deep);
33537 * Disables this node
33539 disable : function(){
33540 this.disabled = true;
33542 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33543 this.ui.onDisableChange(this, true);
33545 this.fireEvent("disabledchange", this, true);
33549 * Enables this node
33551 enable : function(){
33552 this.disabled = false;
33553 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33554 this.ui.onDisableChange(this, false);
33556 this.fireEvent("disabledchange", this, false);
33560 renderChildren : function(suppressEvent){
33561 if(suppressEvent !== false){
33562 this.fireEvent("beforechildrenrendered", this);
33564 var cs = this.childNodes;
33565 for(var i = 0, len = cs.length; i < len; i++){
33566 cs[i].render(true);
33568 this.childrenRendered = true;
33572 sort : function(fn, scope){
33573 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33574 if(this.childrenRendered){
33575 var cs = this.childNodes;
33576 for(var i = 0, len = cs.length; i < len; i++){
33577 cs[i].render(true);
33583 render : function(bulkRender){
33584 this.ui.render(bulkRender);
33585 if(!this.rendered){
33586 this.rendered = true;
33588 this.expanded = false;
33589 this.expand(false, false);
33595 renderIndent : function(deep, refresh){
33597 this.ui.childIndent = null;
33599 this.ui.renderIndent();
33600 if(deep === true && this.childrenRendered){
33601 var cs = this.childNodes;
33602 for(var i = 0, len = cs.length; i < len; i++){
33603 cs[i].renderIndent(true, refresh);
33609 * Ext JS Library 1.1.1
33610 * Copyright(c) 2006-2007, Ext JS, LLC.
33612 * Originally Released Under LGPL - original licence link has changed is not relivant.
33615 * <script type="text/javascript">
33619 * @class Roo.tree.AsyncTreeNode
33620 * @extends Roo.tree.TreeNode
33621 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33623 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33625 Roo.tree.AsyncTreeNode = function(config){
33626 this.loaded = false;
33627 this.loading = false;
33628 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33630 * @event beforeload
33631 * Fires before this node is loaded, return false to cancel
33632 * @param {Node} this This node
33634 this.addEvents({'beforeload':true, 'load': true});
33637 * Fires when this node is loaded
33638 * @param {Node} this This node
33641 * The loader used by this node (defaults to using the tree's defined loader)
33646 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33647 expand : function(deep, anim, callback){
33648 if(this.loading){ // if an async load is already running, waiting til it's done
33650 var f = function(){
33651 if(!this.loading){ // done loading
33652 clearInterval(timer);
33653 this.expand(deep, anim, callback);
33655 }.createDelegate(this);
33656 timer = setInterval(f, 200);
33660 if(this.fireEvent("beforeload", this) === false){
33663 this.loading = true;
33664 this.ui.beforeLoad(this);
33665 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33667 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33671 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33675 * Returns true if this node is currently loading
33676 * @return {Boolean}
33678 isLoading : function(){
33679 return this.loading;
33682 loadComplete : function(deep, anim, callback){
33683 this.loading = false;
33684 this.loaded = true;
33685 this.ui.afterLoad(this);
33686 this.fireEvent("load", this);
33687 this.expand(deep, anim, callback);
33691 * Returns true if this node has been loaded
33692 * @return {Boolean}
33694 isLoaded : function(){
33695 return this.loaded;
33698 hasChildNodes : function(){
33699 if(!this.isLeaf() && !this.loaded){
33702 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33707 * Trigger a reload for this node
33708 * @param {Function} callback
33710 reload : function(callback){
33711 this.collapse(false, false);
33712 while(this.firstChild){
33713 this.removeChild(this.firstChild);
33715 this.childrenRendered = false;
33716 this.loaded = false;
33717 if(this.isHiddenRoot()){
33718 this.expanded = false;
33720 this.expand(false, false, callback);
33724 * Ext JS Library 1.1.1
33725 * Copyright(c) 2006-2007, Ext JS, LLC.
33727 * Originally Released Under LGPL - original licence link has changed is not relivant.
33730 * <script type="text/javascript">
33734 * @class Roo.tree.TreeNodeUI
33736 * @param {Object} node The node to render
33737 * The TreeNode UI implementation is separate from the
33738 * tree implementation. Unless you are customizing the tree UI,
33739 * you should never have to use this directly.
33741 Roo.tree.TreeNodeUI = function(node){
33743 this.rendered = false;
33744 this.animating = false;
33745 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33748 Roo.tree.TreeNodeUI.prototype = {
33749 removeChild : function(node){
33751 this.ctNode.removeChild(node.ui.getEl());
33755 beforeLoad : function(){
33756 this.addClass("x-tree-node-loading");
33759 afterLoad : function(){
33760 this.removeClass("x-tree-node-loading");
33763 onTextChange : function(node, text, oldText){
33765 this.textNode.innerHTML = text;
33769 onDisableChange : function(node, state){
33770 this.disabled = state;
33772 this.addClass("x-tree-node-disabled");
33774 this.removeClass("x-tree-node-disabled");
33778 onSelectedChange : function(state){
33781 this.addClass("x-tree-selected");
33784 this.removeClass("x-tree-selected");
33788 onMove : function(tree, node, oldParent, newParent, index, refNode){
33789 this.childIndent = null;
33791 var targetNode = newParent.ui.getContainer();
33792 if(!targetNode){//target not rendered
33793 this.holder = document.createElement("div");
33794 this.holder.appendChild(this.wrap);
33797 var insertBefore = refNode ? refNode.ui.getEl() : null;
33799 targetNode.insertBefore(this.wrap, insertBefore);
33801 targetNode.appendChild(this.wrap);
33803 this.node.renderIndent(true);
33807 addClass : function(cls){
33809 Roo.fly(this.elNode).addClass(cls);
33813 removeClass : function(cls){
33815 Roo.fly(this.elNode).removeClass(cls);
33819 remove : function(){
33821 this.holder = document.createElement("div");
33822 this.holder.appendChild(this.wrap);
33826 fireEvent : function(){
33827 return this.node.fireEvent.apply(this.node, arguments);
33830 initEvents : function(){
33831 this.node.on("move", this.onMove, this);
33832 var E = Roo.EventManager;
33833 var a = this.anchor;
33835 var el = Roo.fly(a, '_treeui');
33837 if(Roo.isOpera){ // opera render bug ignores the CSS
33838 el.setStyle("text-decoration", "none");
33841 el.on("click", this.onClick, this);
33842 el.on("dblclick", this.onDblClick, this);
33845 Roo.EventManager.on(this.checkbox,
33846 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33849 el.on("contextmenu", this.onContextMenu, this);
33851 var icon = Roo.fly(this.iconNode);
33852 icon.on("click", this.onClick, this);
33853 icon.on("dblclick", this.onDblClick, this);
33854 icon.on("contextmenu", this.onContextMenu, this);
33855 E.on(this.ecNode, "click", this.ecClick, this, true);
33857 if(this.node.disabled){
33858 this.addClass("x-tree-node-disabled");
33860 if(this.node.hidden){
33861 this.addClass("x-tree-node-disabled");
33863 var ot = this.node.getOwnerTree();
33864 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33865 if(dd && (!this.node.isRoot || ot.rootVisible)){
33866 Roo.dd.Registry.register(this.elNode, {
33868 handles: this.getDDHandles(),
33874 getDDHandles : function(){
33875 return [this.iconNode, this.textNode];
33880 this.wrap.style.display = "none";
33886 this.wrap.style.display = "";
33890 onContextMenu : function(e){
33891 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33892 e.preventDefault();
33894 this.fireEvent("contextmenu", this.node, e);
33898 onClick : function(e){
33903 if(this.fireEvent("beforeclick", this.node, e) !== false){
33904 if(!this.disabled && this.node.attributes.href){
33905 this.fireEvent("click", this.node, e);
33908 e.preventDefault();
33913 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33914 this.node.toggle();
33917 this.fireEvent("click", this.node, e);
33923 onDblClick : function(e){
33924 e.preventDefault();
33929 this.toggleCheck();
33931 if(!this.animating && this.node.hasChildNodes()){
33932 this.node.toggle();
33934 this.fireEvent("dblclick", this.node, e);
33937 onCheckChange : function(){
33938 var checked = this.checkbox.checked;
33939 this.node.attributes.checked = checked;
33940 this.fireEvent('checkchange', this.node, checked);
33943 ecClick : function(e){
33944 if(!this.animating && this.node.hasChildNodes()){
33945 this.node.toggle();
33949 startDrop : function(){
33950 this.dropping = true;
33953 // delayed drop so the click event doesn't get fired on a drop
33954 endDrop : function(){
33955 setTimeout(function(){
33956 this.dropping = false;
33957 }.createDelegate(this), 50);
33960 expand : function(){
33961 this.updateExpandIcon();
33962 this.ctNode.style.display = "";
33965 focus : function(){
33966 if(!this.node.preventHScroll){
33967 try{this.anchor.focus();
33969 }else if(!Roo.isIE){
33971 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33972 var l = noscroll.scrollLeft;
33973 this.anchor.focus();
33974 noscroll.scrollLeft = l;
33979 toggleCheck : function(value){
33980 var cb = this.checkbox;
33982 cb.checked = (value === undefined ? !cb.checked : value);
33988 this.anchor.blur();
33992 animExpand : function(callback){
33993 var ct = Roo.get(this.ctNode);
33995 if(!this.node.hasChildNodes()){
33996 this.updateExpandIcon();
33997 this.ctNode.style.display = "";
33998 Roo.callback(callback);
34001 this.animating = true;
34002 this.updateExpandIcon();
34005 callback : function(){
34006 this.animating = false;
34007 Roo.callback(callback);
34010 duration: this.node.ownerTree.duration || .25
34014 highlight : function(){
34015 var tree = this.node.getOwnerTree();
34016 Roo.fly(this.wrap).highlight(
34017 tree.hlColor || "C3DAF9",
34018 {endColor: tree.hlBaseColor}
34022 collapse : function(){
34023 this.updateExpandIcon();
34024 this.ctNode.style.display = "none";
34027 animCollapse : function(callback){
34028 var ct = Roo.get(this.ctNode);
34029 ct.enableDisplayMode('block');
34032 this.animating = true;
34033 this.updateExpandIcon();
34036 callback : function(){
34037 this.animating = false;
34038 Roo.callback(callback);
34041 duration: this.node.ownerTree.duration || .25
34045 getContainer : function(){
34046 return this.ctNode;
34049 getEl : function(){
34053 appendDDGhost : function(ghostNode){
34054 ghostNode.appendChild(this.elNode.cloneNode(true));
34057 getDDRepairXY : function(){
34058 return Roo.lib.Dom.getXY(this.iconNode);
34061 onRender : function(){
34065 render : function(bulkRender){
34066 var n = this.node, a = n.attributes;
34067 var targetNode = n.parentNode ?
34068 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34070 if(!this.rendered){
34071 this.rendered = true;
34073 this.renderElements(n, a, targetNode, bulkRender);
34076 if(this.textNode.setAttributeNS){
34077 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34079 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34082 this.textNode.setAttribute("ext:qtip", a.qtip);
34084 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34087 }else if(a.qtipCfg){
34088 a.qtipCfg.target = Roo.id(this.textNode);
34089 Roo.QuickTips.register(a.qtipCfg);
34092 if(!this.node.expanded){
34093 this.updateExpandIcon();
34096 if(bulkRender === true) {
34097 targetNode.appendChild(this.wrap);
34102 renderElements : function(n, a, targetNode, bulkRender)
34104 // add some indent caching, this helps performance when rendering a large tree
34105 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34106 var t = n.getOwnerTree();
34107 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34108 if (typeof(n.attributes.html) != 'undefined') {
34109 txt = n.attributes.html;
34111 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34112 var cb = typeof a.checked == 'boolean';
34113 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34114 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34115 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34116 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34117 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34118 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34119 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34120 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34121 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34122 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34125 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34126 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34127 n.nextSibling.ui.getEl(), buf.join(""));
34129 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34132 this.elNode = this.wrap.childNodes[0];
34133 this.ctNode = this.wrap.childNodes[1];
34134 var cs = this.elNode.childNodes;
34135 this.indentNode = cs[0];
34136 this.ecNode = cs[1];
34137 this.iconNode = cs[2];
34140 this.checkbox = cs[3];
34143 this.anchor = cs[index];
34144 this.textNode = cs[index].firstChild;
34147 getAnchor : function(){
34148 return this.anchor;
34151 getTextEl : function(){
34152 return this.textNode;
34155 getIconEl : function(){
34156 return this.iconNode;
34159 isChecked : function(){
34160 return this.checkbox ? this.checkbox.checked : false;
34163 updateExpandIcon : function(){
34165 var n = this.node, c1, c2;
34166 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34167 var hasChild = n.hasChildNodes();
34171 c1 = "x-tree-node-collapsed";
34172 c2 = "x-tree-node-expanded";
34175 c1 = "x-tree-node-expanded";
34176 c2 = "x-tree-node-collapsed";
34179 this.removeClass("x-tree-node-leaf");
34180 this.wasLeaf = false;
34182 if(this.c1 != c1 || this.c2 != c2){
34183 Roo.fly(this.elNode).replaceClass(c1, c2);
34184 this.c1 = c1; this.c2 = c2;
34187 // this changes non-leafs into leafs if they have no children.
34188 // it's not very rational behaviour..
34190 if(!this.wasLeaf && this.node.leaf){
34191 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34194 this.wasLeaf = true;
34197 var ecc = "x-tree-ec-icon "+cls;
34198 if(this.ecc != ecc){
34199 this.ecNode.className = ecc;
34205 getChildIndent : function(){
34206 if(!this.childIndent){
34210 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34212 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34214 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34219 this.childIndent = buf.join("");
34221 return this.childIndent;
34224 renderIndent : function(){
34227 var p = this.node.parentNode;
34229 indent = p.ui.getChildIndent();
34231 if(this.indentMarkup != indent){ // don't rerender if not required
34232 this.indentNode.innerHTML = indent;
34233 this.indentMarkup = indent;
34235 this.updateExpandIcon();
34240 Roo.tree.RootTreeNodeUI = function(){
34241 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34243 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34244 render : function(){
34245 if(!this.rendered){
34246 var targetNode = this.node.ownerTree.innerCt.dom;
34247 this.node.expanded = true;
34248 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34249 this.wrap = this.ctNode = targetNode.firstChild;
34252 collapse : function(){
34254 expand : function(){
34258 * Ext JS Library 1.1.1
34259 * Copyright(c) 2006-2007, Ext JS, LLC.
34261 * Originally Released Under LGPL - original licence link has changed is not relivant.
34264 * <script type="text/javascript">
34267 * @class Roo.tree.TreeLoader
34268 * @extends Roo.util.Observable
34269 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34270 * nodes from a specified URL. The response must be a javascript Array definition
34271 * who's elements are node definition objects. eg:
34276 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34277 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34284 * The old style respose with just an array is still supported, but not recommended.
34287 * A server request is sent, and child nodes are loaded only when a node is expanded.
34288 * The loading node's id is passed to the server under the parameter name "node" to
34289 * enable the server to produce the correct child nodes.
34291 * To pass extra parameters, an event handler may be attached to the "beforeload"
34292 * event, and the parameters specified in the TreeLoader's baseParams property:
34294 myTreeLoader.on("beforeload", function(treeLoader, node) {
34295 this.baseParams.category = node.attributes.category;
34298 * This would pass an HTTP parameter called "category" to the server containing
34299 * the value of the Node's "category" attribute.
34301 * Creates a new Treeloader.
34302 * @param {Object} config A config object containing config properties.
34304 Roo.tree.TreeLoader = function(config){
34305 this.baseParams = {};
34306 this.requestMethod = "POST";
34307 Roo.apply(this, config);
34312 * @event beforeload
34313 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34314 * @param {Object} This TreeLoader object.
34315 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34316 * @param {Object} callback The callback function specified in the {@link #load} call.
34321 * Fires when the node has been successfuly loaded.
34322 * @param {Object} This TreeLoader object.
34323 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34324 * @param {Object} response The response object containing the data from the server.
34328 * @event loadexception
34329 * Fires if the network request failed.
34330 * @param {Object} This TreeLoader object.
34331 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34332 * @param {Object} response The response object containing the data from the server.
34334 loadexception : true,
34337 * Fires before a node is created, enabling you to return custom Node types
34338 * @param {Object} This TreeLoader object.
34339 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34344 Roo.tree.TreeLoader.superclass.constructor.call(this);
34347 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34349 * @cfg {String} dataUrl The URL from which to request a Json string which
34350 * specifies an array of node definition object representing the child nodes
34354 * @cfg {String} requestMethod either GET or POST
34355 * defaults to POST (due to BC)
34359 * @cfg {Object} baseParams (optional) An object containing properties which
34360 * specify HTTP parameters to be passed to each request for child nodes.
34363 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34364 * created by this loader. If the attributes sent by the server have an attribute in this object,
34365 * they take priority.
34368 * @cfg {Object} uiProviders (optional) An object containing properties which
34370 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34371 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34372 * <i>uiProvider</i> attribute of a returned child node is a string rather
34373 * than a reference to a TreeNodeUI implementation, this that string value
34374 * is used as a property name in the uiProviders object. You can define the provider named
34375 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34380 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34381 * child nodes before loading.
34383 clearOnLoad : true,
34386 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34387 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34388 * Grid query { data : [ .....] }
34393 * @cfg {String} queryParam (optional)
34394 * Name of the query as it will be passed on the querystring (defaults to 'node')
34395 * eg. the request will be ?node=[id]
34402 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34403 * This is called automatically when a node is expanded, but may be used to reload
34404 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34405 * @param {Roo.tree.TreeNode} node
34406 * @param {Function} callback
34408 load : function(node, callback){
34409 if(this.clearOnLoad){
34410 while(node.firstChild){
34411 node.removeChild(node.firstChild);
34414 if(node.attributes.children){ // preloaded json children
34415 var cs = node.attributes.children;
34416 for(var i = 0, len = cs.length; i < len; i++){
34417 node.appendChild(this.createNode(cs[i]));
34419 if(typeof callback == "function"){
34422 }else if(this.dataUrl){
34423 this.requestData(node, callback);
34427 getParams: function(node){
34428 var buf = [], bp = this.baseParams;
34429 for(var key in bp){
34430 if(typeof bp[key] != "function"){
34431 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34434 var n = this.queryParam === false ? 'node' : this.queryParam;
34435 buf.push(n + "=", encodeURIComponent(node.id));
34436 return buf.join("");
34439 requestData : function(node, callback){
34440 if(this.fireEvent("beforeload", this, node, callback) !== false){
34441 this.transId = Roo.Ajax.request({
34442 method:this.requestMethod,
34443 url: this.dataUrl||this.url,
34444 success: this.handleResponse,
34445 failure: this.handleFailure,
34447 argument: {callback: callback, node: node},
34448 params: this.getParams(node)
34451 // if the load is cancelled, make sure we notify
34452 // the node that we are done
34453 if(typeof callback == "function"){
34459 isLoading : function(){
34460 return this.transId ? true : false;
34463 abort : function(){
34464 if(this.isLoading()){
34465 Roo.Ajax.abort(this.transId);
34470 createNode : function(attr)
34472 // apply baseAttrs, nice idea Corey!
34473 if(this.baseAttrs){
34474 Roo.applyIf(attr, this.baseAttrs);
34476 if(this.applyLoader !== false){
34477 attr.loader = this;
34479 // uiProvider = depreciated..
34481 if(typeof(attr.uiProvider) == 'string'){
34482 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34483 /** eval:var:attr */ eval(attr.uiProvider);
34485 if(typeof(this.uiProviders['default']) != 'undefined') {
34486 attr.uiProvider = this.uiProviders['default'];
34489 this.fireEvent('create', this, attr);
34491 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34493 new Roo.tree.TreeNode(attr) :
34494 new Roo.tree.AsyncTreeNode(attr));
34497 processResponse : function(response, node, callback)
34499 var json = response.responseText;
34502 var o = Roo.decode(json);
34504 if (this.root === false && typeof(o.success) != undefined) {
34505 this.root = 'data'; // the default behaviour for list like data..
34508 if (this.root !== false && !o.success) {
34509 // it's a failure condition.
34510 var a = response.argument;
34511 this.fireEvent("loadexception", this, a.node, response);
34512 Roo.log("Load failed - should have a handler really");
34518 if (this.root !== false) {
34522 for(var i = 0, len = o.length; i < len; i++){
34523 var n = this.createNode(o[i]);
34525 node.appendChild(n);
34528 if(typeof callback == "function"){
34529 callback(this, node);
34532 this.handleFailure(response);
34536 handleResponse : function(response){
34537 this.transId = false;
34538 var a = response.argument;
34539 this.processResponse(response, a.node, a.callback);
34540 this.fireEvent("load", this, a.node, response);
34543 handleFailure : function(response)
34545 // should handle failure better..
34546 this.transId = false;
34547 var a = response.argument;
34548 this.fireEvent("loadexception", this, a.node, response);
34549 if(typeof a.callback == "function"){
34550 a.callback(this, a.node);
34555 * Ext JS Library 1.1.1
34556 * Copyright(c) 2006-2007, Ext JS, LLC.
34558 * Originally Released Under LGPL - original licence link has changed is not relivant.
34561 * <script type="text/javascript">
34565 * @class Roo.tree.TreeFilter
34566 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34567 * @param {TreePanel} tree
34568 * @param {Object} config (optional)
34570 Roo.tree.TreeFilter = function(tree, config){
34572 this.filtered = {};
34573 Roo.apply(this, config);
34576 Roo.tree.TreeFilter.prototype = {
34583 * Filter the data by a specific attribute.
34584 * @param {String/RegExp} value Either string that the attribute value
34585 * should start with or a RegExp to test against the attribute
34586 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34587 * @param {TreeNode} startNode (optional) The node to start the filter at.
34589 filter : function(value, attr, startNode){
34590 attr = attr || "text";
34592 if(typeof value == "string"){
34593 var vlen = value.length;
34594 // auto clear empty filter
34595 if(vlen == 0 && this.clearBlank){
34599 value = value.toLowerCase();
34601 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34603 }else if(value.exec){ // regex?
34605 return value.test(n.attributes[attr]);
34608 throw 'Illegal filter type, must be string or regex';
34610 this.filterBy(f, null, startNode);
34614 * Filter by a function. The passed function will be called with each
34615 * node in the tree (or from the startNode). If the function returns true, the node is kept
34616 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34617 * @param {Function} fn The filter function
34618 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34620 filterBy : function(fn, scope, startNode){
34621 startNode = startNode || this.tree.root;
34622 if(this.autoClear){
34625 var af = this.filtered, rv = this.reverse;
34626 var f = function(n){
34627 if(n == startNode){
34633 var m = fn.call(scope || n, n);
34641 startNode.cascade(f);
34644 if(typeof id != "function"){
34646 if(n && n.parentNode){
34647 n.parentNode.removeChild(n);
34655 * Clears the current filter. Note: with the "remove" option
34656 * set a filter cannot be cleared.
34658 clear : function(){
34660 var af = this.filtered;
34662 if(typeof id != "function"){
34669 this.filtered = {};
34674 * Ext JS Library 1.1.1
34675 * Copyright(c) 2006-2007, Ext JS, LLC.
34677 * Originally Released Under LGPL - original licence link has changed is not relivant.
34680 * <script type="text/javascript">
34685 * @class Roo.tree.TreeSorter
34686 * Provides sorting of nodes in a TreePanel
34688 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34689 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34690 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34691 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34692 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34693 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34695 * @param {TreePanel} tree
34696 * @param {Object} config
34698 Roo.tree.TreeSorter = function(tree, config){
34699 Roo.apply(this, config);
34700 tree.on("beforechildrenrendered", this.doSort, this);
34701 tree.on("append", this.updateSort, this);
34702 tree.on("insert", this.updateSort, this);
34704 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34705 var p = this.property || "text";
34706 var sortType = this.sortType;
34707 var fs = this.folderSort;
34708 var cs = this.caseSensitive === true;
34709 var leafAttr = this.leafAttr || 'leaf';
34711 this.sortFn = function(n1, n2){
34713 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34716 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34720 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34721 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34723 return dsc ? +1 : -1;
34725 return dsc ? -1 : +1;
34732 Roo.tree.TreeSorter.prototype = {
34733 doSort : function(node){
34734 node.sort(this.sortFn);
34737 compareNodes : function(n1, n2){
34738 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34741 updateSort : function(tree, node){
34742 if(node.childrenRendered){
34743 this.doSort.defer(1, this, [node]);
34748 * Ext JS Library 1.1.1
34749 * Copyright(c) 2006-2007, Ext JS, LLC.
34751 * Originally Released Under LGPL - original licence link has changed is not relivant.
34754 * <script type="text/javascript">
34757 if(Roo.dd.DropZone){
34759 Roo.tree.TreeDropZone = function(tree, config){
34760 this.allowParentInsert = false;
34761 this.allowContainerDrop = false;
34762 this.appendOnly = false;
34763 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34765 this.lastInsertClass = "x-tree-no-status";
34766 this.dragOverData = {};
34769 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34770 ddGroup : "TreeDD",
34773 expandDelay : 1000,
34775 expandNode : function(node){
34776 if(node.hasChildNodes() && !node.isExpanded()){
34777 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34781 queueExpand : function(node){
34782 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34785 cancelExpand : function(){
34786 if(this.expandProcId){
34787 clearTimeout(this.expandProcId);
34788 this.expandProcId = false;
34792 isValidDropPoint : function(n, pt, dd, e, data){
34793 if(!n || !data){ return false; }
34794 var targetNode = n.node;
34795 var dropNode = data.node;
34796 // default drop rules
34797 if(!(targetNode && targetNode.isTarget && pt)){
34800 if(pt == "append" && targetNode.allowChildren === false){
34803 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34806 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34809 // reuse the object
34810 var overEvent = this.dragOverData;
34811 overEvent.tree = this.tree;
34812 overEvent.target = targetNode;
34813 overEvent.data = data;
34814 overEvent.point = pt;
34815 overEvent.source = dd;
34816 overEvent.rawEvent = e;
34817 overEvent.dropNode = dropNode;
34818 overEvent.cancel = false;
34819 var result = this.tree.fireEvent("nodedragover", overEvent);
34820 return overEvent.cancel === false && result !== false;
34823 getDropPoint : function(e, n, dd)
34827 return tn.allowChildren !== false ? "append" : false; // always append for root
34829 var dragEl = n.ddel;
34830 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34831 var y = Roo.lib.Event.getPageY(e);
34832 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34834 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34835 var noAppend = tn.allowChildren === false;
34836 if(this.appendOnly || tn.parentNode.allowChildren === false){
34837 return noAppend ? false : "append";
34839 var noBelow = false;
34840 if(!this.allowParentInsert){
34841 noBelow = tn.hasChildNodes() && tn.isExpanded();
34843 var q = (b - t) / (noAppend ? 2 : 3);
34844 if(y >= t && y < (t + q)){
34846 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34853 onNodeEnter : function(n, dd, e, data)
34855 this.cancelExpand();
34858 onNodeOver : function(n, dd, e, data)
34861 var pt = this.getDropPoint(e, n, dd);
34864 // auto node expand check
34865 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34866 this.queueExpand(node);
34867 }else if(pt != "append"){
34868 this.cancelExpand();
34871 // set the insert point style on the target node
34872 var returnCls = this.dropNotAllowed;
34873 if(this.isValidDropPoint(n, pt, dd, e, data)){
34878 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34879 cls = "x-tree-drag-insert-above";
34880 }else if(pt == "below"){
34881 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34882 cls = "x-tree-drag-insert-below";
34884 returnCls = "x-tree-drop-ok-append";
34885 cls = "x-tree-drag-append";
34887 if(this.lastInsertClass != cls){
34888 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34889 this.lastInsertClass = cls;
34896 onNodeOut : function(n, dd, e, data){
34898 this.cancelExpand();
34899 this.removeDropIndicators(n);
34902 onNodeDrop : function(n, dd, e, data){
34903 var point = this.getDropPoint(e, n, dd);
34904 var targetNode = n.node;
34905 targetNode.ui.startDrop();
34906 if(!this.isValidDropPoint(n, point, dd, e, data)){
34907 targetNode.ui.endDrop();
34910 // first try to find the drop node
34911 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34914 target: targetNode,
34919 dropNode: dropNode,
34922 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34923 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34924 targetNode.ui.endDrop();
34927 // allow target changing
34928 targetNode = dropEvent.target;
34929 if(point == "append" && !targetNode.isExpanded()){
34930 targetNode.expand(false, null, function(){
34931 this.completeDrop(dropEvent);
34932 }.createDelegate(this));
34934 this.completeDrop(dropEvent);
34939 completeDrop : function(de){
34940 var ns = de.dropNode, p = de.point, t = de.target;
34941 if(!(ns instanceof Array)){
34945 for(var i = 0, len = ns.length; i < len; i++){
34948 t.parentNode.insertBefore(n, t);
34949 }else if(p == "below"){
34950 t.parentNode.insertBefore(n, t.nextSibling);
34956 if(this.tree.hlDrop){
34960 this.tree.fireEvent("nodedrop", de);
34963 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34964 if(this.tree.hlDrop){
34965 dropNode.ui.focus();
34966 dropNode.ui.highlight();
34968 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34971 getTree : function(){
34975 removeDropIndicators : function(n){
34978 Roo.fly(el).removeClass([
34979 "x-tree-drag-insert-above",
34980 "x-tree-drag-insert-below",
34981 "x-tree-drag-append"]);
34982 this.lastInsertClass = "_noclass";
34986 beforeDragDrop : function(target, e, id){
34987 this.cancelExpand();
34991 afterRepair : function(data){
34992 if(data && Roo.enableFx){
34993 data.node.ui.highlight();
35003 * Ext JS Library 1.1.1
35004 * Copyright(c) 2006-2007, Ext JS, LLC.
35006 * Originally Released Under LGPL - original licence link has changed is not relivant.
35009 * <script type="text/javascript">
35013 if(Roo.dd.DragZone){
35014 Roo.tree.TreeDragZone = function(tree, config){
35015 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35019 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35020 ddGroup : "TreeDD",
35022 onBeforeDrag : function(data, e){
35024 return n && n.draggable && !n.disabled;
35028 onInitDrag : function(e){
35029 var data = this.dragData;
35030 this.tree.getSelectionModel().select(data.node);
35031 this.proxy.update("");
35032 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35033 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35036 getRepairXY : function(e, data){
35037 return data.node.ui.getDDRepairXY();
35040 onEndDrag : function(data, e){
35041 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35046 onValidDrop : function(dd, e, id){
35047 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35051 beforeInvalidDrop : function(e, id){
35052 // this scrolls the original position back into view
35053 var sm = this.tree.getSelectionModel();
35054 sm.clearSelections();
35055 sm.select(this.dragData.node);
35060 * Ext JS Library 1.1.1
35061 * Copyright(c) 2006-2007, Ext JS, LLC.
35063 * Originally Released Under LGPL - original licence link has changed is not relivant.
35066 * <script type="text/javascript">
35069 * @class Roo.tree.TreeEditor
35070 * @extends Roo.Editor
35071 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35072 * as the editor field.
35074 * @param {Object} config (used to be the tree panel.)
35075 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35077 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35078 * @cfg {Roo.form.TextField|Object} field The field configuration
35082 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35085 if (oldconfig) { // old style..
35086 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35089 tree = config.tree;
35090 config.field = config.field || {};
35091 config.field.xtype = 'TextField';
35092 field = Roo.factory(config.field, Roo.form);
35094 config = config || {};
35099 * @event beforenodeedit
35100 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35101 * false from the handler of this event.
35102 * @param {Editor} this
35103 * @param {Roo.tree.Node} node
35105 "beforenodeedit" : true
35109 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35113 tree.on('beforeclick', this.beforeNodeClick, this);
35114 tree.getTreeEl().on('mousedown', this.hide, this);
35115 this.on('complete', this.updateNode, this);
35116 this.on('beforestartedit', this.fitToTree, this);
35117 this.on('startedit', this.bindScroll, this, {delay:10});
35118 this.on('specialkey', this.onSpecialKey, this);
35121 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35123 * @cfg {String} alignment
35124 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35130 * @cfg {Boolean} hideEl
35131 * True to hide the bound element while the editor is displayed (defaults to false)
35135 * @cfg {String} cls
35136 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35138 cls: "x-small-editor x-tree-editor",
35140 * @cfg {Boolean} shim
35141 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35147 * @cfg {Number} maxWidth
35148 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35149 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35150 * scroll and client offsets into account prior to each edit.
35157 fitToTree : function(ed, el){
35158 var td = this.tree.getTreeEl().dom, nd = el.dom;
35159 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35160 td.scrollLeft = nd.offsetLeft;
35164 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35165 this.setSize(w, '');
35167 return this.fireEvent('beforenodeedit', this, this.editNode);
35172 triggerEdit : function(node){
35173 this.completeEdit();
35174 this.editNode = node;
35175 this.startEdit(node.ui.textNode, node.text);
35179 bindScroll : function(){
35180 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35184 beforeNodeClick : function(node, e){
35185 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35186 this.lastClick = new Date();
35187 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35189 this.triggerEdit(node);
35196 updateNode : function(ed, value){
35197 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35198 this.editNode.setText(value);
35202 onHide : function(){
35203 Roo.tree.TreeEditor.superclass.onHide.call(this);
35205 this.editNode.ui.focus();
35210 onSpecialKey : function(field, e){
35211 var k = e.getKey();
35215 }else if(k == e.ENTER && !e.hasModifier()){
35217 this.completeEdit();
35220 });//<Script type="text/javascript">
35223 * Ext JS Library 1.1.1
35224 * Copyright(c) 2006-2007, Ext JS, LLC.
35226 * Originally Released Under LGPL - original licence link has changed is not relivant.
35229 * <script type="text/javascript">
35233 * Not documented??? - probably should be...
35236 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35237 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35239 renderElements : function(n, a, targetNode, bulkRender){
35240 //consel.log("renderElements?");
35241 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35243 var t = n.getOwnerTree();
35244 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35246 var cols = t.columns;
35247 var bw = t.borderWidth;
35249 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35250 var cb = typeof a.checked == "boolean";
35251 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35252 var colcls = 'x-t-' + tid + '-c0';
35254 '<li class="x-tree-node">',
35257 '<div class="x-tree-node-el ', a.cls,'">',
35259 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35262 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35263 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35264 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35265 (a.icon ? ' x-tree-node-inline-icon' : ''),
35266 (a.iconCls ? ' '+a.iconCls : ''),
35267 '" unselectable="on" />',
35268 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35269 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35271 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35272 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35273 '<span unselectable="on" qtip="' + tx + '">',
35277 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35278 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35280 for(var i = 1, len = cols.length; i < len; i++){
35282 colcls = 'x-t-' + tid + '-c' +i;
35283 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35284 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35285 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35291 '<div class="x-clear"></div></div>',
35292 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35295 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35296 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35297 n.nextSibling.ui.getEl(), buf.join(""));
35299 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35301 var el = this.wrap.firstChild;
35303 this.elNode = el.firstChild;
35304 this.ranchor = el.childNodes[1];
35305 this.ctNode = this.wrap.childNodes[1];
35306 var cs = el.firstChild.childNodes;
35307 this.indentNode = cs[0];
35308 this.ecNode = cs[1];
35309 this.iconNode = cs[2];
35312 this.checkbox = cs[3];
35315 this.anchor = cs[index];
35317 this.textNode = cs[index].firstChild;
35319 //el.on("click", this.onClick, this);
35320 //el.on("dblclick", this.onDblClick, this);
35323 // console.log(this);
35325 initEvents : function(){
35326 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35329 var a = this.ranchor;
35331 var el = Roo.get(a);
35333 if(Roo.isOpera){ // opera render bug ignores the CSS
35334 el.setStyle("text-decoration", "none");
35337 el.on("click", this.onClick, this);
35338 el.on("dblclick", this.onDblClick, this);
35339 el.on("contextmenu", this.onContextMenu, this);
35343 /*onSelectedChange : function(state){
35346 this.addClass("x-tree-selected");
35349 this.removeClass("x-tree-selected");
35352 addClass : function(cls){
35354 Roo.fly(this.elRow).addClass(cls);
35360 removeClass : function(cls){
35362 Roo.fly(this.elRow).removeClass(cls);
35368 });//<Script type="text/javascript">
35372 * Ext JS Library 1.1.1
35373 * Copyright(c) 2006-2007, Ext JS, LLC.
35375 * Originally Released Under LGPL - original licence link has changed is not relivant.
35378 * <script type="text/javascript">
35383 * @class Roo.tree.ColumnTree
35384 * @extends Roo.data.TreePanel
35385 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35386 * @cfg {int} borderWidth compined right/left border allowance
35388 * @param {String/HTMLElement/Element} el The container element
35389 * @param {Object} config
35391 Roo.tree.ColumnTree = function(el, config)
35393 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35397 * Fire this event on a container when it resizes
35398 * @param {int} w Width
35399 * @param {int} h Height
35403 this.on('resize', this.onResize, this);
35406 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35410 borderWidth: Roo.isBorderBox ? 0 : 2,
35413 render : function(){
35414 // add the header.....
35416 Roo.tree.ColumnTree.superclass.render.apply(this);
35418 this.el.addClass('x-column-tree');
35420 this.headers = this.el.createChild(
35421 {cls:'x-tree-headers'},this.innerCt.dom);
35423 var cols = this.columns, c;
35424 var totalWidth = 0;
35426 var len = cols.length;
35427 for(var i = 0; i < len; i++){
35429 totalWidth += c.width;
35430 this.headEls.push(this.headers.createChild({
35431 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35433 cls:'x-tree-hd-text',
35436 style:'width:'+(c.width-this.borderWidth)+'px;'
35439 this.headers.createChild({cls:'x-clear'});
35440 // prevent floats from wrapping when clipped
35441 this.headers.setWidth(totalWidth);
35442 //this.innerCt.setWidth(totalWidth);
35443 this.innerCt.setStyle({ overflow: 'auto' });
35444 this.onResize(this.width, this.height);
35448 onResize : function(w,h)
35453 this.innerCt.setWidth(this.width);
35454 this.innerCt.setHeight(this.height-20);
35457 var cols = this.columns, c;
35458 var totalWidth = 0;
35460 var len = cols.length;
35461 for(var i = 0; i < len; i++){
35463 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35464 // it's the expander..
35465 expEl = this.headEls[i];
35468 totalWidth += c.width;
35472 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35474 this.headers.setWidth(w-20);
35483 * Ext JS Library 1.1.1
35484 * Copyright(c) 2006-2007, Ext JS, LLC.
35486 * Originally Released Under LGPL - original licence link has changed is not relivant.
35489 * <script type="text/javascript">
35493 * @class Roo.menu.Menu
35494 * @extends Roo.util.Observable
35495 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35496 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35498 * Creates a new Menu
35499 * @param {Object} config Configuration options
35501 Roo.menu.Menu = function(config){
35502 Roo.apply(this, config);
35503 this.id = this.id || Roo.id();
35506 * @event beforeshow
35507 * Fires before this menu is displayed
35508 * @param {Roo.menu.Menu} this
35512 * @event beforehide
35513 * Fires before this menu is hidden
35514 * @param {Roo.menu.Menu} this
35519 * Fires after this menu is displayed
35520 * @param {Roo.menu.Menu} this
35525 * Fires after this menu is hidden
35526 * @param {Roo.menu.Menu} this
35531 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35532 * @param {Roo.menu.Menu} this
35533 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35534 * @param {Roo.EventObject} e
35539 * Fires when the mouse is hovering over this menu
35540 * @param {Roo.menu.Menu} this
35541 * @param {Roo.EventObject} e
35542 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35547 * Fires when the mouse exits this menu
35548 * @param {Roo.menu.Menu} this
35549 * @param {Roo.EventObject} e
35550 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35555 * Fires when a menu item contained in this menu is clicked
35556 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35557 * @param {Roo.EventObject} e
35561 if (this.registerMenu) {
35562 Roo.menu.MenuMgr.register(this);
35565 var mis = this.items;
35566 this.items = new Roo.util.MixedCollection();
35568 this.add.apply(this, mis);
35572 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35574 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35578 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35579 * for bottom-right shadow (defaults to "sides")
35583 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35584 * this menu (defaults to "tl-tr?")
35586 subMenuAlign : "tl-tr?",
35588 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35589 * relative to its element of origin (defaults to "tl-bl?")
35591 defaultAlign : "tl-bl?",
35593 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35595 allowOtherMenus : false,
35597 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35599 registerMenu : true,
35604 render : function(){
35608 var el = this.el = new Roo.Layer({
35610 shadow:this.shadow,
35612 parentEl: this.parentEl || document.body,
35616 this.keyNav = new Roo.menu.MenuNav(this);
35619 el.addClass("x-menu-plain");
35622 el.addClass(this.cls);
35624 // generic focus element
35625 this.focusEl = el.createChild({
35626 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35628 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35629 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35631 ul.on("mouseover", this.onMouseOver, this);
35632 ul.on("mouseout", this.onMouseOut, this);
35633 this.items.each(function(item){
35638 var li = document.createElement("li");
35639 li.className = "x-menu-list-item";
35640 ul.dom.appendChild(li);
35641 item.render(li, this);
35648 autoWidth : function(){
35649 var el = this.el, ul = this.ul;
35653 var w = this.width;
35656 }else if(Roo.isIE){
35657 el.setWidth(this.minWidth);
35658 var t = el.dom.offsetWidth; // force recalc
35659 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35664 delayAutoWidth : function(){
35667 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35669 this.awTask.delay(20);
35674 findTargetItem : function(e){
35675 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35676 if(t && t.menuItemId){
35677 return this.items.get(t.menuItemId);
35682 onClick : function(e){
35683 Roo.log("menu.onClick");
35684 var t = this.findTargetItem(e);
35689 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35690 if(t == this.activeItem && t.shouldDeactivate(e)){
35691 this.activeItem.deactivate();
35692 delete this.activeItem;
35696 this.setActiveItem(t, true);
35704 this.fireEvent("click", this, t, e);
35708 setActiveItem : function(item, autoExpand){
35709 if(item != this.activeItem){
35710 if(this.activeItem){
35711 this.activeItem.deactivate();
35713 this.activeItem = item;
35714 item.activate(autoExpand);
35715 }else if(autoExpand){
35721 tryActivate : function(start, step){
35722 var items = this.items;
35723 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35724 var item = items.get(i);
35725 if(!item.disabled && item.canActivate){
35726 this.setActiveItem(item, false);
35734 onMouseOver : function(e){
35736 if(t = this.findTargetItem(e)){
35737 if(t.canActivate && !t.disabled){
35738 this.setActiveItem(t, true);
35741 this.fireEvent("mouseover", this, e, t);
35745 onMouseOut : function(e){
35747 if(t = this.findTargetItem(e)){
35748 if(t == this.activeItem && t.shouldDeactivate(e)){
35749 this.activeItem.deactivate();
35750 delete this.activeItem;
35753 this.fireEvent("mouseout", this, e, t);
35757 * Read-only. Returns true if the menu is currently displayed, else false.
35760 isVisible : function(){
35761 return this.el && !this.hidden;
35765 * Displays this menu relative to another element
35766 * @param {String/HTMLElement/Roo.Element} element The element to align to
35767 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35768 * the element (defaults to this.defaultAlign)
35769 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35771 show : function(el, pos, parentMenu){
35772 this.parentMenu = parentMenu;
35776 this.fireEvent("beforeshow", this);
35777 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35781 * Displays this menu at a specific xy position
35782 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35783 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35785 showAt : function(xy, parentMenu, /* private: */_e){
35786 this.parentMenu = parentMenu;
35791 this.fireEvent("beforeshow", this);
35792 xy = this.el.adjustForConstraints(xy);
35796 this.hidden = false;
35798 this.fireEvent("show", this);
35801 focus : function(){
35803 this.doFocus.defer(50, this);
35807 doFocus : function(){
35809 this.focusEl.focus();
35814 * Hides this menu and optionally all parent menus
35815 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35817 hide : function(deep){
35818 if(this.el && this.isVisible()){
35819 this.fireEvent("beforehide", this);
35820 if(this.activeItem){
35821 this.activeItem.deactivate();
35822 this.activeItem = null;
35825 this.hidden = true;
35826 this.fireEvent("hide", this);
35828 if(deep === true && this.parentMenu){
35829 this.parentMenu.hide(true);
35834 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35835 * Any of the following are valid:
35837 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35838 * <li>An HTMLElement object which will be converted to a menu item</li>
35839 * <li>A menu item config object that will be created as a new menu item</li>
35840 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35841 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35846 var menu = new Roo.menu.Menu();
35848 // Create a menu item to add by reference
35849 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35851 // Add a bunch of items at once using different methods.
35852 // Only the last item added will be returned.
35853 var item = menu.add(
35854 menuItem, // add existing item by ref
35855 'Dynamic Item', // new TextItem
35856 '-', // new separator
35857 { text: 'Config Item' } // new item by config
35860 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35861 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35864 var a = arguments, l = a.length, item;
35865 for(var i = 0; i < l; i++){
35867 if ((typeof(el) == "object") && el.xtype && el.xns) {
35868 el = Roo.factory(el, Roo.menu);
35871 if(el.render){ // some kind of Item
35872 item = this.addItem(el);
35873 }else if(typeof el == "string"){ // string
35874 if(el == "separator" || el == "-"){
35875 item = this.addSeparator();
35877 item = this.addText(el);
35879 }else if(el.tagName || el.el){ // element
35880 item = this.addElement(el);
35881 }else if(typeof el == "object"){ // must be menu item config?
35882 item = this.addMenuItem(el);
35889 * Returns this menu's underlying {@link Roo.Element} object
35890 * @return {Roo.Element} The element
35892 getEl : function(){
35900 * Adds a separator bar to the menu
35901 * @return {Roo.menu.Item} The menu item that was added
35903 addSeparator : function(){
35904 return this.addItem(new Roo.menu.Separator());
35908 * Adds an {@link Roo.Element} object to the menu
35909 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35910 * @return {Roo.menu.Item} The menu item that was added
35912 addElement : function(el){
35913 return this.addItem(new Roo.menu.BaseItem(el));
35917 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35918 * @param {Roo.menu.Item} item The menu item to add
35919 * @return {Roo.menu.Item} The menu item that was added
35921 addItem : function(item){
35922 this.items.add(item);
35924 var li = document.createElement("li");
35925 li.className = "x-menu-list-item";
35926 this.ul.dom.appendChild(li);
35927 item.render(li, this);
35928 this.delayAutoWidth();
35934 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35935 * @param {Object} config A MenuItem config object
35936 * @return {Roo.menu.Item} The menu item that was added
35938 addMenuItem : function(config){
35939 if(!(config instanceof Roo.menu.Item)){
35940 if(typeof config.checked == "boolean"){ // must be check menu item config?
35941 config = new Roo.menu.CheckItem(config);
35943 config = new Roo.menu.Item(config);
35946 return this.addItem(config);
35950 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35951 * @param {String} text The text to display in the menu item
35952 * @return {Roo.menu.Item} The menu item that was added
35954 addText : function(text){
35955 return this.addItem(new Roo.menu.TextItem({ text : text }));
35959 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35960 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35961 * @param {Roo.menu.Item} item The menu item to add
35962 * @return {Roo.menu.Item} The menu item that was added
35964 insert : function(index, item){
35965 this.items.insert(index, item);
35967 var li = document.createElement("li");
35968 li.className = "x-menu-list-item";
35969 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35970 item.render(li, this);
35971 this.delayAutoWidth();
35977 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35978 * @param {Roo.menu.Item} item The menu item to remove
35980 remove : function(item){
35981 this.items.removeKey(item.id);
35986 * Removes and destroys all items in the menu
35988 removeAll : function(){
35990 while(f = this.items.first()){
35996 // MenuNav is a private utility class used internally by the Menu
35997 Roo.menu.MenuNav = function(menu){
35998 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35999 this.scope = this.menu = menu;
36002 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36003 doRelay : function(e, h){
36004 var k = e.getKey();
36005 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36006 this.menu.tryActivate(0, 1);
36009 return h.call(this.scope || this, e, this.menu);
36012 up : function(e, m){
36013 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36014 m.tryActivate(m.items.length-1, -1);
36018 down : function(e, m){
36019 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36020 m.tryActivate(0, 1);
36024 right : function(e, m){
36026 m.activeItem.expandMenu(true);
36030 left : function(e, m){
36032 if(m.parentMenu && m.parentMenu.activeItem){
36033 m.parentMenu.activeItem.activate();
36037 enter : function(e, m){
36039 e.stopPropagation();
36040 m.activeItem.onClick(e);
36041 m.fireEvent("click", this, m.activeItem);
36047 * Ext JS Library 1.1.1
36048 * Copyright(c) 2006-2007, Ext JS, LLC.
36050 * Originally Released Under LGPL - original licence link has changed is not relivant.
36053 * <script type="text/javascript">
36057 * @class Roo.menu.MenuMgr
36058 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36061 Roo.menu.MenuMgr = function(){
36062 var menus, active, groups = {}, attached = false, lastShow = new Date();
36064 // private - called when first menu is created
36067 active = new Roo.util.MixedCollection();
36068 Roo.get(document).addKeyListener(27, function(){
36069 if(active.length > 0){
36076 function hideAll(){
36077 if(active && active.length > 0){
36078 var c = active.clone();
36079 c.each(function(m){
36086 function onHide(m){
36088 if(active.length < 1){
36089 Roo.get(document).un("mousedown", onMouseDown);
36095 function onShow(m){
36096 var last = active.last();
36097 lastShow = new Date();
36100 Roo.get(document).on("mousedown", onMouseDown);
36104 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36105 m.parentMenu.activeChild = m;
36106 }else if(last && last.isVisible()){
36107 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36112 function onBeforeHide(m){
36114 m.activeChild.hide();
36116 if(m.autoHideTimer){
36117 clearTimeout(m.autoHideTimer);
36118 delete m.autoHideTimer;
36123 function onBeforeShow(m){
36124 var pm = m.parentMenu;
36125 if(!pm && !m.allowOtherMenus){
36127 }else if(pm && pm.activeChild && active != m){
36128 pm.activeChild.hide();
36133 function onMouseDown(e){
36134 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36140 function onBeforeCheck(mi, state){
36142 var g = groups[mi.group];
36143 for(var i = 0, l = g.length; i < l; i++){
36145 g[i].setChecked(false);
36154 * Hides all menus that are currently visible
36156 hideAll : function(){
36161 register : function(menu){
36165 menus[menu.id] = menu;
36166 menu.on("beforehide", onBeforeHide);
36167 menu.on("hide", onHide);
36168 menu.on("beforeshow", onBeforeShow);
36169 menu.on("show", onShow);
36170 var g = menu.group;
36171 if(g && menu.events["checkchange"]){
36175 groups[g].push(menu);
36176 menu.on("checkchange", onCheck);
36181 * Returns a {@link Roo.menu.Menu} object
36182 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36183 * be used to generate and return a new Menu instance.
36185 get : function(menu){
36186 if(typeof menu == "string"){ // menu id
36187 return menus[menu];
36188 }else if(menu.events){ // menu instance
36190 }else if(typeof menu.length == 'number'){ // array of menu items?
36191 return new Roo.menu.Menu({items:menu});
36192 }else{ // otherwise, must be a config
36193 return new Roo.menu.Menu(menu);
36198 unregister : function(menu){
36199 delete menus[menu.id];
36200 menu.un("beforehide", onBeforeHide);
36201 menu.un("hide", onHide);
36202 menu.un("beforeshow", onBeforeShow);
36203 menu.un("show", onShow);
36204 var g = menu.group;
36205 if(g && menu.events["checkchange"]){
36206 groups[g].remove(menu);
36207 menu.un("checkchange", onCheck);
36212 registerCheckable : function(menuItem){
36213 var g = menuItem.group;
36218 groups[g].push(menuItem);
36219 menuItem.on("beforecheckchange", onBeforeCheck);
36224 unregisterCheckable : function(menuItem){
36225 var g = menuItem.group;
36227 groups[g].remove(menuItem);
36228 menuItem.un("beforecheckchange", onBeforeCheck);
36234 * Ext JS Library 1.1.1
36235 * Copyright(c) 2006-2007, Ext JS, LLC.
36237 * Originally Released Under LGPL - original licence link has changed is not relivant.
36240 * <script type="text/javascript">
36245 * @class Roo.menu.BaseItem
36246 * @extends Roo.Component
36247 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36248 * management and base configuration options shared by all menu components.
36250 * Creates a new BaseItem
36251 * @param {Object} config Configuration options
36253 Roo.menu.BaseItem = function(config){
36254 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36259 * Fires when this item is clicked
36260 * @param {Roo.menu.BaseItem} this
36261 * @param {Roo.EventObject} e
36266 * Fires when this item is activated
36267 * @param {Roo.menu.BaseItem} this
36271 * @event deactivate
36272 * Fires when this item is deactivated
36273 * @param {Roo.menu.BaseItem} this
36279 this.on("click", this.handler, this.scope, true);
36283 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36285 * @cfg {Function} handler
36286 * A function that will handle the click event of this menu item (defaults to undefined)
36289 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36291 canActivate : false,
36294 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36299 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36301 activeClass : "x-menu-item-active",
36303 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36305 hideOnClick : true,
36307 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36312 ctype: "Roo.menu.BaseItem",
36315 actionMode : "container",
36318 render : function(container, parentMenu){
36319 this.parentMenu = parentMenu;
36320 Roo.menu.BaseItem.superclass.render.call(this, container);
36321 this.container.menuItemId = this.id;
36325 onRender : function(container, position){
36326 this.el = Roo.get(this.el);
36327 container.dom.appendChild(this.el.dom);
36331 onClick : function(e){
36332 if(!this.disabled && this.fireEvent("click", this, e) !== false
36333 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36334 this.handleClick(e);
36341 activate : function(){
36345 var li = this.container;
36346 li.addClass(this.activeClass);
36347 this.region = li.getRegion().adjust(2, 2, -2, -2);
36348 this.fireEvent("activate", this);
36353 deactivate : function(){
36354 this.container.removeClass(this.activeClass);
36355 this.fireEvent("deactivate", this);
36359 shouldDeactivate : function(e){
36360 return !this.region || !this.region.contains(e.getPoint());
36364 handleClick : function(e){
36365 if(this.hideOnClick){
36366 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36371 expandMenu : function(autoActivate){
36376 hideMenu : function(){
36381 * Ext JS Library 1.1.1
36382 * Copyright(c) 2006-2007, Ext JS, LLC.
36384 * Originally Released Under LGPL - original licence link has changed is not relivant.
36387 * <script type="text/javascript">
36391 * @class Roo.menu.Adapter
36392 * @extends Roo.menu.BaseItem
36393 * 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.
36394 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36396 * Creates a new Adapter
36397 * @param {Object} config Configuration options
36399 Roo.menu.Adapter = function(component, config){
36400 Roo.menu.Adapter.superclass.constructor.call(this, config);
36401 this.component = component;
36403 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36405 canActivate : true,
36408 onRender : function(container, position){
36409 this.component.render(container);
36410 this.el = this.component.getEl();
36414 activate : function(){
36418 this.component.focus();
36419 this.fireEvent("activate", this);
36424 deactivate : function(){
36425 this.fireEvent("deactivate", this);
36429 disable : function(){
36430 this.component.disable();
36431 Roo.menu.Adapter.superclass.disable.call(this);
36435 enable : function(){
36436 this.component.enable();
36437 Roo.menu.Adapter.superclass.enable.call(this);
36441 * Ext JS Library 1.1.1
36442 * Copyright(c) 2006-2007, Ext JS, LLC.
36444 * Originally Released Under LGPL - original licence link has changed is not relivant.
36447 * <script type="text/javascript">
36451 * @class Roo.menu.TextItem
36452 * @extends Roo.menu.BaseItem
36453 * Adds a static text string to a menu, usually used as either a heading or group separator.
36454 * Note: old style constructor with text is still supported.
36457 * Creates a new TextItem
36458 * @param {Object} cfg Configuration
36460 Roo.menu.TextItem = function(cfg){
36461 if (typeof(cfg) == 'string') {
36464 Roo.apply(this,cfg);
36467 Roo.menu.TextItem.superclass.constructor.call(this);
36470 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36472 * @cfg {Boolean} text Text to show on item.
36477 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36479 hideOnClick : false,
36481 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36483 itemCls : "x-menu-text",
36486 onRender : function(){
36487 var s = document.createElement("span");
36488 s.className = this.itemCls;
36489 s.innerHTML = this.text;
36491 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36495 * Ext JS Library 1.1.1
36496 * Copyright(c) 2006-2007, Ext JS, LLC.
36498 * Originally Released Under LGPL - original licence link has changed is not relivant.
36501 * <script type="text/javascript">
36505 * @class Roo.menu.Separator
36506 * @extends Roo.menu.BaseItem
36507 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36508 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36510 * @param {Object} config Configuration options
36512 Roo.menu.Separator = function(config){
36513 Roo.menu.Separator.superclass.constructor.call(this, config);
36516 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36518 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36520 itemCls : "x-menu-sep",
36522 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36524 hideOnClick : false,
36527 onRender : function(li){
36528 var s = document.createElement("span");
36529 s.className = this.itemCls;
36530 s.innerHTML = " ";
36532 li.addClass("x-menu-sep-li");
36533 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36537 * Ext JS Library 1.1.1
36538 * Copyright(c) 2006-2007, Ext JS, LLC.
36540 * Originally Released Under LGPL - original licence link has changed is not relivant.
36543 * <script type="text/javascript">
36546 * @class Roo.menu.Item
36547 * @extends Roo.menu.BaseItem
36548 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36549 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36550 * activation and click handling.
36552 * Creates a new Item
36553 * @param {Object} config Configuration options
36555 Roo.menu.Item = function(config){
36556 Roo.menu.Item.superclass.constructor.call(this, config);
36558 this.menu = Roo.menu.MenuMgr.get(this.menu);
36561 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36564 * @cfg {String} text
36565 * The text to show on the menu item.
36569 * @cfg {String} HTML to render in menu
36570 * The text to show on the menu item (HTML version).
36574 * @cfg {String} icon
36575 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36579 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36581 itemCls : "x-menu-item",
36583 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36585 canActivate : true,
36587 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36590 // doc'd in BaseItem
36594 ctype: "Roo.menu.Item",
36597 onRender : function(container, position){
36598 var el = document.createElement("a");
36599 el.hideFocus = true;
36600 el.unselectable = "on";
36601 el.href = this.href || "#";
36602 if(this.hrefTarget){
36603 el.target = this.hrefTarget;
36605 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36607 var html = this.html.length ? this.html : String.format('{0}',this.text);
36609 el.innerHTML = String.format(
36610 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36611 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36613 Roo.menu.Item.superclass.onRender.call(this, container, position);
36617 * Sets the text to display in this menu item
36618 * @param {String} text The text to display
36619 * @param {Boolean} isHTML true to indicate text is pure html.
36621 setText : function(text, isHTML){
36629 var html = this.html.length ? this.html : String.format('{0}',this.text);
36631 this.el.update(String.format(
36632 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36633 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36634 this.parentMenu.autoWidth();
36639 handleClick : function(e){
36640 if(!this.href){ // if no link defined, stop the event automatically
36643 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36647 activate : function(autoExpand){
36648 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36658 shouldDeactivate : function(e){
36659 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36660 if(this.menu && this.menu.isVisible()){
36661 return !this.menu.getEl().getRegion().contains(e.getPoint());
36669 deactivate : function(){
36670 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36675 expandMenu : function(autoActivate){
36676 if(!this.disabled && this.menu){
36677 clearTimeout(this.hideTimer);
36678 delete this.hideTimer;
36679 if(!this.menu.isVisible() && !this.showTimer){
36680 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36681 }else if (this.menu.isVisible() && autoActivate){
36682 this.menu.tryActivate(0, 1);
36688 deferExpand : function(autoActivate){
36689 delete this.showTimer;
36690 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36692 this.menu.tryActivate(0, 1);
36697 hideMenu : function(){
36698 clearTimeout(this.showTimer);
36699 delete this.showTimer;
36700 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36701 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36706 deferHide : function(){
36707 delete this.hideTimer;
36712 * Ext JS Library 1.1.1
36713 * Copyright(c) 2006-2007, Ext JS, LLC.
36715 * Originally Released Under LGPL - original licence link has changed is not relivant.
36718 * <script type="text/javascript">
36722 * @class Roo.menu.CheckItem
36723 * @extends Roo.menu.Item
36724 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36726 * Creates a new CheckItem
36727 * @param {Object} config Configuration options
36729 Roo.menu.CheckItem = function(config){
36730 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36733 * @event beforecheckchange
36734 * Fires before the checked value is set, providing an opportunity to cancel if needed
36735 * @param {Roo.menu.CheckItem} this
36736 * @param {Boolean} checked The new checked value that will be set
36738 "beforecheckchange" : true,
36740 * @event checkchange
36741 * Fires after the checked value has been set
36742 * @param {Roo.menu.CheckItem} this
36743 * @param {Boolean} checked The checked value that was set
36745 "checkchange" : true
36747 if(this.checkHandler){
36748 this.on('checkchange', this.checkHandler, this.scope);
36751 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36753 * @cfg {String} group
36754 * All check items with the same group name will automatically be grouped into a single-select
36755 * radio button group (defaults to '')
36758 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36760 itemCls : "x-menu-item x-menu-check-item",
36762 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36764 groupClass : "x-menu-group-item",
36767 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36768 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36769 * initialized with checked = true will be rendered as checked.
36774 ctype: "Roo.menu.CheckItem",
36777 onRender : function(c){
36778 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36780 this.el.addClass(this.groupClass);
36782 Roo.menu.MenuMgr.registerCheckable(this);
36784 this.checked = false;
36785 this.setChecked(true, true);
36790 destroy : function(){
36792 Roo.menu.MenuMgr.unregisterCheckable(this);
36794 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36798 * Set the checked state of this item
36799 * @param {Boolean} checked The new checked value
36800 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36802 setChecked : function(state, suppressEvent){
36803 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36804 if(this.container){
36805 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36807 this.checked = state;
36808 if(suppressEvent !== true){
36809 this.fireEvent("checkchange", this, state);
36815 handleClick : function(e){
36816 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36817 this.setChecked(!this.checked);
36819 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36823 * Ext JS Library 1.1.1
36824 * Copyright(c) 2006-2007, Ext JS, LLC.
36826 * Originally Released Under LGPL - original licence link has changed is not relivant.
36829 * <script type="text/javascript">
36833 * @class Roo.menu.DateItem
36834 * @extends Roo.menu.Adapter
36835 * A menu item that wraps the {@link Roo.DatPicker} component.
36837 * Creates a new DateItem
36838 * @param {Object} config Configuration options
36840 Roo.menu.DateItem = function(config){
36841 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36842 /** The Roo.DatePicker object @type Roo.DatePicker */
36843 this.picker = this.component;
36844 this.addEvents({select: true});
36846 this.picker.on("render", function(picker){
36847 picker.getEl().swallowEvent("click");
36848 picker.container.addClass("x-menu-date-item");
36851 this.picker.on("select", this.onSelect, this);
36854 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36856 onSelect : function(picker, date){
36857 this.fireEvent("select", this, date, picker);
36858 Roo.menu.DateItem.superclass.handleClick.call(this);
36862 * Ext JS Library 1.1.1
36863 * Copyright(c) 2006-2007, Ext JS, LLC.
36865 * Originally Released Under LGPL - original licence link has changed is not relivant.
36868 * <script type="text/javascript">
36872 * @class Roo.menu.ColorItem
36873 * @extends Roo.menu.Adapter
36874 * A menu item that wraps the {@link Roo.ColorPalette} component.
36876 * Creates a new ColorItem
36877 * @param {Object} config Configuration options
36879 Roo.menu.ColorItem = function(config){
36880 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36881 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36882 this.palette = this.component;
36883 this.relayEvents(this.palette, ["select"]);
36884 if(this.selectHandler){
36885 this.on('select', this.selectHandler, this.scope);
36888 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36890 * Ext JS Library 1.1.1
36891 * Copyright(c) 2006-2007, Ext JS, LLC.
36893 * Originally Released Under LGPL - original licence link has changed is not relivant.
36896 * <script type="text/javascript">
36901 * @class Roo.menu.DateMenu
36902 * @extends Roo.menu.Menu
36903 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36905 * Creates a new DateMenu
36906 * @param {Object} config Configuration options
36908 Roo.menu.DateMenu = function(config){
36909 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36911 var di = new Roo.menu.DateItem(config);
36914 * The {@link Roo.DatePicker} instance for this DateMenu
36917 this.picker = di.picker;
36920 * @param {DatePicker} picker
36921 * @param {Date} date
36923 this.relayEvents(di, ["select"]);
36924 this.on('beforeshow', function(){
36926 this.picker.hideMonthPicker(false);
36930 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36934 * Ext JS Library 1.1.1
36935 * Copyright(c) 2006-2007, Ext JS, LLC.
36937 * Originally Released Under LGPL - original licence link has changed is not relivant.
36940 * <script type="text/javascript">
36945 * @class Roo.menu.ColorMenu
36946 * @extends Roo.menu.Menu
36947 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36949 * Creates a new ColorMenu
36950 * @param {Object} config Configuration options
36952 Roo.menu.ColorMenu = function(config){
36953 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36955 var ci = new Roo.menu.ColorItem(config);
36958 * The {@link Roo.ColorPalette} instance for this ColorMenu
36959 * @type ColorPalette
36961 this.palette = ci.palette;
36964 * @param {ColorPalette} palette
36965 * @param {String} color
36967 this.relayEvents(ci, ["select"]);
36969 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36971 * Ext JS Library 1.1.1
36972 * Copyright(c) 2006-2007, Ext JS, LLC.
36974 * Originally Released Under LGPL - original licence link has changed is not relivant.
36977 * <script type="text/javascript">
36981 * @class Roo.form.Field
36982 * @extends Roo.BoxComponent
36983 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36985 * Creates a new Field
36986 * @param {Object} config Configuration options
36988 Roo.form.Field = function(config){
36989 Roo.form.Field.superclass.constructor.call(this, config);
36992 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36994 * @cfg {String} fieldLabel Label to use when rendering a form.
36997 * @cfg {String} qtip Mouse over tip
37001 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37003 invalidClass : "x-form-invalid",
37005 * @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")
37007 invalidText : "The value in this field is invalid",
37009 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37011 focusClass : "x-form-focus",
37013 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37014 automatic validation (defaults to "keyup").
37016 validationEvent : "keyup",
37018 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37020 validateOnBlur : true,
37022 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37024 validationDelay : 250,
37026 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37027 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37029 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
37031 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37033 fieldClass : "x-form-field",
37035 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37038 ----------- ----------------------------------------------------------------------
37039 qtip Display a quick tip when the user hovers over the field
37040 title Display a default browser title attribute popup
37041 under Add a block div beneath the field containing the error text
37042 side Add an error icon to the right of the field with a popup on hover
37043 [element id] Add the error text directly to the innerHTML of the specified element
37046 msgTarget : 'qtip',
37048 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37053 * @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.
37058 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37063 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37065 inputType : undefined,
37068 * @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).
37070 tabIndex : undefined,
37073 isFormField : true,
37078 * @property {Roo.Element} fieldEl
37079 * Element Containing the rendered Field (with label etc.)
37082 * @cfg {Mixed} value A value to initialize this field with.
37087 * @cfg {String} name The field's HTML name attribute.
37090 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37094 initComponent : function(){
37095 Roo.form.Field.superclass.initComponent.call(this);
37099 * Fires when this field receives input focus.
37100 * @param {Roo.form.Field} this
37105 * Fires when this field loses input focus.
37106 * @param {Roo.form.Field} this
37110 * @event specialkey
37111 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37112 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37113 * @param {Roo.form.Field} this
37114 * @param {Roo.EventObject} e The event object
37119 * Fires just before the field blurs if the field value has changed.
37120 * @param {Roo.form.Field} this
37121 * @param {Mixed} newValue The new value
37122 * @param {Mixed} oldValue The original value
37127 * Fires after the field has been marked as invalid.
37128 * @param {Roo.form.Field} this
37129 * @param {String} msg The validation message
37134 * Fires after the field has been validated with no errors.
37135 * @param {Roo.form.Field} this
37140 * Fires after the key up
37141 * @param {Roo.form.Field} this
37142 * @param {Roo.EventObject} e The event Object
37149 * Returns the name attribute of the field if available
37150 * @return {String} name The field name
37152 getName: function(){
37153 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37157 onRender : function(ct, position){
37158 Roo.form.Field.superclass.onRender.call(this, ct, position);
37160 var cfg = this.getAutoCreate();
37162 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37164 if (!cfg.name.length) {
37167 if(this.inputType){
37168 cfg.type = this.inputType;
37170 this.el = ct.createChild(cfg, position);
37172 var type = this.el.dom.type;
37174 if(type == 'password'){
37177 this.el.addClass('x-form-'+type);
37180 this.el.dom.readOnly = true;
37182 if(this.tabIndex !== undefined){
37183 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37186 this.el.addClass([this.fieldClass, this.cls]);
37191 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37192 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37193 * @return {Roo.form.Field} this
37195 applyTo : function(target){
37196 this.allowDomMove = false;
37197 this.el = Roo.get(target);
37198 this.render(this.el.dom.parentNode);
37203 initValue : function(){
37204 if(this.value !== undefined){
37205 this.setValue(this.value);
37206 }else if(this.el.dom.value.length > 0){
37207 this.setValue(this.el.dom.value);
37212 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37214 isDirty : function() {
37215 if(this.disabled) {
37218 return String(this.getValue()) !== String(this.originalValue);
37222 afterRender : function(){
37223 Roo.form.Field.superclass.afterRender.call(this);
37228 fireKey : function(e){
37229 //Roo.log('field ' + e.getKey());
37230 if(e.isNavKeyPress()){
37231 this.fireEvent("specialkey", this, e);
37236 * Resets the current field value to the originally loaded value and clears any validation messages
37238 reset : function(){
37239 this.setValue(this.resetValue);
37240 this.clearInvalid();
37244 initEvents : function(){
37245 // safari killled keypress - so keydown is now used..
37246 this.el.on("keydown" , this.fireKey, this);
37247 this.el.on("focus", this.onFocus, this);
37248 this.el.on("blur", this.onBlur, this);
37249 this.el.relayEvent('keyup', this);
37251 // reference to original value for reset
37252 this.originalValue = this.getValue();
37253 this.resetValue = this.getValue();
37257 onFocus : function(){
37258 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37259 this.el.addClass(this.focusClass);
37261 if(!this.hasFocus){
37262 this.hasFocus = true;
37263 this.startValue = this.getValue();
37264 this.fireEvent("focus", this);
37268 beforeBlur : Roo.emptyFn,
37271 onBlur : function(){
37273 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37274 this.el.removeClass(this.focusClass);
37276 this.hasFocus = false;
37277 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37280 var v = this.getValue();
37281 if(String(v) !== String(this.startValue)){
37282 this.fireEvent('change', this, v, this.startValue);
37284 this.fireEvent("blur", this);
37288 * Returns whether or not the field value is currently valid
37289 * @param {Boolean} preventMark True to disable marking the field invalid
37290 * @return {Boolean} True if the value is valid, else false
37292 isValid : function(preventMark){
37296 var restore = this.preventMark;
37297 this.preventMark = preventMark === true;
37298 var v = this.validateValue(this.processValue(this.getRawValue()));
37299 this.preventMark = restore;
37304 * Validates the field value
37305 * @return {Boolean} True if the value is valid, else false
37307 validate : function(){
37308 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37309 this.clearInvalid();
37315 processValue : function(value){
37320 // Subclasses should provide the validation implementation by overriding this
37321 validateValue : function(value){
37326 * Mark this field as invalid
37327 * @param {String} msg The validation message
37329 markInvalid : function(msg){
37330 if(!this.rendered || this.preventMark){ // not rendered
37334 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37336 obj.el.addClass(this.invalidClass);
37337 msg = msg || this.invalidText;
37338 switch(this.msgTarget){
37340 obj.el.dom.qtip = msg;
37341 obj.el.dom.qclass = 'x-form-invalid-tip';
37342 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37343 Roo.QuickTips.enable();
37347 this.el.dom.title = msg;
37351 var elp = this.el.findParent('.x-form-element', 5, true);
37352 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37353 this.errorEl.setWidth(elp.getWidth(true)-20);
37355 this.errorEl.update(msg);
37356 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37359 if(!this.errorIcon){
37360 var elp = this.el.findParent('.x-form-element', 5, true);
37361 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37363 this.alignErrorIcon();
37364 this.errorIcon.dom.qtip = msg;
37365 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37366 this.errorIcon.show();
37367 this.on('resize', this.alignErrorIcon, this);
37370 var t = Roo.getDom(this.msgTarget);
37372 t.style.display = this.msgDisplay;
37375 this.fireEvent('invalid', this, msg);
37379 alignErrorIcon : function(){
37380 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37384 * Clear any invalid styles/messages for this field
37386 clearInvalid : function(){
37387 if(!this.rendered || this.preventMark){ // not rendered
37390 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37392 obj.el.removeClass(this.invalidClass);
37393 switch(this.msgTarget){
37395 obj.el.dom.qtip = '';
37398 this.el.dom.title = '';
37402 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37406 if(this.errorIcon){
37407 this.errorIcon.dom.qtip = '';
37408 this.errorIcon.hide();
37409 this.un('resize', this.alignErrorIcon, this);
37413 var t = Roo.getDom(this.msgTarget);
37415 t.style.display = 'none';
37418 this.fireEvent('valid', this);
37422 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37423 * @return {Mixed} value The field value
37425 getRawValue : function(){
37426 var v = this.el.getValue();
37432 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37433 * @return {Mixed} value The field value
37435 getValue : function(){
37436 var v = this.el.getValue();
37442 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37443 * @param {Mixed} value The value to set
37445 setRawValue : function(v){
37446 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37450 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37451 * @param {Mixed} value The value to set
37453 setValue : function(v){
37456 this.el.dom.value = (v === null || v === undefined ? '' : v);
37461 adjustSize : function(w, h){
37462 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37463 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37467 adjustWidth : function(tag, w){
37468 tag = tag.toLowerCase();
37469 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37470 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37471 if(tag == 'input'){
37474 if(tag == 'textarea'){
37477 }else if(Roo.isOpera){
37478 if(tag == 'input'){
37481 if(tag == 'textarea'){
37491 // anything other than normal should be considered experimental
37492 Roo.form.Field.msgFx = {
37494 show: function(msgEl, f){
37495 msgEl.setDisplayed('block');
37498 hide : function(msgEl, f){
37499 msgEl.setDisplayed(false).update('');
37504 show: function(msgEl, f){
37505 msgEl.slideIn('t', {stopFx:true});
37508 hide : function(msgEl, f){
37509 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37514 show: function(msgEl, f){
37515 msgEl.fixDisplay();
37516 msgEl.alignTo(f.el, 'tl-tr');
37517 msgEl.slideIn('l', {stopFx:true});
37520 hide : function(msgEl, f){
37521 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37526 * Ext JS Library 1.1.1
37527 * Copyright(c) 2006-2007, Ext JS, LLC.
37529 * Originally Released Under LGPL - original licence link has changed is not relivant.
37532 * <script type="text/javascript">
37537 * @class Roo.form.TextField
37538 * @extends Roo.form.Field
37539 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37540 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37542 * Creates a new TextField
37543 * @param {Object} config Configuration options
37545 Roo.form.TextField = function(config){
37546 Roo.form.TextField.superclass.constructor.call(this, config);
37550 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37551 * according to the default logic, but this event provides a hook for the developer to apply additional
37552 * logic at runtime to resize the field if needed.
37553 * @param {Roo.form.Field} this This text field
37554 * @param {Number} width The new field width
37560 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37562 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37566 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37570 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37574 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37578 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37582 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37584 disableKeyFilter : false,
37586 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37590 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37594 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37596 maxLength : Number.MAX_VALUE,
37598 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37600 minLengthText : "The minimum length for this field is {0}",
37602 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37604 maxLengthText : "The maximum length for this field is {0}",
37606 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37608 selectOnFocus : false,
37610 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37612 blankText : "This field is required",
37614 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37615 * If available, this function will be called only after the basic validators all return true, and will be passed the
37616 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37620 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37621 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37622 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37626 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37630 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37636 initEvents : function()
37638 if (this.emptyText) {
37639 this.el.attr('placeholder', this.emptyText);
37642 Roo.form.TextField.superclass.initEvents.call(this);
37643 if(this.validationEvent == 'keyup'){
37644 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37645 this.el.on('keyup', this.filterValidation, this);
37647 else if(this.validationEvent !== false){
37648 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37651 if(this.selectOnFocus){
37652 this.on("focus", this.preFocus, this);
37655 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37656 this.el.on("keypress", this.filterKeys, this);
37659 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37660 this.el.on("click", this.autoSize, this);
37662 if(this.el.is('input[type=password]') && Roo.isSafari){
37663 this.el.on('keydown', this.SafariOnKeyDown, this);
37667 processValue : function(value){
37668 if(this.stripCharsRe){
37669 var newValue = value.replace(this.stripCharsRe, '');
37670 if(newValue !== value){
37671 this.setRawValue(newValue);
37678 filterValidation : function(e){
37679 if(!e.isNavKeyPress()){
37680 this.validationTask.delay(this.validationDelay);
37685 onKeyUp : function(e){
37686 if(!e.isNavKeyPress()){
37692 * Resets the current field value to the originally-loaded value and clears any validation messages.
37695 reset : function(){
37696 Roo.form.TextField.superclass.reset.call(this);
37702 preFocus : function(){
37704 if(this.selectOnFocus){
37705 this.el.dom.select();
37711 filterKeys : function(e){
37712 var k = e.getKey();
37713 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37716 var c = e.getCharCode(), cc = String.fromCharCode(c);
37717 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37720 if(!this.maskRe.test(cc)){
37725 setValue : function(v){
37727 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37733 * Validates a value according to the field's validation rules and marks the field as invalid
37734 * if the validation fails
37735 * @param {Mixed} value The value to validate
37736 * @return {Boolean} True if the value is valid, else false
37738 validateValue : function(value){
37739 if(value.length < 1) { // if it's blank
37740 if(this.allowBlank){
37741 this.clearInvalid();
37744 this.markInvalid(this.blankText);
37748 if(value.length < this.minLength){
37749 this.markInvalid(String.format(this.minLengthText, this.minLength));
37752 if(value.length > this.maxLength){
37753 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37757 var vt = Roo.form.VTypes;
37758 if(!vt[this.vtype](value, this)){
37759 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37763 if(typeof this.validator == "function"){
37764 var msg = this.validator(value);
37766 this.markInvalid(msg);
37770 if(this.regex && !this.regex.test(value)){
37771 this.markInvalid(this.regexText);
37778 * Selects text in this field
37779 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37780 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37782 selectText : function(start, end){
37783 var v = this.getRawValue();
37785 start = start === undefined ? 0 : start;
37786 end = end === undefined ? v.length : end;
37787 var d = this.el.dom;
37788 if(d.setSelectionRange){
37789 d.setSelectionRange(start, end);
37790 }else if(d.createTextRange){
37791 var range = d.createTextRange();
37792 range.moveStart("character", start);
37793 range.moveEnd("character", v.length-end);
37800 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37801 * This only takes effect if grow = true, and fires the autosize event.
37803 autoSize : function(){
37804 if(!this.grow || !this.rendered){
37808 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37811 var v = el.dom.value;
37812 var d = document.createElement('div');
37813 d.appendChild(document.createTextNode(v));
37817 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37818 this.el.setWidth(w);
37819 this.fireEvent("autosize", this, w);
37823 SafariOnKeyDown : function(event)
37825 // this is a workaround for a password hang bug on chrome/ webkit.
37827 var isSelectAll = false;
37829 if(this.el.dom.selectionEnd > 0){
37830 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37832 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37833 event.preventDefault();
37838 if(isSelectAll){ // backspace and delete key
37840 event.preventDefault();
37841 // this is very hacky as keydown always get's upper case.
37843 var cc = String.fromCharCode(event.getCharCode());
37844 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37852 * Ext JS Library 1.1.1
37853 * Copyright(c) 2006-2007, Ext JS, LLC.
37855 * Originally Released Under LGPL - original licence link has changed is not relivant.
37858 * <script type="text/javascript">
37862 * @class Roo.form.Hidden
37863 * @extends Roo.form.TextField
37864 * Simple Hidden element used on forms
37866 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37869 * Creates a new Hidden form element.
37870 * @param {Object} config Configuration options
37875 // easy hidden field...
37876 Roo.form.Hidden = function(config){
37877 Roo.form.Hidden.superclass.constructor.call(this, config);
37880 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37882 inputType: 'hidden',
37885 labelSeparator: '',
37887 itemCls : 'x-form-item-display-none'
37895 * Ext JS Library 1.1.1
37896 * Copyright(c) 2006-2007, Ext JS, LLC.
37898 * Originally Released Under LGPL - original licence link has changed is not relivant.
37901 * <script type="text/javascript">
37905 * @class Roo.form.TriggerField
37906 * @extends Roo.form.TextField
37907 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37908 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37909 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37910 * for which you can provide a custom implementation. For example:
37912 var trigger = new Roo.form.TriggerField();
37913 trigger.onTriggerClick = myTriggerFn;
37914 trigger.applyTo('my-field');
37917 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37918 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37919 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37920 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37922 * Create a new TriggerField.
37923 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37924 * to the base TextField)
37926 Roo.form.TriggerField = function(config){
37927 this.mimicing = false;
37928 Roo.form.TriggerField.superclass.constructor.call(this, config);
37931 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37933 * @cfg {String} triggerClass A CSS class to apply to the trigger
37936 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37937 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37939 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37941 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37945 /** @cfg {Boolean} grow @hide */
37946 /** @cfg {Number} growMin @hide */
37947 /** @cfg {Number} growMax @hide */
37953 autoSize: Roo.emptyFn,
37957 deferHeight : true,
37960 actionMode : 'wrap',
37962 onResize : function(w, h){
37963 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37964 if(typeof w == 'number'){
37965 var x = w - this.trigger.getWidth();
37966 this.el.setWidth(this.adjustWidth('input', x));
37967 this.trigger.setStyle('left', x+'px');
37972 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37975 getResizeEl : function(){
37980 getPositionEl : function(){
37985 alignErrorIcon : function(){
37986 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37990 onRender : function(ct, position){
37991 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37992 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37993 this.trigger = this.wrap.createChild(this.triggerConfig ||
37994 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37995 if(this.hideTrigger){
37996 this.trigger.setDisplayed(false);
37998 this.initTrigger();
38000 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38005 initTrigger : function(){
38006 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38007 this.trigger.addClassOnOver('x-form-trigger-over');
38008 this.trigger.addClassOnClick('x-form-trigger-click');
38012 onDestroy : function(){
38014 this.trigger.removeAllListeners();
38015 this.trigger.remove();
38018 this.wrap.remove();
38020 Roo.form.TriggerField.superclass.onDestroy.call(this);
38024 onFocus : function(){
38025 Roo.form.TriggerField.superclass.onFocus.call(this);
38026 if(!this.mimicing){
38027 this.wrap.addClass('x-trigger-wrap-focus');
38028 this.mimicing = true;
38029 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38030 if(this.monitorTab){
38031 this.el.on("keydown", this.checkTab, this);
38037 checkTab : function(e){
38038 if(e.getKey() == e.TAB){
38039 this.triggerBlur();
38044 onBlur : function(){
38049 mimicBlur : function(e, t){
38050 if(!this.wrap.contains(t) && this.validateBlur()){
38051 this.triggerBlur();
38056 triggerBlur : function(){
38057 this.mimicing = false;
38058 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38059 if(this.monitorTab){
38060 this.el.un("keydown", this.checkTab, this);
38062 this.wrap.removeClass('x-trigger-wrap-focus');
38063 Roo.form.TriggerField.superclass.onBlur.call(this);
38067 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38068 validateBlur : function(e, t){
38073 onDisable : function(){
38074 Roo.form.TriggerField.superclass.onDisable.call(this);
38076 this.wrap.addClass('x-item-disabled');
38081 onEnable : function(){
38082 Roo.form.TriggerField.superclass.onEnable.call(this);
38084 this.wrap.removeClass('x-item-disabled');
38089 onShow : function(){
38090 var ae = this.getActionEl();
38093 ae.dom.style.display = '';
38094 ae.dom.style.visibility = 'visible';
38100 onHide : function(){
38101 var ae = this.getActionEl();
38102 ae.dom.style.display = 'none';
38106 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38107 * by an implementing function.
38109 * @param {EventObject} e
38111 onTriggerClick : Roo.emptyFn
38114 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38115 // to be extended by an implementing class. For an example of implementing this class, see the custom
38116 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38117 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38118 initComponent : function(){
38119 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38121 this.triggerConfig = {
38122 tag:'span', cls:'x-form-twin-triggers', cn:[
38123 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38124 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38128 getTrigger : function(index){
38129 return this.triggers[index];
38132 initTrigger : function(){
38133 var ts = this.trigger.select('.x-form-trigger', true);
38134 this.wrap.setStyle('overflow', 'hidden');
38135 var triggerField = this;
38136 ts.each(function(t, all, index){
38137 t.hide = function(){
38138 var w = triggerField.wrap.getWidth();
38139 this.dom.style.display = 'none';
38140 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38142 t.show = function(){
38143 var w = triggerField.wrap.getWidth();
38144 this.dom.style.display = '';
38145 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38147 var triggerIndex = 'Trigger'+(index+1);
38149 if(this['hide'+triggerIndex]){
38150 t.dom.style.display = 'none';
38152 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38153 t.addClassOnOver('x-form-trigger-over');
38154 t.addClassOnClick('x-form-trigger-click');
38156 this.triggers = ts.elements;
38159 onTrigger1Click : Roo.emptyFn,
38160 onTrigger2Click : Roo.emptyFn
38163 * Ext JS Library 1.1.1
38164 * Copyright(c) 2006-2007, Ext JS, LLC.
38166 * Originally Released Under LGPL - original licence link has changed is not relivant.
38169 * <script type="text/javascript">
38173 * @class Roo.form.TextArea
38174 * @extends Roo.form.TextField
38175 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38176 * support for auto-sizing.
38178 * Creates a new TextArea
38179 * @param {Object} config Configuration options
38181 Roo.form.TextArea = function(config){
38182 Roo.form.TextArea.superclass.constructor.call(this, config);
38183 // these are provided exchanges for backwards compat
38184 // minHeight/maxHeight were replaced by growMin/growMax to be
38185 // compatible with TextField growing config values
38186 if(this.minHeight !== undefined){
38187 this.growMin = this.minHeight;
38189 if(this.maxHeight !== undefined){
38190 this.growMax = this.maxHeight;
38194 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38196 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38200 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38204 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38205 * in the field (equivalent to setting overflow: hidden, defaults to false)
38207 preventScrollbars: false,
38209 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38210 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38214 onRender : function(ct, position){
38216 this.defaultAutoCreate = {
38218 style:"width:300px;height:60px;",
38219 autocomplete: "off"
38222 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38224 this.textSizeEl = Roo.DomHelper.append(document.body, {
38225 tag: "pre", cls: "x-form-grow-sizer"
38227 if(this.preventScrollbars){
38228 this.el.setStyle("overflow", "hidden");
38230 this.el.setHeight(this.growMin);
38234 onDestroy : function(){
38235 if(this.textSizeEl){
38236 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38238 Roo.form.TextArea.superclass.onDestroy.call(this);
38242 onKeyUp : function(e){
38243 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38249 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38250 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38252 autoSize : function(){
38253 if(!this.grow || !this.textSizeEl){
38257 var v = el.dom.value;
38258 var ts = this.textSizeEl;
38261 ts.appendChild(document.createTextNode(v));
38264 Roo.fly(ts).setWidth(this.el.getWidth());
38266 v = "  ";
38269 v = v.replace(/\n/g, '<p> </p>');
38271 v += " \n ";
38274 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38275 if(h != this.lastHeight){
38276 this.lastHeight = h;
38277 this.el.setHeight(h);
38278 this.fireEvent("autosize", this, h);
38283 * Ext JS Library 1.1.1
38284 * Copyright(c) 2006-2007, Ext JS, LLC.
38286 * Originally Released Under LGPL - original licence link has changed is not relivant.
38289 * <script type="text/javascript">
38294 * @class Roo.form.NumberField
38295 * @extends Roo.form.TextField
38296 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38298 * Creates a new NumberField
38299 * @param {Object} config Configuration options
38301 Roo.form.NumberField = function(config){
38302 Roo.form.NumberField.superclass.constructor.call(this, config);
38305 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38307 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38309 fieldClass: "x-form-field x-form-num-field",
38311 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38313 allowDecimals : true,
38315 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38317 decimalSeparator : ".",
38319 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38321 decimalPrecision : 2,
38323 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38325 allowNegative : true,
38327 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38329 minValue : Number.NEGATIVE_INFINITY,
38331 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38333 maxValue : Number.MAX_VALUE,
38335 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38337 minText : "The minimum value for this field is {0}",
38339 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38341 maxText : "The maximum value for this field is {0}",
38343 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38344 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38346 nanText : "{0} is not a valid number",
38349 initEvents : function(){
38350 Roo.form.NumberField.superclass.initEvents.call(this);
38351 var allowed = "0123456789";
38352 if(this.allowDecimals){
38353 allowed += this.decimalSeparator;
38355 if(this.allowNegative){
38358 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38359 var keyPress = function(e){
38360 var k = e.getKey();
38361 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38364 var c = e.getCharCode();
38365 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38369 this.el.on("keypress", keyPress, this);
38373 validateValue : function(value){
38374 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38377 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38380 var num = this.parseValue(value);
38382 this.markInvalid(String.format(this.nanText, value));
38385 if(num < this.minValue){
38386 this.markInvalid(String.format(this.minText, this.minValue));
38389 if(num > this.maxValue){
38390 this.markInvalid(String.format(this.maxText, this.maxValue));
38396 getValue : function(){
38397 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38401 parseValue : function(value){
38402 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38403 return isNaN(value) ? '' : value;
38407 fixPrecision : function(value){
38408 var nan = isNaN(value);
38409 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38410 return nan ? '' : value;
38412 return parseFloat(value).toFixed(this.decimalPrecision);
38415 setValue : function(v){
38416 v = this.fixPrecision(v);
38417 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38421 decimalPrecisionFcn : function(v){
38422 return Math.floor(v);
38425 beforeBlur : function(){
38426 var v = this.parseValue(this.getRawValue());
38433 * Ext JS Library 1.1.1
38434 * Copyright(c) 2006-2007, Ext JS, LLC.
38436 * Originally Released Under LGPL - original licence link has changed is not relivant.
38439 * <script type="text/javascript">
38443 * @class Roo.form.DateField
38444 * @extends Roo.form.TriggerField
38445 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38447 * Create a new DateField
38448 * @param {Object} config
38450 Roo.form.DateField = function(config){
38451 Roo.form.DateField.superclass.constructor.call(this, config);
38457 * Fires when a date is selected
38458 * @param {Roo.form.DateField} combo This combo box
38459 * @param {Date} date The date selected
38466 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38467 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38468 this.ddMatch = null;
38469 if(this.disabledDates){
38470 var dd = this.disabledDates;
38472 for(var i = 0; i < dd.length; i++){
38474 if(i != dd.length-1) re += "|";
38476 this.ddMatch = new RegExp(re + ")");
38480 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38482 * @cfg {String} format
38483 * The default date format string which can be overriden for localization support. The format must be
38484 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38488 * @cfg {String} altFormats
38489 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38490 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38492 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38494 * @cfg {Array} disabledDays
38495 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38497 disabledDays : null,
38499 * @cfg {String} disabledDaysText
38500 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38502 disabledDaysText : "Disabled",
38504 * @cfg {Array} disabledDates
38505 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38506 * expression so they are very powerful. Some examples:
38508 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38509 * <li>["03/08", "09/16"] would disable those days for every year</li>
38510 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38511 * <li>["03/../2006"] would disable every day in March 2006</li>
38512 * <li>["^03"] would disable every day in every March</li>
38514 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38515 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38517 disabledDates : null,
38519 * @cfg {String} disabledDatesText
38520 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38522 disabledDatesText : "Disabled",
38524 * @cfg {Date/String} minValue
38525 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38526 * valid format (defaults to null).
38530 * @cfg {Date/String} maxValue
38531 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38532 * valid format (defaults to null).
38536 * @cfg {String} minText
38537 * The error text to display when the date in the cell is before minValue (defaults to
38538 * 'The date in this field must be after {minValue}').
38540 minText : "The date in this field must be equal to or after {0}",
38542 * @cfg {String} maxText
38543 * The error text to display when the date in the cell is after maxValue (defaults to
38544 * 'The date in this field must be before {maxValue}').
38546 maxText : "The date in this field must be equal to or before {0}",
38548 * @cfg {String} invalidText
38549 * The error text to display when the date in the field is invalid (defaults to
38550 * '{value} is not a valid date - it must be in the format {format}').
38552 invalidText : "{0} is not a valid date - it must be in the format {1}",
38554 * @cfg {String} triggerClass
38555 * An additional CSS class used to style the trigger button. The trigger will always get the
38556 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38557 * which displays a calendar icon).
38559 triggerClass : 'x-form-date-trigger',
38563 * @cfg {Boolean} useIso
38564 * if enabled, then the date field will use a hidden field to store the
38565 * real value as iso formated date. default (false)
38569 * @cfg {String/Object} autoCreate
38570 * A DomHelper element spec, or true for a default element spec (defaults to
38571 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38574 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38577 hiddenField: false,
38579 onRender : function(ct, position)
38581 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38583 //this.el.dom.removeAttribute('name');
38584 Roo.log("Changing name?");
38585 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38586 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38588 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38589 // prevent input submission
38590 this.hiddenName = this.name;
38597 validateValue : function(value)
38599 value = this.formatDate(value);
38600 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38601 Roo.log('super failed');
38604 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38607 var svalue = value;
38608 value = this.parseDate(value);
38610 Roo.log('parse date failed' + svalue);
38611 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38614 var time = value.getTime();
38615 if(this.minValue && time < this.minValue.getTime()){
38616 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38619 if(this.maxValue && time > this.maxValue.getTime()){
38620 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38623 if(this.disabledDays){
38624 var day = value.getDay();
38625 for(var i = 0; i < this.disabledDays.length; i++) {
38626 if(day === this.disabledDays[i]){
38627 this.markInvalid(this.disabledDaysText);
38632 var fvalue = this.formatDate(value);
38633 if(this.ddMatch && this.ddMatch.test(fvalue)){
38634 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38641 // Provides logic to override the default TriggerField.validateBlur which just returns true
38642 validateBlur : function(){
38643 return !this.menu || !this.menu.isVisible();
38646 getName: function()
38648 // returns hidden if it's set..
38649 if (!this.rendered) {return ''};
38650 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38655 * Returns the current date value of the date field.
38656 * @return {Date} The date value
38658 getValue : function(){
38660 return this.hiddenField ?
38661 this.hiddenField.value :
38662 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38666 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38667 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38668 * (the default format used is "m/d/y").
38671 //All of these calls set the same date value (May 4, 2006)
38673 //Pass a date object:
38674 var dt = new Date('5/4/06');
38675 dateField.setValue(dt);
38677 //Pass a date string (default format):
38678 dateField.setValue('5/4/06');
38680 //Pass a date string (custom format):
38681 dateField.format = 'Y-m-d';
38682 dateField.setValue('2006-5-4');
38684 * @param {String/Date} date The date or valid date string
38686 setValue : function(date){
38687 if (this.hiddenField) {
38688 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38690 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38691 // make sure the value field is always stored as a date..
38692 this.value = this.parseDate(date);
38698 parseDate : function(value){
38699 if(!value || value instanceof Date){
38702 var v = Date.parseDate(value, this.format);
38703 if (!v && this.useIso) {
38704 v = Date.parseDate(value, 'Y-m-d');
38706 if(!v && this.altFormats){
38707 if(!this.altFormatsArray){
38708 this.altFormatsArray = this.altFormats.split("|");
38710 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38711 v = Date.parseDate(value, this.altFormatsArray[i]);
38718 formatDate : function(date, fmt){
38719 return (!date || !(date instanceof Date)) ?
38720 date : date.dateFormat(fmt || this.format);
38725 select: function(m, d){
38728 this.fireEvent('select', this, d);
38730 show : function(){ // retain focus styling
38734 this.focus.defer(10, this);
38735 var ml = this.menuListeners;
38736 this.menu.un("select", ml.select, this);
38737 this.menu.un("show", ml.show, this);
38738 this.menu.un("hide", ml.hide, this);
38743 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38744 onTriggerClick : function(){
38748 if(this.menu == null){
38749 this.menu = new Roo.menu.DateMenu();
38751 Roo.apply(this.menu.picker, {
38752 showClear: this.allowBlank,
38753 minDate : this.minValue,
38754 maxDate : this.maxValue,
38755 disabledDatesRE : this.ddMatch,
38756 disabledDatesText : this.disabledDatesText,
38757 disabledDays : this.disabledDays,
38758 disabledDaysText : this.disabledDaysText,
38759 format : this.useIso ? 'Y-m-d' : this.format,
38760 minText : String.format(this.minText, this.formatDate(this.minValue)),
38761 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38763 this.menu.on(Roo.apply({}, this.menuListeners, {
38766 this.menu.picker.setValue(this.getValue() || new Date());
38767 this.menu.show(this.el, "tl-bl?");
38770 beforeBlur : function(){
38771 var v = this.parseDate(this.getRawValue());
38781 isDirty : function() {
38782 if(this.disabled) {
38786 if(typeof(this.startValue) === 'undefined'){
38790 return String(this.getValue()) !== String(this.startValue);
38795 * Ext JS Library 1.1.1
38796 * Copyright(c) 2006-2007, Ext JS, LLC.
38798 * Originally Released Under LGPL - original licence link has changed is not relivant.
38801 * <script type="text/javascript">
38805 * @class Roo.form.MonthField
38806 * @extends Roo.form.TriggerField
38807 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38809 * Create a new MonthField
38810 * @param {Object} config
38812 Roo.form.MonthField = function(config){
38814 Roo.form.MonthField.superclass.constructor.call(this, config);
38820 * Fires when a date is selected
38821 * @param {Roo.form.MonthFieeld} combo This combo box
38822 * @param {Date} date The date selected
38829 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38830 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38831 this.ddMatch = null;
38832 if(this.disabledDates){
38833 var dd = this.disabledDates;
38835 for(var i = 0; i < dd.length; i++){
38837 if(i != dd.length-1) re += "|";
38839 this.ddMatch = new RegExp(re + ")");
38843 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38845 * @cfg {String} format
38846 * The default date format string which can be overriden for localization support. The format must be
38847 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38851 * @cfg {String} altFormats
38852 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38853 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38855 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38857 * @cfg {Array} disabledDays
38858 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38860 disabledDays : [0,1,2,3,4,5,6],
38862 * @cfg {String} disabledDaysText
38863 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38865 disabledDaysText : "Disabled",
38867 * @cfg {Array} disabledDates
38868 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38869 * expression so they are very powerful. Some examples:
38871 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38872 * <li>["03/08", "09/16"] would disable those days for every year</li>
38873 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38874 * <li>["03/../2006"] would disable every day in March 2006</li>
38875 * <li>["^03"] would disable every day in every March</li>
38877 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38878 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38880 disabledDates : null,
38882 * @cfg {String} disabledDatesText
38883 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38885 disabledDatesText : "Disabled",
38887 * @cfg {Date/String} minValue
38888 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38889 * valid format (defaults to null).
38893 * @cfg {Date/String} maxValue
38894 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38895 * valid format (defaults to null).
38899 * @cfg {String} minText
38900 * The error text to display when the date in the cell is before minValue (defaults to
38901 * 'The date in this field must be after {minValue}').
38903 minText : "The date in this field must be equal to or after {0}",
38905 * @cfg {String} maxTextf
38906 * The error text to display when the date in the cell is after maxValue (defaults to
38907 * 'The date in this field must be before {maxValue}').
38909 maxText : "The date in this field must be equal to or before {0}",
38911 * @cfg {String} invalidText
38912 * The error text to display when the date in the field is invalid (defaults to
38913 * '{value} is not a valid date - it must be in the format {format}').
38915 invalidText : "{0} is not a valid date - it must be in the format {1}",
38917 * @cfg {String} triggerClass
38918 * An additional CSS class used to style the trigger button. The trigger will always get the
38919 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38920 * which displays a calendar icon).
38922 triggerClass : 'x-form-date-trigger',
38926 * @cfg {Boolean} useIso
38927 * if enabled, then the date field will use a hidden field to store the
38928 * real value as iso formated date. default (true)
38932 * @cfg {String/Object} autoCreate
38933 * A DomHelper element spec, or true for a default element spec (defaults to
38934 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38937 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38940 hiddenField: false,
38942 hideMonthPicker : false,
38944 onRender : function(ct, position)
38946 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38948 this.el.dom.removeAttribute('name');
38949 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38951 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38952 // prevent input submission
38953 this.hiddenName = this.name;
38960 validateValue : function(value)
38962 value = this.formatDate(value);
38963 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38966 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38969 var svalue = value;
38970 value = this.parseDate(value);
38972 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38975 var time = value.getTime();
38976 if(this.minValue && time < this.minValue.getTime()){
38977 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38980 if(this.maxValue && time > this.maxValue.getTime()){
38981 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38984 /*if(this.disabledDays){
38985 var day = value.getDay();
38986 for(var i = 0; i < this.disabledDays.length; i++) {
38987 if(day === this.disabledDays[i]){
38988 this.markInvalid(this.disabledDaysText);
38994 var fvalue = this.formatDate(value);
38995 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38996 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39004 // Provides logic to override the default TriggerField.validateBlur which just returns true
39005 validateBlur : function(){
39006 return !this.menu || !this.menu.isVisible();
39010 * Returns the current date value of the date field.
39011 * @return {Date} The date value
39013 getValue : function(){
39017 return this.hiddenField ?
39018 this.hiddenField.value :
39019 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39023 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39024 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39025 * (the default format used is "m/d/y").
39028 //All of these calls set the same date value (May 4, 2006)
39030 //Pass a date object:
39031 var dt = new Date('5/4/06');
39032 monthField.setValue(dt);
39034 //Pass a date string (default format):
39035 monthField.setValue('5/4/06');
39037 //Pass a date string (custom format):
39038 monthField.format = 'Y-m-d';
39039 monthField.setValue('2006-5-4');
39041 * @param {String/Date} date The date or valid date string
39043 setValue : function(date){
39044 Roo.log('month setValue' + date);
39045 // can only be first of month..
39047 var val = this.parseDate(date);
39049 if (this.hiddenField) {
39050 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39052 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39053 this.value = this.parseDate(date);
39057 parseDate : function(value){
39058 if(!value || value instanceof Date){
39059 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39062 var v = Date.parseDate(value, this.format);
39063 if (!v && this.useIso) {
39064 v = Date.parseDate(value, 'Y-m-d');
39068 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39072 if(!v && this.altFormats){
39073 if(!this.altFormatsArray){
39074 this.altFormatsArray = this.altFormats.split("|");
39076 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39077 v = Date.parseDate(value, this.altFormatsArray[i]);
39084 formatDate : function(date, fmt){
39085 return (!date || !(date instanceof Date)) ?
39086 date : date.dateFormat(fmt || this.format);
39091 select: function(m, d){
39093 this.fireEvent('select', this, d);
39095 show : function(){ // retain focus styling
39099 this.focus.defer(10, this);
39100 var ml = this.menuListeners;
39101 this.menu.un("select", ml.select, this);
39102 this.menu.un("show", ml.show, this);
39103 this.menu.un("hide", ml.hide, this);
39107 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39108 onTriggerClick : function(){
39112 if(this.menu == null){
39113 this.menu = new Roo.menu.DateMenu();
39117 Roo.apply(this.menu.picker, {
39119 showClear: this.allowBlank,
39120 minDate : this.minValue,
39121 maxDate : this.maxValue,
39122 disabledDatesRE : this.ddMatch,
39123 disabledDatesText : this.disabledDatesText,
39125 format : this.useIso ? 'Y-m-d' : this.format,
39126 minText : String.format(this.minText, this.formatDate(this.minValue)),
39127 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39130 this.menu.on(Roo.apply({}, this.menuListeners, {
39138 // hide month picker get's called when we called by 'before hide';
39140 var ignorehide = true;
39141 p.hideMonthPicker = function(disableAnim){
39145 if(this.monthPicker){
39146 Roo.log("hideMonthPicker called");
39147 if(disableAnim === true){
39148 this.monthPicker.hide();
39150 this.monthPicker.slideOut('t', {duration:.2});
39151 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39152 p.fireEvent("select", this, this.value);
39158 Roo.log('picker set value');
39159 Roo.log(this.getValue());
39160 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39161 m.show(this.el, 'tl-bl?');
39162 ignorehide = false;
39163 // this will trigger hideMonthPicker..
39166 // hidden the day picker
39167 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39173 p.showMonthPicker.defer(100, p);
39179 beforeBlur : function(){
39180 var v = this.parseDate(this.getRawValue());
39186 /** @cfg {Boolean} grow @hide */
39187 /** @cfg {Number} growMin @hide */
39188 /** @cfg {Number} growMax @hide */
39195 * Ext JS Library 1.1.1
39196 * Copyright(c) 2006-2007, Ext JS, LLC.
39198 * Originally Released Under LGPL - original licence link has changed is not relivant.
39201 * <script type="text/javascript">
39206 * @class Roo.form.ComboBox
39207 * @extends Roo.form.TriggerField
39208 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39210 * Create a new ComboBox.
39211 * @param {Object} config Configuration options
39213 Roo.form.ComboBox = function(config){
39214 Roo.form.ComboBox.superclass.constructor.call(this, config);
39218 * Fires when the dropdown list is expanded
39219 * @param {Roo.form.ComboBox} combo This combo box
39224 * Fires when the dropdown list is collapsed
39225 * @param {Roo.form.ComboBox} combo This combo box
39229 * @event beforeselect
39230 * Fires before a list item is selected. Return false to cancel the selection.
39231 * @param {Roo.form.ComboBox} combo This combo box
39232 * @param {Roo.data.Record} record The data record returned from the underlying store
39233 * @param {Number} index The index of the selected item in the dropdown list
39235 'beforeselect' : true,
39238 * Fires when a list item is selected
39239 * @param {Roo.form.ComboBox} combo This combo box
39240 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39241 * @param {Number} index The index of the selected item in the dropdown list
39245 * @event beforequery
39246 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39247 * The event object passed has these properties:
39248 * @param {Roo.form.ComboBox} combo This combo box
39249 * @param {String} query The query
39250 * @param {Boolean} forceAll true to force "all" query
39251 * @param {Boolean} cancel true to cancel the query
39252 * @param {Object} e The query event object
39254 'beforequery': true,
39257 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39258 * @param {Roo.form.ComboBox} combo This combo box
39263 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39264 * @param {Roo.form.ComboBox} combo This combo box
39265 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39271 if(this.transform){
39272 this.allowDomMove = false;
39273 var s = Roo.getDom(this.transform);
39274 if(!this.hiddenName){
39275 this.hiddenName = s.name;
39278 this.mode = 'local';
39279 var d = [], opts = s.options;
39280 for(var i = 0, len = opts.length;i < len; i++){
39282 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39284 this.value = value;
39286 d.push([value, o.text]);
39288 this.store = new Roo.data.SimpleStore({
39290 fields: ['value', 'text'],
39293 this.valueField = 'value';
39294 this.displayField = 'text';
39296 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39297 if(!this.lazyRender){
39298 this.target = true;
39299 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39300 s.parentNode.removeChild(s); // remove it
39301 this.render(this.el.parentNode);
39303 s.parentNode.removeChild(s); // remove it
39308 this.store = Roo.factory(this.store, Roo.data);
39311 this.selectedIndex = -1;
39312 if(this.mode == 'local'){
39313 if(config.queryDelay === undefined){
39314 this.queryDelay = 10;
39316 if(config.minChars === undefined){
39322 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39324 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39327 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39328 * rendering into an Roo.Editor, defaults to false)
39331 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39332 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39335 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39338 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39339 * the dropdown list (defaults to undefined, with no header element)
39343 * @cfg {String/Roo.Template} tpl The template to use to render the output
39347 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39349 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39351 listWidth: undefined,
39353 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39354 * mode = 'remote' or 'text' if mode = 'local')
39356 displayField: undefined,
39358 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39359 * mode = 'remote' or 'value' if mode = 'local').
39360 * Note: use of a valueField requires the user make a selection
39361 * in order for a value to be mapped.
39363 valueField: undefined,
39367 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39368 * field's data value (defaults to the underlying DOM element's name)
39370 hiddenName: undefined,
39372 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39376 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39378 selectedClass: 'x-combo-selected',
39380 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39381 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39382 * which displays a downward arrow icon).
39384 triggerClass : 'x-form-arrow-trigger',
39386 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39390 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39391 * anchor positions (defaults to 'tl-bl')
39393 listAlign: 'tl-bl?',
39395 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39399 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39400 * query specified by the allQuery config option (defaults to 'query')
39402 triggerAction: 'query',
39404 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39405 * (defaults to 4, does not apply if editable = false)
39409 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39410 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39414 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39415 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39419 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39420 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39424 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39425 * when editable = true (defaults to false)
39427 selectOnFocus:false,
39429 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39431 queryParam: 'query',
39433 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39434 * when mode = 'remote' (defaults to 'Loading...')
39436 loadingText: 'Loading...',
39438 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39442 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39446 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39447 * traditional select (defaults to true)
39451 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39455 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39459 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39460 * listWidth has a higher value)
39464 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39465 * allow the user to set arbitrary text into the field (defaults to false)
39467 forceSelection:false,
39469 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39470 * if typeAhead = true (defaults to 250)
39472 typeAheadDelay : 250,
39474 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39475 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39477 valueNotFoundText : undefined,
39479 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39481 blockFocus : false,
39484 * @cfg {Boolean} disableClear Disable showing of clear button.
39486 disableClear : false,
39488 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39490 alwaysQuery : false,
39496 // element that contains real text value.. (when hidden is used..)
39499 onRender : function(ct, position){
39500 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39501 if(this.hiddenName){
39502 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39504 this.hiddenField.value =
39505 this.hiddenValue !== undefined ? this.hiddenValue :
39506 this.value !== undefined ? this.value : '';
39508 // prevent input submission
39509 this.el.dom.removeAttribute('name');
39514 this.el.dom.setAttribute('autocomplete', 'off');
39517 var cls = 'x-combo-list';
39519 this.list = new Roo.Layer({
39520 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39523 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39524 this.list.setWidth(lw);
39525 this.list.swallowEvent('mousewheel');
39526 this.assetHeight = 0;
39529 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39530 this.assetHeight += this.header.getHeight();
39533 this.innerList = this.list.createChild({cls:cls+'-inner'});
39534 this.innerList.on('mouseover', this.onViewOver, this);
39535 this.innerList.on('mousemove', this.onViewMove, this);
39536 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39538 if(this.allowBlank && !this.pageSize && !this.disableClear){
39539 this.footer = this.list.createChild({cls:cls+'-ft'});
39540 this.pageTb = new Roo.Toolbar(this.footer);
39544 this.footer = this.list.createChild({cls:cls+'-ft'});
39545 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39546 {pageSize: this.pageSize});
39550 if (this.pageTb && this.allowBlank && !this.disableClear) {
39552 this.pageTb.add(new Roo.Toolbar.Fill(), {
39553 cls: 'x-btn-icon x-btn-clear',
39555 handler: function()
39558 _this.clearValue();
39559 _this.onSelect(false, -1);
39564 this.assetHeight += this.footer.getHeight();
39569 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39572 this.view = new Roo.View(this.innerList, this.tpl, {
39573 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39576 this.view.on('click', this.onViewClick, this);
39578 this.store.on('beforeload', this.onBeforeLoad, this);
39579 this.store.on('load', this.onLoad, this);
39580 this.store.on('loadexception', this.onLoadException, this);
39582 if(this.resizable){
39583 this.resizer = new Roo.Resizable(this.list, {
39584 pinned:true, handles:'se'
39586 this.resizer.on('resize', function(r, w, h){
39587 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39588 this.listWidth = w;
39589 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39590 this.restrictHeight();
39592 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39594 if(!this.editable){
39595 this.editable = true;
39596 this.setEditable(false);
39600 if (typeof(this.events.add.listeners) != 'undefined') {
39602 this.addicon = this.wrap.createChild(
39603 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39605 this.addicon.on('click', function(e) {
39606 this.fireEvent('add', this);
39609 if (typeof(this.events.edit.listeners) != 'undefined') {
39611 this.editicon = this.wrap.createChild(
39612 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39613 if (this.addicon) {
39614 this.editicon.setStyle('margin-left', '40px');
39616 this.editicon.on('click', function(e) {
39618 // we fire even if inothing is selected..
39619 this.fireEvent('edit', this, this.lastData );
39629 initEvents : function(){
39630 Roo.form.ComboBox.superclass.initEvents.call(this);
39632 this.keyNav = new Roo.KeyNav(this.el, {
39633 "up" : function(e){
39634 this.inKeyMode = true;
39638 "down" : function(e){
39639 if(!this.isExpanded()){
39640 this.onTriggerClick();
39642 this.inKeyMode = true;
39647 "enter" : function(e){
39648 this.onViewClick();
39652 "esc" : function(e){
39656 "tab" : function(e){
39657 this.onViewClick(false);
39658 this.fireEvent("specialkey", this, e);
39664 doRelay : function(foo, bar, hname){
39665 if(hname == 'down' || this.scope.isExpanded()){
39666 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39673 this.queryDelay = Math.max(this.queryDelay || 10,
39674 this.mode == 'local' ? 10 : 250);
39675 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39676 if(this.typeAhead){
39677 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39679 if(this.editable !== false){
39680 this.el.on("keyup", this.onKeyUp, this);
39682 if(this.forceSelection){
39683 this.on('blur', this.doForce, this);
39687 onDestroy : function(){
39689 this.view.setStore(null);
39690 this.view.el.removeAllListeners();
39691 this.view.el.remove();
39692 this.view.purgeListeners();
39695 this.list.destroy();
39698 this.store.un('beforeload', this.onBeforeLoad, this);
39699 this.store.un('load', this.onLoad, this);
39700 this.store.un('loadexception', this.onLoadException, this);
39702 Roo.form.ComboBox.superclass.onDestroy.call(this);
39706 fireKey : function(e){
39707 if(e.isNavKeyPress() && !this.list.isVisible()){
39708 this.fireEvent("specialkey", this, e);
39713 onResize: function(w, h){
39714 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39716 if(typeof w != 'number'){
39717 // we do not handle it!?!?
39720 var tw = this.trigger.getWidth();
39721 tw += this.addicon ? this.addicon.getWidth() : 0;
39722 tw += this.editicon ? this.editicon.getWidth() : 0;
39724 this.el.setWidth( this.adjustWidth('input', x));
39726 this.trigger.setStyle('left', x+'px');
39728 if(this.list && this.listWidth === undefined){
39729 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39730 this.list.setWidth(lw);
39731 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39739 * Allow or prevent the user from directly editing the field text. If false is passed,
39740 * the user will only be able to select from the items defined in the dropdown list. This method
39741 * is the runtime equivalent of setting the 'editable' config option at config time.
39742 * @param {Boolean} value True to allow the user to directly edit the field text
39744 setEditable : function(value){
39745 if(value == this.editable){
39748 this.editable = value;
39750 this.el.dom.setAttribute('readOnly', true);
39751 this.el.on('mousedown', this.onTriggerClick, this);
39752 this.el.addClass('x-combo-noedit');
39754 this.el.dom.setAttribute('readOnly', false);
39755 this.el.un('mousedown', this.onTriggerClick, this);
39756 this.el.removeClass('x-combo-noedit');
39761 onBeforeLoad : function(){
39762 if(!this.hasFocus){
39765 this.innerList.update(this.loadingText ?
39766 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39767 this.restrictHeight();
39768 this.selectedIndex = -1;
39772 onLoad : function(){
39773 if(!this.hasFocus){
39776 if(this.store.getCount() > 0){
39778 this.restrictHeight();
39779 if(this.lastQuery == this.allQuery){
39781 this.el.dom.select();
39783 if(!this.selectByValue(this.value, true)){
39784 this.select(0, true);
39788 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39789 this.taTask.delay(this.typeAheadDelay);
39793 this.onEmptyResults();
39798 onLoadException : function()
39801 Roo.log(this.store.reader.jsonData);
39802 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39803 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39809 onTypeAhead : function(){
39810 if(this.store.getCount() > 0){
39811 var r = this.store.getAt(0);
39812 var newValue = r.data[this.displayField];
39813 var len = newValue.length;
39814 var selStart = this.getRawValue().length;
39815 if(selStart != len){
39816 this.setRawValue(newValue);
39817 this.selectText(selStart, newValue.length);
39823 onSelect : function(record, index){
39824 if(this.fireEvent('beforeselect', this, record, index) !== false){
39825 this.setFromData(index > -1 ? record.data : false);
39827 this.fireEvent('select', this, record, index);
39832 * Returns the currently selected field value or empty string if no value is set.
39833 * @return {String} value The selected value
39835 getValue : function(){
39836 if(this.valueField){
39837 return typeof this.value != 'undefined' ? this.value : '';
39839 return Roo.form.ComboBox.superclass.getValue.call(this);
39843 * Clears any text/value currently set in the field
39845 clearValue : function(){
39846 if(this.hiddenField){
39847 this.hiddenField.value = '';
39850 this.setRawValue('');
39851 this.lastSelectionText = '';
39856 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39857 * will be displayed in the field. If the value does not match the data value of an existing item,
39858 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39859 * Otherwise the field will be blank (although the value will still be set).
39860 * @param {String} value The value to match
39862 setValue : function(v){
39864 if(this.valueField){
39865 var r = this.findRecord(this.valueField, v);
39867 text = r.data[this.displayField];
39868 }else if(this.valueNotFoundText !== undefined){
39869 text = this.valueNotFoundText;
39872 this.lastSelectionText = text;
39873 if(this.hiddenField){
39874 this.hiddenField.value = v;
39876 Roo.form.ComboBox.superclass.setValue.call(this, text);
39880 * @property {Object} the last set data for the element
39885 * Sets the value of the field based on a object which is related to the record format for the store.
39886 * @param {Object} value the value to set as. or false on reset?
39888 setFromData : function(o){
39889 var dv = ''; // display value
39890 var vv = ''; // value value..
39892 if (this.displayField) {
39893 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39895 // this is an error condition!!!
39896 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39899 if(this.valueField){
39900 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39902 if(this.hiddenField){
39903 this.hiddenField.value = vv;
39905 this.lastSelectionText = dv;
39906 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39910 // no hidden field.. - we store the value in 'value', but still display
39911 // display field!!!!
39912 this.lastSelectionText = dv;
39913 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39919 reset : function(){
39920 // overridden so that last data is reset..
39921 this.setValue(this.resetValue);
39922 this.clearInvalid();
39923 this.lastData = false;
39925 this.view.clearSelections();
39929 findRecord : function(prop, value){
39931 if(this.store.getCount() > 0){
39932 this.store.each(function(r){
39933 if(r.data[prop] == value){
39943 getName: function()
39945 // returns hidden if it's set..
39946 if (!this.rendered) {return ''};
39947 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39951 onViewMove : function(e, t){
39952 this.inKeyMode = false;
39956 onViewOver : function(e, t){
39957 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39960 var item = this.view.findItemFromChild(t);
39962 var index = this.view.indexOf(item);
39963 this.select(index, false);
39968 onViewClick : function(doFocus)
39970 var index = this.view.getSelectedIndexes()[0];
39971 var r = this.store.getAt(index);
39973 this.onSelect(r, index);
39975 if(doFocus !== false && !this.blockFocus){
39981 restrictHeight : function(){
39982 this.innerList.dom.style.height = '';
39983 var inner = this.innerList.dom;
39984 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39985 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39986 this.list.beginUpdate();
39987 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39988 this.list.alignTo(this.el, this.listAlign);
39989 this.list.endUpdate();
39993 onEmptyResults : function(){
39998 * Returns true if the dropdown list is expanded, else false.
40000 isExpanded : function(){
40001 return this.list.isVisible();
40005 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40006 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40007 * @param {String} value The data value of the item to select
40008 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40009 * selected item if it is not currently in view (defaults to true)
40010 * @return {Boolean} True if the value matched an item in the list, else false
40012 selectByValue : function(v, scrollIntoView){
40013 if(v !== undefined && v !== null){
40014 var r = this.findRecord(this.valueField || this.displayField, v);
40016 this.select(this.store.indexOf(r), scrollIntoView);
40024 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40025 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40026 * @param {Number} index The zero-based index of the list item to select
40027 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40028 * selected item if it is not currently in view (defaults to true)
40030 select : function(index, scrollIntoView){
40031 this.selectedIndex = index;
40032 this.view.select(index);
40033 if(scrollIntoView !== false){
40034 var el = this.view.getNode(index);
40036 this.innerList.scrollChildIntoView(el, false);
40042 selectNext : function(){
40043 var ct = this.store.getCount();
40045 if(this.selectedIndex == -1){
40047 }else if(this.selectedIndex < ct-1){
40048 this.select(this.selectedIndex+1);
40054 selectPrev : function(){
40055 var ct = this.store.getCount();
40057 if(this.selectedIndex == -1){
40059 }else if(this.selectedIndex != 0){
40060 this.select(this.selectedIndex-1);
40066 onKeyUp : function(e){
40067 if(this.editable !== false && !e.isSpecialKey()){
40068 this.lastKey = e.getKey();
40069 this.dqTask.delay(this.queryDelay);
40074 validateBlur : function(){
40075 return !this.list || !this.list.isVisible();
40079 initQuery : function(){
40080 this.doQuery(this.getRawValue());
40084 doForce : function(){
40085 if(this.el.dom.value.length > 0){
40086 this.el.dom.value =
40087 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40093 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40094 * query allowing the query action to be canceled if needed.
40095 * @param {String} query The SQL query to execute
40096 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40097 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40098 * saved in the current store (defaults to false)
40100 doQuery : function(q, forceAll){
40101 if(q === undefined || q === null){
40106 forceAll: forceAll,
40110 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40114 forceAll = qe.forceAll;
40115 if(forceAll === true || (q.length >= this.minChars)){
40116 if(this.lastQuery != q || this.alwaysQuery){
40117 this.lastQuery = q;
40118 if(this.mode == 'local'){
40119 this.selectedIndex = -1;
40121 this.store.clearFilter();
40123 this.store.filter(this.displayField, q);
40127 this.store.baseParams[this.queryParam] = q;
40129 params: this.getParams(q)
40134 this.selectedIndex = -1;
40141 getParams : function(q){
40143 //p[this.queryParam] = q;
40146 p.limit = this.pageSize;
40152 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40154 collapse : function(){
40155 if(!this.isExpanded()){
40159 Roo.get(document).un('mousedown', this.collapseIf, this);
40160 Roo.get(document).un('mousewheel', this.collapseIf, this);
40161 if (!this.editable) {
40162 Roo.get(document).un('keydown', this.listKeyPress, this);
40164 this.fireEvent('collapse', this);
40168 collapseIf : function(e){
40169 if(!e.within(this.wrap) && !e.within(this.list)){
40175 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40177 expand : function(){
40178 if(this.isExpanded() || !this.hasFocus){
40181 this.list.alignTo(this.el, this.listAlign);
40183 Roo.get(document).on('mousedown', this.collapseIf, this);
40184 Roo.get(document).on('mousewheel', this.collapseIf, this);
40185 if (!this.editable) {
40186 Roo.get(document).on('keydown', this.listKeyPress, this);
40189 this.fireEvent('expand', this);
40193 // Implements the default empty TriggerField.onTriggerClick function
40194 onTriggerClick : function(){
40198 if(this.isExpanded()){
40200 if (!this.blockFocus) {
40205 this.hasFocus = true;
40206 if(this.triggerAction == 'all') {
40207 this.doQuery(this.allQuery, true);
40209 this.doQuery(this.getRawValue());
40211 if (!this.blockFocus) {
40216 listKeyPress : function(e)
40218 //Roo.log('listkeypress');
40219 // scroll to first matching element based on key pres..
40220 if (e.isSpecialKey()) {
40223 var k = String.fromCharCode(e.getKey()).toUpperCase();
40226 var csel = this.view.getSelectedNodes();
40227 var cselitem = false;
40229 var ix = this.view.indexOf(csel[0]);
40230 cselitem = this.store.getAt(ix);
40231 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40237 this.store.each(function(v) {
40239 // start at existing selection.
40240 if (cselitem.id == v.id) {
40246 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40247 match = this.store.indexOf(v);
40252 if (match === false) {
40253 return true; // no more action?
40256 this.view.select(match);
40257 var sn = Roo.get(this.view.getSelectedNodes()[0])
40258 sn.scrollIntoView(sn.dom.parentNode, false);
40262 * @cfg {Boolean} grow
40266 * @cfg {Number} growMin
40270 * @cfg {Number} growMax
40278 * Copyright(c) 2010-2012, Roo J Solutions Limited
40285 * @class Roo.form.ComboBoxArray
40286 * @extends Roo.form.TextField
40287 * A facebook style adder... for lists of email / people / countries etc...
40288 * pick multiple items from a combo box, and shows each one.
40290 * Fred [x] Brian [x] [Pick another |v]
40293 * For this to work: it needs various extra information
40294 * - normal combo problay has
40296 * + displayField, valueField
40298 * For our purpose...
40301 * If we change from 'extends' to wrapping...
40308 * Create a new ComboBoxArray.
40309 * @param {Object} config Configuration options
40313 Roo.form.ComboBoxArray = function(config)
40318 * Fires when remove the value from the list
40319 * @param {Roo.form.ComboBoxArray} _self This combo box array
40320 * @param {Roo.form.ComboBoxArray.Item} item removed item
40327 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40329 this.items = new Roo.util.MixedCollection(false);
40331 // construct the child combo...
40341 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40344 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40349 // behavies liek a hiddne field
40350 inputType: 'hidden',
40352 * @cfg {Number} width The width of the box that displays the selected element
40359 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40363 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40365 hiddenName : false,
40368 // private the array of items that are displayed..
40370 // private - the hidden field el.
40372 // private - the filed el..
40375 //validateValue : function() { return true; }, // all values are ok!
40376 //onAddClick: function() { },
40378 onRender : function(ct, position)
40381 // create the standard hidden element
40382 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40385 // give fake names to child combo;
40386 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40387 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40389 this.combo = Roo.factory(this.combo, Roo.form);
40390 this.combo.onRender(ct, position);
40391 if (typeof(this.combo.width) != 'undefined') {
40392 this.combo.onResize(this.combo.width,0);
40395 this.combo.initEvents();
40397 // assigned so form know we need to do this..
40398 this.store = this.combo.store;
40399 this.valueField = this.combo.valueField;
40400 this.displayField = this.combo.displayField ;
40403 this.combo.wrap.addClass('x-cbarray-grp');
40405 var cbwrap = this.combo.wrap.createChild(
40406 {tag: 'div', cls: 'x-cbarray-cb'},
40411 this.hiddenEl = this.combo.wrap.createChild({
40412 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40414 this.el = this.combo.wrap.createChild({
40415 tag: 'input', type:'hidden' , name: this.name, value : ''
40417 // this.el.dom.removeAttribute("name");
40420 this.outerWrap = this.combo.wrap;
40421 this.wrap = cbwrap;
40423 this.outerWrap.setWidth(this.width);
40424 this.outerWrap.dom.removeChild(this.el.dom);
40426 this.wrap.dom.appendChild(this.el.dom);
40427 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40428 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40430 this.combo.trigger.setStyle('position','relative');
40431 this.combo.trigger.setStyle('left', '0px');
40432 this.combo.trigger.setStyle('top', '2px');
40434 this.combo.el.setStyle('vertical-align', 'text-bottom');
40436 //this.trigger.setStyle('vertical-align', 'top');
40438 // this should use the code from combo really... on('add' ....)
40442 this.adder = this.outerWrap.createChild(
40443 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40445 this.adder.on('click', function(e) {
40446 _t.fireEvent('adderclick', this, e);
40450 //this.adder.on('click', this.onAddClick, _t);
40453 this.combo.on('select', function(cb, rec, ix) {
40454 this.addItem(rec.data);
40457 cb.el.dom.value = '';
40458 //cb.lastData = rec.data;
40467 getName: function()
40469 // returns hidden if it's set..
40470 if (!this.rendered) {return ''};
40471 return this.hiddenName ? this.hiddenName : this.name;
40476 onResize: function(w, h){
40479 // not sure if this is needed..
40480 //this.combo.onResize(w,h);
40482 if(typeof w != 'number'){
40483 // we do not handle it!?!?
40486 var tw = this.combo.trigger.getWidth();
40487 tw += this.addicon ? this.addicon.getWidth() : 0;
40488 tw += this.editicon ? this.editicon.getWidth() : 0;
40490 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40492 this.combo.trigger.setStyle('left', '0px');
40494 if(this.list && this.listWidth === undefined){
40495 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40496 this.list.setWidth(lw);
40497 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40504 addItem: function(rec)
40506 var valueField = this.combo.valueField;
40507 var displayField = this.combo.displayField;
40508 if (this.items.indexOfKey(rec[valueField]) > -1) {
40509 //console.log("GOT " + rec.data.id);
40513 var x = new Roo.form.ComboBoxArray.Item({
40514 //id : rec[this.idField],
40516 displayField : displayField ,
40517 tipField : displayField ,
40521 this.items.add(rec[valueField],x);
40522 // add it before the element..
40523 this.updateHiddenEl();
40524 x.render(this.outerWrap, this.wrap.dom);
40525 // add the image handler..
40528 updateHiddenEl : function()
40531 if (!this.hiddenEl) {
40535 var idField = this.combo.valueField;
40537 this.items.each(function(f) {
40538 ar.push(f.data[idField]);
40541 this.hiddenEl.dom.value = ar.join(',');
40547 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40548 this.items.each(function(f) {
40551 this.el.dom.value = '';
40552 if (this.hiddenEl) {
40553 this.hiddenEl.dom.value = '';
40557 getValue: function()
40559 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40561 setValue: function(v) // not a valid action - must use addItems..
40568 if (this.store.isLocal && (typeof(v) == 'string')) {
40569 // then we can use the store to find the values..
40570 // comma seperated at present.. this needs to allow JSON based encoding..
40571 this.hiddenEl.value = v;
40573 Roo.each(v.split(','), function(k) {
40574 Roo.log("CHECK " + this.valueField + ',' + k);
40575 var li = this.store.query(this.valueField, k);
40580 add[this.valueField] = k;
40581 add[this.displayField] = li.item(0).data[this.displayField];
40587 if (typeof(v) == 'object' ) {
40588 // then let's assume it's an array of objects..
40589 Roo.each(v, function(l) {
40597 setFromData: function(v)
40599 // this recieves an object, if setValues is called.
40601 this.el.dom.value = v[this.displayField];
40602 this.hiddenEl.dom.value = v[this.valueField];
40603 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40606 var kv = v[this.valueField];
40607 var dv = v[this.displayField];
40608 kv = typeof(kv) != 'string' ? '' : kv;
40609 dv = typeof(dv) != 'string' ? '' : dv;
40612 var keys = kv.split(',');
40613 var display = dv.split(',');
40614 for (var i = 0 ; i < keys.length; i++) {
40617 add[this.valueField] = keys[i];
40618 add[this.displayField] = display[i];
40626 * Validates the combox array value
40627 * @return {Boolean} True if the value is valid, else false
40629 validate : function(){
40630 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40631 this.clearInvalid();
40637 validateValue : function(value){
40638 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40646 isDirty : function() {
40647 if(this.disabled) {
40652 var d = Roo.decode(String(this.originalValue));
40654 return String(this.getValue()) !== String(this.originalValue);
40657 var originalValue = [];
40659 for (var i = 0; i < d.length; i++){
40660 originalValue.push(d[i][this.valueField]);
40663 return String(this.getValue()) !== String(originalValue.join(','));
40672 * @class Roo.form.ComboBoxArray.Item
40673 * @extends Roo.BoxComponent
40674 * A selected item in the list
40675 * Fred [x] Brian [x] [Pick another |v]
40678 * Create a new item.
40679 * @param {Object} config Configuration options
40682 Roo.form.ComboBoxArray.Item = function(config) {
40683 config.id = Roo.id();
40684 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40687 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40690 displayField : false,
40694 defaultAutoCreate : {
40696 cls: 'x-cbarray-item',
40703 src : Roo.BLANK_IMAGE_URL ,
40711 onRender : function(ct, position)
40713 Roo.form.Field.superclass.onRender.call(this, ct, position);
40716 var cfg = this.getAutoCreate();
40717 this.el = ct.createChild(cfg, position);
40720 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40722 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40723 this.cb.renderer(this.data) :
40724 String.format('{0}',this.data[this.displayField]);
40727 this.el.child('div').dom.setAttribute('qtip',
40728 String.format('{0}',this.data[this.tipField])
40731 this.el.child('img').on('click', this.remove, this);
40735 remove : function()
40737 if(this.cb.disabled){
40740 this.cb.items.remove(this);
40741 this.el.child('img').un('click', this.remove, this);
40743 this.cb.updateHiddenEl();
40745 this.cb.fireEvent('remove', this.cb, this);
40749 * Ext JS Library 1.1.1
40750 * Copyright(c) 2006-2007, Ext JS, LLC.
40752 * Originally Released Under LGPL - original licence link has changed is not relivant.
40755 * <script type="text/javascript">
40758 * @class Roo.form.Checkbox
40759 * @extends Roo.form.Field
40760 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40762 * Creates a new Checkbox
40763 * @param {Object} config Configuration options
40765 Roo.form.Checkbox = function(config){
40766 Roo.form.Checkbox.superclass.constructor.call(this, config);
40770 * Fires when the checkbox is checked or unchecked.
40771 * @param {Roo.form.Checkbox} this This checkbox
40772 * @param {Boolean} checked The new checked value
40778 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40780 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40782 focusClass : undefined,
40784 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40786 fieldClass: "x-form-field",
40788 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40792 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40793 * {tag: "input", type: "checkbox", autocomplete: "off"})
40795 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40797 * @cfg {String} boxLabel The text that appears beside the checkbox
40801 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40805 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40807 valueOff: '0', // value when not checked..
40809 actionMode : 'viewEl',
40812 itemCls : 'x-menu-check-item x-form-item',
40813 groupClass : 'x-menu-group-item',
40814 inputType : 'hidden',
40817 inSetChecked: false, // check that we are not calling self...
40819 inputElement: false, // real input element?
40820 basedOn: false, // ????
40822 isFormField: true, // not sure where this is needed!!!!
40824 onResize : function(){
40825 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40826 if(!this.boxLabel){
40827 this.el.alignTo(this.wrap, 'c-c');
40831 initEvents : function(){
40832 Roo.form.Checkbox.superclass.initEvents.call(this);
40833 this.el.on("click", this.onClick, this);
40834 this.el.on("change", this.onClick, this);
40838 getResizeEl : function(){
40842 getPositionEl : function(){
40847 onRender : function(ct, position){
40848 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40850 if(this.inputValue !== undefined){
40851 this.el.dom.value = this.inputValue;
40854 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40855 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40856 var viewEl = this.wrap.createChild({
40857 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40858 this.viewEl = viewEl;
40859 this.wrap.on('click', this.onClick, this);
40861 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40862 this.el.on('propertychange', this.setFromHidden, this); //ie
40867 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40868 // viewEl.on('click', this.onClick, this);
40870 //if(this.checked){
40871 this.setChecked(this.checked);
40873 //this.checked = this.el.dom;
40879 initValue : Roo.emptyFn,
40882 * Returns the checked state of the checkbox.
40883 * @return {Boolean} True if checked, else false
40885 getValue : function(){
40887 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40889 return this.valueOff;
40894 onClick : function(){
40895 if (this.disabled) {
40898 this.setChecked(!this.checked);
40900 //if(this.el.dom.checked != this.checked){
40901 // this.setValue(this.el.dom.checked);
40906 * Sets the checked state of the checkbox.
40907 * On is always based on a string comparison between inputValue and the param.
40908 * @param {Boolean/String} value - the value to set
40909 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40911 setValue : function(v,suppressEvent){
40914 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40915 //if(this.el && this.el.dom){
40916 // this.el.dom.checked = this.checked;
40917 // this.el.dom.defaultChecked = this.checked;
40919 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40920 //this.fireEvent("check", this, this.checked);
40923 setChecked : function(state,suppressEvent)
40925 if (this.inSetChecked) {
40926 this.checked = state;
40932 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40934 this.checked = state;
40935 if(suppressEvent !== true){
40936 this.fireEvent('check', this, state);
40938 this.inSetChecked = true;
40939 this.el.dom.value = state ? this.inputValue : this.valueOff;
40940 this.inSetChecked = false;
40943 // handle setting of hidden value by some other method!!?!?
40944 setFromHidden: function()
40949 //console.log("SET FROM HIDDEN");
40950 //alert('setFrom hidden');
40951 this.setValue(this.el.dom.value);
40954 onDestroy : function()
40957 Roo.get(this.viewEl).remove();
40960 Roo.form.Checkbox.superclass.onDestroy.call(this);
40965 * Ext JS Library 1.1.1
40966 * Copyright(c) 2006-2007, Ext JS, LLC.
40968 * Originally Released Under LGPL - original licence link has changed is not relivant.
40971 * <script type="text/javascript">
40975 * @class Roo.form.Radio
40976 * @extends Roo.form.Checkbox
40977 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40978 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40980 * Creates a new Radio
40981 * @param {Object} config Configuration options
40983 Roo.form.Radio = function(){
40984 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40986 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40987 inputType: 'radio',
40990 * If this radio is part of a group, it will return the selected value
40993 getGroupValue : function(){
40994 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40998 onRender : function(ct, position){
40999 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41001 if(this.inputValue !== undefined){
41002 this.el.dom.value = this.inputValue;
41005 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41006 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41007 //var viewEl = this.wrap.createChild({
41008 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41009 //this.viewEl = viewEl;
41010 //this.wrap.on('click', this.onClick, this);
41012 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41013 //this.el.on('propertychange', this.setFromHidden, this); //ie
41018 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41019 // viewEl.on('click', this.onClick, this);
41022 this.el.dom.checked = 'checked' ;
41028 });//<script type="text/javascript">
41031 * Based Ext JS Library 1.1.1
41032 * Copyright(c) 2006-2007, Ext JS, LLC.
41038 * @class Roo.HtmlEditorCore
41039 * @extends Roo.Component
41040 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41042 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41045 Roo.HtmlEditorCore = function(config){
41048 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41053 * @event initialize
41054 * Fires when the editor is fully initialized (including the iframe)
41055 * @param {Roo.HtmlEditorCore} this
41060 * Fires when the editor is first receives the focus. Any insertion must wait
41061 * until after this event.
41062 * @param {Roo.HtmlEditorCore} this
41066 * @event beforesync
41067 * Fires before the textarea is updated with content from the editor iframe. Return false
41068 * to cancel the sync.
41069 * @param {Roo.HtmlEditorCore} this
41070 * @param {String} html
41074 * @event beforepush
41075 * Fires before the iframe editor is updated with content from the textarea. Return false
41076 * to cancel the push.
41077 * @param {Roo.HtmlEditorCore} this
41078 * @param {String} html
41083 * Fires when the textarea is updated with content from the editor iframe.
41084 * @param {Roo.HtmlEditorCore} this
41085 * @param {String} html
41090 * Fires when the iframe editor is updated with content from the textarea.
41091 * @param {Roo.HtmlEditorCore} this
41092 * @param {String} html
41097 * @event editorevent
41098 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41099 * @param {Roo.HtmlEditorCore} this
41104 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41106 // defaults : white / black...
41107 this.applyBlacklists();
41114 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41118 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41124 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41129 * @cfg {Number} height (in pixels)
41133 * @cfg {Number} width (in pixels)
41138 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41141 stylesheets: false,
41146 // private properties
41147 validationEvent : false,
41149 initialized : false,
41151 sourceEditMode : false,
41152 onFocus : Roo.emptyFn,
41154 hideMode:'offsets',
41158 // blacklist + whitelisted elements..
41165 * Protected method that will not generally be called directly. It
41166 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41167 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41169 getDocMarkup : function(){
41172 Roo.log(this.stylesheets);
41174 // inherit styels from page...??
41175 if (this.stylesheets === false) {
41177 Roo.get(document.head).select('style').each(function(node) {
41178 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41181 Roo.get(document.head).select('link').each(function(node) {
41182 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41185 } else if (!this.stylesheets.length) {
41187 st = '<style type="text/css">' +
41188 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41191 Roo.each(this.stylesheets, function(s) {
41192 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41197 st += '<style type="text/css">' +
41198 'IMG { cursor: pointer } ' +
41202 return '<html><head>' + st +
41203 //<style type="text/css">' +
41204 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41206 ' </head><body class="roo-htmleditor-body"></body></html>';
41210 onRender : function(ct, position)
41213 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41214 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41217 this.el.dom.style.border = '0 none';
41218 this.el.dom.setAttribute('tabIndex', -1);
41219 this.el.addClass('x-hidden hide');
41223 if(Roo.isIE){ // fix IE 1px bogus margin
41224 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41228 this.frameId = Roo.id();
41232 var iframe = this.owner.wrap.createChild({
41234 cls: 'form-control', // bootstrap..
41236 name: this.frameId,
41237 frameBorder : 'no',
41238 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41243 this.iframe = iframe.dom;
41245 this.assignDocWin();
41247 this.doc.designMode = 'on';
41250 this.doc.write(this.getDocMarkup());
41254 var task = { // must defer to wait for browser to be ready
41256 //console.log("run task?" + this.doc.readyState);
41257 this.assignDocWin();
41258 if(this.doc.body || this.doc.readyState == 'complete'){
41260 this.doc.designMode="on";
41264 Roo.TaskMgr.stop(task);
41265 this.initEditor.defer(10, this);
41272 Roo.TaskMgr.start(task);
41279 onResize : function(w, h)
41281 Roo.log('resize: ' +w + ',' + h );
41282 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41286 if(typeof w == 'number'){
41288 this.iframe.style.width = w + 'px';
41290 if(typeof h == 'number'){
41292 this.iframe.style.height = h + 'px';
41294 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41301 * Toggles the editor between standard and source edit mode.
41302 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41304 toggleSourceEdit : function(sourceEditMode){
41306 this.sourceEditMode = sourceEditMode === true;
41308 if(this.sourceEditMode){
41310 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41313 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41314 //this.iframe.className = '';
41317 //this.setSize(this.owner.wrap.getSize());
41318 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41325 * Protected method that will not generally be called directly. If you need/want
41326 * custom HTML cleanup, this is the method you should override.
41327 * @param {String} html The HTML to be cleaned
41328 * return {String} The cleaned HTML
41330 cleanHtml : function(html){
41331 html = String(html);
41332 if(html.length > 5){
41333 if(Roo.isSafari){ // strip safari nonsense
41334 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41337 if(html == ' '){
41344 * HTML Editor -> Textarea
41345 * Protected method that will not generally be called directly. Syncs the contents
41346 * of the editor iframe with the textarea.
41348 syncValue : function(){
41349 if(this.initialized){
41350 var bd = (this.doc.body || this.doc.documentElement);
41351 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41352 var html = bd.innerHTML;
41354 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41355 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41357 html = '<div style="'+m[0]+'">' + html + '</div>';
41360 html = this.cleanHtml(html);
41361 // fix up the special chars.. normaly like back quotes in word...
41362 // however we do not want to do this with chinese..
41363 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41364 var cc = b.charCodeAt();
41366 (cc >= 0x4E00 && cc < 0xA000 ) ||
41367 (cc >= 0x3400 && cc < 0x4E00 ) ||
41368 (cc >= 0xf900 && cc < 0xfb00 )
41374 if(this.owner.fireEvent('beforesync', this, html) !== false){
41375 this.el.dom.value = html;
41376 this.owner.fireEvent('sync', this, html);
41382 * Protected method that will not generally be called directly. Pushes the value of the textarea
41383 * into the iframe editor.
41385 pushValue : function(){
41386 if(this.initialized){
41387 var v = this.el.dom.value.trim();
41389 // if(v.length < 1){
41393 if(this.owner.fireEvent('beforepush', this, v) !== false){
41394 var d = (this.doc.body || this.doc.documentElement);
41396 this.cleanUpPaste();
41397 this.el.dom.value = d.innerHTML;
41398 this.owner.fireEvent('push', this, v);
41404 deferFocus : function(){
41405 this.focus.defer(10, this);
41409 focus : function(){
41410 if(this.win && !this.sourceEditMode){
41417 assignDocWin: function()
41419 var iframe = this.iframe;
41422 this.doc = iframe.contentWindow.document;
41423 this.win = iframe.contentWindow;
41425 // if (!Roo.get(this.frameId)) {
41428 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41429 // this.win = Roo.get(this.frameId).dom.contentWindow;
41431 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41435 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41436 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41441 initEditor : function(){
41442 //console.log("INIT EDITOR");
41443 this.assignDocWin();
41447 this.doc.designMode="on";
41449 this.doc.write(this.getDocMarkup());
41452 var dbody = (this.doc.body || this.doc.documentElement);
41453 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41454 // this copies styles from the containing element into thsi one..
41455 // not sure why we need all of this..
41456 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41458 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41459 //ss['background-attachment'] = 'fixed'; // w3c
41460 dbody.bgProperties = 'fixed'; // ie
41461 //Roo.DomHelper.applyStyles(dbody, ss);
41462 Roo.EventManager.on(this.doc, {
41463 //'mousedown': this.onEditorEvent,
41464 'mouseup': this.onEditorEvent,
41465 'dblclick': this.onEditorEvent,
41466 'click': this.onEditorEvent,
41467 'keyup': this.onEditorEvent,
41472 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41474 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41475 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41477 this.initialized = true;
41479 this.owner.fireEvent('initialize', this);
41484 onDestroy : function(){
41490 //for (var i =0; i < this.toolbars.length;i++) {
41491 // // fixme - ask toolbars for heights?
41492 // this.toolbars[i].onDestroy();
41495 //this.wrap.dom.innerHTML = '';
41496 //this.wrap.remove();
41501 onFirstFocus : function(){
41503 this.assignDocWin();
41506 this.activated = true;
41509 if(Roo.isGecko){ // prevent silly gecko errors
41511 var s = this.win.getSelection();
41512 if(!s.focusNode || s.focusNode.nodeType != 3){
41513 var r = s.getRangeAt(0);
41514 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41519 this.execCmd('useCSS', true);
41520 this.execCmd('styleWithCSS', false);
41523 this.owner.fireEvent('activate', this);
41527 adjustFont: function(btn){
41528 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41529 //if(Roo.isSafari){ // safari
41532 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41533 if(Roo.isSafari){ // safari
41534 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41535 v = (v < 10) ? 10 : v;
41536 v = (v > 48) ? 48 : v;
41537 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41542 v = Math.max(1, v+adjust);
41544 this.execCmd('FontSize', v );
41547 onEditorEvent : function(e){
41548 this.owner.fireEvent('editorevent', this, e);
41549 // this.updateToolbar();
41550 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41553 insertTag : function(tg)
41555 // could be a bit smarter... -> wrap the current selected tRoo..
41556 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41558 range = this.createRange(this.getSelection());
41559 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41560 wrappingNode.appendChild(range.extractContents());
41561 range.insertNode(wrappingNode);
41568 this.execCmd("formatblock", tg);
41572 insertText : function(txt)
41576 var range = this.createRange();
41577 range.deleteContents();
41578 //alert(Sender.getAttribute('label'));
41580 range.insertNode(this.doc.createTextNode(txt));
41586 * Executes a Midas editor command on the editor document and performs necessary focus and
41587 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41588 * @param {String} cmd The Midas command
41589 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41591 relayCmd : function(cmd, value){
41593 this.execCmd(cmd, value);
41594 this.owner.fireEvent('editorevent', this);
41595 //this.updateToolbar();
41596 this.owner.deferFocus();
41600 * Executes a Midas editor command directly on the editor document.
41601 * For visual commands, you should use {@link #relayCmd} instead.
41602 * <b>This should only be called after the editor is initialized.</b>
41603 * @param {String} cmd The Midas command
41604 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41606 execCmd : function(cmd, value){
41607 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41614 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41616 * @param {String} text | dom node..
41618 insertAtCursor : function(text)
41623 if(!this.activated){
41629 var r = this.doc.selection.createRange();
41640 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41644 // from jquery ui (MIT licenced)
41646 var win = this.win;
41648 if (win.getSelection && win.getSelection().getRangeAt) {
41649 range = win.getSelection().getRangeAt(0);
41650 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41651 range.insertNode(node);
41652 } else if (win.document.selection && win.document.selection.createRange) {
41653 // no firefox support
41654 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41655 win.document.selection.createRange().pasteHTML(txt);
41657 // no firefox support
41658 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41659 this.execCmd('InsertHTML', txt);
41668 mozKeyPress : function(e){
41670 var c = e.getCharCode(), cmd;
41673 c = String.fromCharCode(c).toLowerCase();
41687 this.cleanUpPaste.defer(100, this);
41695 e.preventDefault();
41703 fixKeys : function(){ // load time branching for fastest keydown performance
41705 return function(e){
41706 var k = e.getKey(), r;
41709 r = this.doc.selection.createRange();
41712 r.pasteHTML('    ');
41719 r = this.doc.selection.createRange();
41721 var target = r.parentElement();
41722 if(!target || target.tagName.toLowerCase() != 'li'){
41724 r.pasteHTML('<br />');
41730 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41731 this.cleanUpPaste.defer(100, this);
41737 }else if(Roo.isOpera){
41738 return function(e){
41739 var k = e.getKey();
41743 this.execCmd('InsertHTML','    ');
41746 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41747 this.cleanUpPaste.defer(100, this);
41752 }else if(Roo.isSafari){
41753 return function(e){
41754 var k = e.getKey();
41758 this.execCmd('InsertText','\t');
41762 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41763 this.cleanUpPaste.defer(100, this);
41771 getAllAncestors: function()
41773 var p = this.getSelectedNode();
41776 a.push(p); // push blank onto stack..
41777 p = this.getParentElement();
41781 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41785 a.push(this.doc.body);
41789 lastSelNode : false,
41792 getSelection : function()
41794 this.assignDocWin();
41795 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41798 getSelectedNode: function()
41800 // this may only work on Gecko!!!
41802 // should we cache this!!!!
41807 var range = this.createRange(this.getSelection()).cloneRange();
41810 var parent = range.parentElement();
41812 var testRange = range.duplicate();
41813 testRange.moveToElementText(parent);
41814 if (testRange.inRange(range)) {
41817 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41820 parent = parent.parentElement;
41825 // is ancestor a text element.
41826 var ac = range.commonAncestorContainer;
41827 if (ac.nodeType == 3) {
41828 ac = ac.parentNode;
41831 var ar = ac.childNodes;
41834 var other_nodes = [];
41835 var has_other_nodes = false;
41836 for (var i=0;i<ar.length;i++) {
41837 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41840 // fullly contained node.
41842 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41847 // probably selected..
41848 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41849 other_nodes.push(ar[i]);
41853 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41858 has_other_nodes = true;
41860 if (!nodes.length && other_nodes.length) {
41861 nodes= other_nodes;
41863 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41869 createRange: function(sel)
41871 // this has strange effects when using with
41872 // top toolbar - not sure if it's a great idea.
41873 //this.editor.contentWindow.focus();
41874 if (typeof sel != "undefined") {
41876 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41878 return this.doc.createRange();
41881 return this.doc.createRange();
41884 getParentElement: function()
41887 this.assignDocWin();
41888 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41890 var range = this.createRange(sel);
41893 var p = range.commonAncestorContainer;
41894 while (p.nodeType == 3) { // text node
41905 * Range intersection.. the hard stuff...
41909 * [ -- selected range --- ]
41913 * if end is before start or hits it. fail.
41914 * if start is after end or hits it fail.
41916 * if either hits (but other is outside. - then it's not
41922 // @see http://www.thismuchiknow.co.uk/?p=64.
41923 rangeIntersectsNode : function(range, node)
41925 var nodeRange = node.ownerDocument.createRange();
41927 nodeRange.selectNode(node);
41929 nodeRange.selectNodeContents(node);
41932 var rangeStartRange = range.cloneRange();
41933 rangeStartRange.collapse(true);
41935 var rangeEndRange = range.cloneRange();
41936 rangeEndRange.collapse(false);
41938 var nodeStartRange = nodeRange.cloneRange();
41939 nodeStartRange.collapse(true);
41941 var nodeEndRange = nodeRange.cloneRange();
41942 nodeEndRange.collapse(false);
41944 return rangeStartRange.compareBoundaryPoints(
41945 Range.START_TO_START, nodeEndRange) == -1 &&
41946 rangeEndRange.compareBoundaryPoints(
41947 Range.START_TO_START, nodeStartRange) == 1;
41951 rangeCompareNode : function(range, node)
41953 var nodeRange = node.ownerDocument.createRange();
41955 nodeRange.selectNode(node);
41957 nodeRange.selectNodeContents(node);
41961 range.collapse(true);
41963 nodeRange.collapse(true);
41965 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41966 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41968 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41970 var nodeIsBefore = ss == 1;
41971 var nodeIsAfter = ee == -1;
41973 if (nodeIsBefore && nodeIsAfter)
41975 if (!nodeIsBefore && nodeIsAfter)
41976 return 1; //right trailed.
41978 if (nodeIsBefore && !nodeIsAfter)
41979 return 2; // left trailed.
41984 // private? - in a new class?
41985 cleanUpPaste : function()
41987 // cleans up the whole document..
41988 Roo.log('cleanuppaste');
41990 this.cleanUpChildren(this.doc.body);
41991 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41992 if (clean != this.doc.body.innerHTML) {
41993 this.doc.body.innerHTML = clean;
41998 cleanWordChars : function(input) {// change the chars to hex code
41999 var he = Roo.HtmlEditorCore;
42001 var output = input;
42002 Roo.each(he.swapCodes, function(sw) {
42003 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42005 output = output.replace(swapper, sw[1]);
42012 cleanUpChildren : function (n)
42014 if (!n.childNodes.length) {
42017 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42018 this.cleanUpChild(n.childNodes[i]);
42025 cleanUpChild : function (node)
42028 //console.log(node);
42029 if (node.nodeName == "#text") {
42030 // clean up silly Windows -- stuff?
42033 if (node.nodeName == "#comment") {
42034 node.parentNode.removeChild(node);
42035 // clean up silly Windows -- stuff?
42038 var lcname = node.tagName.toLowerCase();
42039 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42040 // whitelist of tags..
42042 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42044 node.parentNode.removeChild(node);
42049 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42051 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42052 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42054 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42055 // remove_keep_children = true;
42058 if (remove_keep_children) {
42059 this.cleanUpChildren(node);
42060 // inserts everything just before this node...
42061 while (node.childNodes.length) {
42062 var cn = node.childNodes[0];
42063 node.removeChild(cn);
42064 node.parentNode.insertBefore(cn, node);
42066 node.parentNode.removeChild(node);
42070 if (!node.attributes || !node.attributes.length) {
42071 this.cleanUpChildren(node);
42075 function cleanAttr(n,v)
42078 if (v.match(/^\./) || v.match(/^\//)) {
42081 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42084 if (v.match(/^#/)) {
42087 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42088 node.removeAttribute(n);
42092 var cwhite = this.cwhite;
42093 var cblack = this.cblack;
42095 function cleanStyle(n,v)
42097 if (v.match(/expression/)) { //XSS?? should we even bother..
42098 node.removeAttribute(n);
42102 var parts = v.split(/;/);
42105 Roo.each(parts, function(p) {
42106 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42110 var l = p.split(':').shift().replace(/\s+/g,'');
42111 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42113 if ( cwhite.length && cblack.indexOf(l) > -1) {
42114 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42115 //node.removeAttribute(n);
42119 // only allow 'c whitelisted system attributes'
42120 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42121 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42122 //node.removeAttribute(n);
42132 if (clean.length) {
42133 node.setAttribute(n, clean.join(';'));
42135 node.removeAttribute(n);
42141 for (var i = node.attributes.length-1; i > -1 ; i--) {
42142 var a = node.attributes[i];
42145 if (a.name.toLowerCase().substr(0,2)=='on') {
42146 node.removeAttribute(a.name);
42149 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42150 node.removeAttribute(a.name);
42153 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42154 cleanAttr(a.name,a.value); // fixme..
42157 if (a.name == 'style') {
42158 cleanStyle(a.name,a.value);
42161 /// clean up MS crap..
42162 // tecnically this should be a list of valid class'es..
42165 if (a.name == 'class') {
42166 if (a.value.match(/^Mso/)) {
42167 node.className = '';
42170 if (a.value.match(/body/)) {
42171 node.className = '';
42182 this.cleanUpChildren(node);
42187 * Clean up MS wordisms...
42189 cleanWord : function(node)
42192 var cleanWordChildren = function()
42194 if (!node.childNodes.length) {
42197 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42198 _t.cleanWord(node.childNodes[i]);
42204 this.cleanWord(this.doc.body);
42207 if (node.nodeName == "#text") {
42208 // clean up silly Windows -- stuff?
42211 if (node.nodeName == "#comment") {
42212 node.parentNode.removeChild(node);
42213 // clean up silly Windows -- stuff?
42217 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42218 node.parentNode.removeChild(node);
42222 // remove - but keep children..
42223 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42224 while (node.childNodes.length) {
42225 var cn = node.childNodes[0];
42226 node.removeChild(cn);
42227 node.parentNode.insertBefore(cn, node);
42229 node.parentNode.removeChild(node);
42230 cleanWordChildren();
42234 if (node.className.length) {
42236 var cn = node.className.split(/\W+/);
42238 Roo.each(cn, function(cls) {
42239 if (cls.match(/Mso[a-zA-Z]+/)) {
42244 node.className = cna.length ? cna.join(' ') : '';
42246 node.removeAttribute("class");
42250 if (node.hasAttribute("lang")) {
42251 node.removeAttribute("lang");
42254 if (node.hasAttribute("style")) {
42256 var styles = node.getAttribute("style").split(";");
42258 Roo.each(styles, function(s) {
42259 if (!s.match(/:/)) {
42262 var kv = s.split(":");
42263 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42266 // what ever is left... we allow.
42269 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42270 if (!nstyle.length) {
42271 node.removeAttribute('style');
42275 cleanWordChildren();
42279 domToHTML : function(currentElement, depth, nopadtext) {
42281 depth = depth || 0;
42282 nopadtext = nopadtext || false;
42284 if (!currentElement) {
42285 return this.domToHTML(this.doc.body);
42288 //Roo.log(currentElement);
42290 var allText = false;
42291 var nodeName = currentElement.nodeName;
42292 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42294 if (nodeName == '#text') {
42295 return currentElement.nodeValue;
42300 if (nodeName != 'BODY') {
42303 // Prints the node tagName, such as <A>, <IMG>, etc
42306 for(i = 0; i < currentElement.attributes.length;i++) {
42308 var aname = currentElement.attributes.item(i).name;
42309 if (!currentElement.attributes.item(i).value.length) {
42312 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42315 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42324 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42327 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42332 // Traverse the tree
42334 var currentElementChild = currentElement.childNodes.item(i);
42335 var allText = true;
42336 var innerHTML = '';
42338 while (currentElementChild) {
42339 // Formatting code (indent the tree so it looks nice on the screen)
42340 var nopad = nopadtext;
42341 if (lastnode == 'SPAN') {
42345 if (currentElementChild.nodeName == '#text') {
42346 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42347 if (!nopad && toadd.length > 80) {
42348 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42350 innerHTML += toadd;
42353 currentElementChild = currentElement.childNodes.item(i);
42359 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42361 // Recursively traverse the tree structure of the child node
42362 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42363 lastnode = currentElementChild.nodeName;
42365 currentElementChild=currentElement.childNodes.item(i);
42371 // The remaining code is mostly for formatting the tree
42372 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42377 ret+= "</"+tagName+">";
42383 applyBlacklists : function()
42385 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42386 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42390 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42391 if (b.indexOf(tag) > -1) {
42394 this.white.push(tag);
42398 Roo.each(w, function(tag) {
42399 if (b.indexOf(tag) > -1) {
42402 if (this.white.indexOf(tag) > -1) {
42405 this.white.push(tag);
42410 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42411 if (w.indexOf(tag) > -1) {
42414 this.black.push(tag);
42418 Roo.each(b, function(tag) {
42419 if (w.indexOf(tag) > -1) {
42422 if (this.black.indexOf(tag) > -1) {
42425 this.black.push(tag);
42430 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42431 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42435 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42436 if (b.indexOf(tag) > -1) {
42439 this.cwhite.push(tag);
42443 Roo.each(w, function(tag) {
42444 if (b.indexOf(tag) > -1) {
42447 if (this.cwhite.indexOf(tag) > -1) {
42450 this.cwhite.push(tag);
42455 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42456 if (w.indexOf(tag) > -1) {
42459 this.cblack.push(tag);
42463 Roo.each(b, function(tag) {
42464 if (w.indexOf(tag) > -1) {
42467 if (this.cblack.indexOf(tag) > -1) {
42470 this.cblack.push(tag);
42475 // hide stuff that is not compatible
42489 * @event specialkey
42493 * @cfg {String} fieldClass @hide
42496 * @cfg {String} focusClass @hide
42499 * @cfg {String} autoCreate @hide
42502 * @cfg {String} inputType @hide
42505 * @cfg {String} invalidClass @hide
42508 * @cfg {String} invalidText @hide
42511 * @cfg {String} msgFx @hide
42514 * @cfg {String} validateOnBlur @hide
42518 Roo.HtmlEditorCore.white = [
42519 'area', 'br', 'img', 'input', 'hr', 'wbr',
42521 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42522 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42523 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42524 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42525 'table', 'ul', 'xmp',
42527 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42530 'dir', 'menu', 'ol', 'ul', 'dl',
42536 Roo.HtmlEditorCore.black = [
42537 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42539 'base', 'basefont', 'bgsound', 'blink', 'body',
42540 'frame', 'frameset', 'head', 'html', 'ilayer',
42541 'iframe', 'layer', 'link', 'meta', 'object',
42542 'script', 'style' ,'title', 'xml' // clean later..
42544 Roo.HtmlEditorCore.clean = [
42545 'script', 'style', 'title', 'xml'
42547 Roo.HtmlEditorCore.remove = [
42552 Roo.HtmlEditorCore.ablack = [
42556 Roo.HtmlEditorCore.aclean = [
42557 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42561 Roo.HtmlEditorCore.pwhite= [
42562 'http', 'https', 'mailto'
42565 // white listed style attributes.
42566 Roo.HtmlEditorCore.cwhite= [
42567 // 'text-align', /// default is to allow most things..
42573 // black listed style attributes.
42574 Roo.HtmlEditorCore.cblack= [
42575 // 'font-size' -- this can be set by the project
42579 Roo.HtmlEditorCore.swapCodes =[
42590 //<script type="text/javascript">
42593 * Ext JS Library 1.1.1
42594 * Copyright(c) 2006-2007, Ext JS, LLC.
42600 Roo.form.HtmlEditor = function(config){
42604 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42606 if (!this.toolbars) {
42607 this.toolbars = [];
42609 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42615 * @class Roo.form.HtmlEditor
42616 * @extends Roo.form.Field
42617 * Provides a lightweight HTML Editor component.
42619 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42621 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42622 * supported by this editor.</b><br/><br/>
42623 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42624 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42626 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42628 * @cfg {Boolean} clearUp
42632 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42637 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42642 * @cfg {Number} height (in pixels)
42646 * @cfg {Number} width (in pixels)
42651 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42654 stylesheets: false,
42658 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42663 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42669 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42674 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42682 // private properties
42683 validationEvent : false,
42685 initialized : false,
42688 onFocus : Roo.emptyFn,
42690 hideMode:'offsets',
42692 actionMode : 'container', // defaults to hiding it...
42694 defaultAutoCreate : { // modified by initCompnoent..
42696 style:"width:500px;height:300px;",
42697 autocomplete: "off"
42701 initComponent : function(){
42704 * @event initialize
42705 * Fires when the editor is fully initialized (including the iframe)
42706 * @param {HtmlEditor} this
42711 * Fires when the editor is first receives the focus. Any insertion must wait
42712 * until after this event.
42713 * @param {HtmlEditor} this
42717 * @event beforesync
42718 * Fires before the textarea is updated with content from the editor iframe. Return false
42719 * to cancel the sync.
42720 * @param {HtmlEditor} this
42721 * @param {String} html
42725 * @event beforepush
42726 * Fires before the iframe editor is updated with content from the textarea. Return false
42727 * to cancel the push.
42728 * @param {HtmlEditor} this
42729 * @param {String} html
42734 * Fires when the textarea is updated with content from the editor iframe.
42735 * @param {HtmlEditor} this
42736 * @param {String} html
42741 * Fires when the iframe editor is updated with content from the textarea.
42742 * @param {HtmlEditor} this
42743 * @param {String} html
42747 * @event editmodechange
42748 * Fires when the editor switches edit modes
42749 * @param {HtmlEditor} this
42750 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42752 editmodechange: true,
42754 * @event editorevent
42755 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42756 * @param {HtmlEditor} this
42760 * @event firstfocus
42761 * Fires when on first focus - needed by toolbars..
42762 * @param {HtmlEditor} this
42767 * Auto save the htmlEditor value as a file into Events
42768 * @param {HtmlEditor} this
42772 * @event savedpreview
42773 * preview the saved version of htmlEditor
42774 * @param {HtmlEditor} this
42778 this.defaultAutoCreate = {
42780 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42781 autocomplete: "off"
42786 * Protected method that will not generally be called directly. It
42787 * is called when the editor creates its toolbar. Override this method if you need to
42788 * add custom toolbar buttons.
42789 * @param {HtmlEditor} editor
42791 createToolbar : function(editor){
42792 Roo.log("create toolbars");
42793 if (!editor.toolbars || !editor.toolbars.length) {
42794 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42797 for (var i =0 ; i < editor.toolbars.length;i++) {
42798 editor.toolbars[i] = Roo.factory(
42799 typeof(editor.toolbars[i]) == 'string' ?
42800 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42801 Roo.form.HtmlEditor);
42802 editor.toolbars[i].init(editor);
42810 onRender : function(ct, position)
42813 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42815 this.wrap = this.el.wrap({
42816 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42819 this.editorcore.onRender(ct, position);
42821 if (this.resizable) {
42822 this.resizeEl = new Roo.Resizable(this.wrap, {
42826 minHeight : this.height,
42827 height: this.height,
42828 handles : this.resizable,
42831 resize : function(r, w, h) {
42832 _t.onResize(w,h); // -something
42838 this.createToolbar(this);
42842 this.setSize(this.wrap.getSize());
42844 if (this.resizeEl) {
42845 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42846 // should trigger onReize..
42849 // if(this.autosave && this.w){
42850 // this.autoSaveFn = setInterval(this.autosave, 1000);
42855 onResize : function(w, h)
42857 //Roo.log('resize: ' +w + ',' + h );
42858 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42863 if(typeof w == 'number'){
42864 var aw = w - this.wrap.getFrameWidth('lr');
42865 this.el.setWidth(this.adjustWidth('textarea', aw));
42868 if(typeof h == 'number'){
42870 for (var i =0; i < this.toolbars.length;i++) {
42871 // fixme - ask toolbars for heights?
42872 tbh += this.toolbars[i].tb.el.getHeight();
42873 if (this.toolbars[i].footer) {
42874 tbh += this.toolbars[i].footer.el.getHeight();
42881 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42882 ah -= 5; // knock a few pixes off for look..
42883 this.el.setHeight(this.adjustWidth('textarea', ah));
42887 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42888 this.editorcore.onResize(ew,eh);
42893 * Toggles the editor between standard and source edit mode.
42894 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42896 toggleSourceEdit : function(sourceEditMode)
42898 this.editorcore.toggleSourceEdit(sourceEditMode);
42900 if(this.editorcore.sourceEditMode){
42901 Roo.log('editor - showing textarea');
42904 // Roo.log(this.syncValue());
42905 this.editorcore.syncValue();
42906 this.el.removeClass('x-hidden');
42907 this.el.dom.removeAttribute('tabIndex');
42910 Roo.log('editor - hiding textarea');
42912 // Roo.log(this.pushValue());
42913 this.editorcore.pushValue();
42915 this.el.addClass('x-hidden');
42916 this.el.dom.setAttribute('tabIndex', -1);
42917 //this.deferFocus();
42920 this.setSize(this.wrap.getSize());
42921 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42924 // private (for BoxComponent)
42925 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42927 // private (for BoxComponent)
42928 getResizeEl : function(){
42932 // private (for BoxComponent)
42933 getPositionEl : function(){
42938 initEvents : function(){
42939 this.originalValue = this.getValue();
42943 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42946 markInvalid : Roo.emptyFn,
42948 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42951 clearInvalid : Roo.emptyFn,
42953 setValue : function(v){
42954 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42955 this.editorcore.pushValue();
42960 deferFocus : function(){
42961 this.focus.defer(10, this);
42965 focus : function(){
42966 this.editorcore.focus();
42972 onDestroy : function(){
42978 for (var i =0; i < this.toolbars.length;i++) {
42979 // fixme - ask toolbars for heights?
42980 this.toolbars[i].onDestroy();
42983 this.wrap.dom.innerHTML = '';
42984 this.wrap.remove();
42989 onFirstFocus : function(){
42990 //Roo.log("onFirstFocus");
42991 this.editorcore.onFirstFocus();
42992 for (var i =0; i < this.toolbars.length;i++) {
42993 this.toolbars[i].onFirstFocus();
42999 syncValue : function()
43001 this.editorcore.syncValue();
43004 pushValue : function()
43006 this.editorcore.pushValue();
43010 // hide stuff that is not compatible
43024 * @event specialkey
43028 * @cfg {String} fieldClass @hide
43031 * @cfg {String} focusClass @hide
43034 * @cfg {String} autoCreate @hide
43037 * @cfg {String} inputType @hide
43040 * @cfg {String} invalidClass @hide
43043 * @cfg {String} invalidText @hide
43046 * @cfg {String} msgFx @hide
43049 * @cfg {String} validateOnBlur @hide
43053 // <script type="text/javascript">
43056 * Ext JS Library 1.1.1
43057 * Copyright(c) 2006-2007, Ext JS, LLC.
43063 * @class Roo.form.HtmlEditorToolbar1
43068 new Roo.form.HtmlEditor({
43071 new Roo.form.HtmlEditorToolbar1({
43072 disable : { fonts: 1 , format: 1, ..., ... , ...],
43078 * @cfg {Object} disable List of elements to disable..
43079 * @cfg {Array} btns List of additional buttons.
43083 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43086 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43089 Roo.apply(this, config);
43091 // default disabled, based on 'good practice'..
43092 this.disable = this.disable || {};
43093 Roo.applyIf(this.disable, {
43096 specialElements : true
43100 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43101 // dont call parent... till later.
43104 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43111 editorcore : false,
43113 * @cfg {Object} disable List of toolbar elements to disable
43120 * @cfg {String} createLinkText The default text for the create link prompt
43122 createLinkText : 'Please enter the URL for the link:',
43124 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43126 defaultLinkValue : 'http:/'+'/',
43130 * @cfg {Array} fontFamilies An array of available font families
43148 // "á" , ?? a acute?
43153 "°" // , // degrees
43155 // "é" , // e ecute
43156 // "ú" , // u ecute?
43159 specialElements : [
43161 text: "Insert Table",
43164 ihtml : '<table><tr><td>Cell</td></tr></table>'
43168 text: "Insert Image",
43171 ihtml : '<img src="about:blank"/>'
43180 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43181 "input:submit", "input:button", "select", "textarea", "label" ],
43184 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43186 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43194 * @cfg {String} defaultFont default font to use.
43196 defaultFont: 'tahoma',
43198 fontSelect : false,
43201 formatCombo : false,
43203 init : function(editor)
43205 this.editor = editor;
43206 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43207 var editorcore = this.editorcore;
43211 var fid = editorcore.frameId;
43213 function btn(id, toggle, handler){
43214 var xid = fid + '-'+ id ;
43218 cls : 'x-btn-icon x-edit-'+id,
43219 enableToggle:toggle !== false,
43220 scope: _t, // was editor...
43221 handler:handler||_t.relayBtnCmd,
43222 clickEvent:'mousedown',
43223 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43230 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43232 // stop form submits
43233 tb.el.on('click', function(e){
43234 e.preventDefault(); // what does this do?
43237 if(!this.disable.font) { // && !Roo.isSafari){
43238 /* why no safari for fonts
43239 editor.fontSelect = tb.el.createChild({
43242 cls:'x-font-select',
43243 html: this.createFontOptions()
43246 editor.fontSelect.on('change', function(){
43247 var font = editor.fontSelect.dom.value;
43248 editor.relayCmd('fontname', font);
43249 editor.deferFocus();
43253 editor.fontSelect.dom,
43259 if(!this.disable.formats){
43260 this.formatCombo = new Roo.form.ComboBox({
43261 store: new Roo.data.SimpleStore({
43264 data : this.formats // from states.js
43268 //autoCreate : {tag: "div", size: "20"},
43269 displayField:'tag',
43273 triggerAction: 'all',
43274 emptyText:'Add tag',
43275 selectOnFocus:true,
43278 'select': function(c, r, i) {
43279 editorcore.insertTag(r.get('tag'));
43285 tb.addField(this.formatCombo);
43289 if(!this.disable.format){
43296 if(!this.disable.fontSize){
43301 btn('increasefontsize', false, editorcore.adjustFont),
43302 btn('decreasefontsize', false, editorcore.adjustFont)
43307 if(!this.disable.colors){
43310 id:editorcore.frameId +'-forecolor',
43311 cls:'x-btn-icon x-edit-forecolor',
43312 clickEvent:'mousedown',
43313 tooltip: this.buttonTips['forecolor'] || undefined,
43315 menu : new Roo.menu.ColorMenu({
43316 allowReselect: true,
43317 focus: Roo.emptyFn,
43320 selectHandler: function(cp, color){
43321 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43322 editor.deferFocus();
43325 clickEvent:'mousedown'
43328 id:editorcore.frameId +'backcolor',
43329 cls:'x-btn-icon x-edit-backcolor',
43330 clickEvent:'mousedown',
43331 tooltip: this.buttonTips['backcolor'] || undefined,
43333 menu : new Roo.menu.ColorMenu({
43334 focus: Roo.emptyFn,
43337 allowReselect: true,
43338 selectHandler: function(cp, color){
43340 editorcore.execCmd('useCSS', false);
43341 editorcore.execCmd('hilitecolor', color);
43342 editorcore.execCmd('useCSS', true);
43343 editor.deferFocus();
43345 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43346 Roo.isSafari || Roo.isIE ? '#'+color : color);
43347 editor.deferFocus();
43351 clickEvent:'mousedown'
43356 // now add all the items...
43359 if(!this.disable.alignments){
43362 btn('justifyleft'),
43363 btn('justifycenter'),
43364 btn('justifyright')
43368 //if(!Roo.isSafari){
43369 if(!this.disable.links){
43372 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43376 if(!this.disable.lists){
43379 btn('insertorderedlist'),
43380 btn('insertunorderedlist')
43383 if(!this.disable.sourceEdit){
43386 btn('sourceedit', true, function(btn){
43388 this.toggleSourceEdit(btn.pressed);
43395 // special menu.. - needs to be tidied up..
43396 if (!this.disable.special) {
43399 cls: 'x-edit-none',
43405 for (var i =0; i < this.specialChars.length; i++) {
43406 smenu.menu.items.push({
43408 html: this.specialChars[i],
43409 handler: function(a,b) {
43410 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43411 //editor.insertAtCursor(a.html);
43425 if (!this.disable.cleanStyles) {
43427 cls: 'x-btn-icon x-btn-clear',
43433 for (var i =0; i < this.cleanStyles.length; i++) {
43434 cmenu.menu.items.push({
43435 actiontype : this.cleanStyles[i],
43436 html: 'Remove ' + this.cleanStyles[i],
43437 handler: function(a,b) {
43440 var c = Roo.get(editorcore.doc.body);
43441 c.select('[style]').each(function(s) {
43442 s.dom.style.removeProperty(a.actiontype);
43444 editorcore.syncValue();
43449 cmenu.menu.items.push({
43450 actiontype : 'word',
43451 html: 'Remove MS Word Formating',
43452 handler: function(a,b) {
43453 editorcore.cleanWord();
43454 editorcore.syncValue();
43459 cmenu.menu.items.push({
43460 actiontype : 'all',
43461 html: 'Remove All Styles',
43462 handler: function(a,b) {
43464 var c = Roo.get(editorcore.doc.body);
43465 c.select('[style]').each(function(s) {
43466 s.dom.removeAttribute('style');
43468 editorcore.syncValue();
43472 cmenu.menu.items.push({
43473 actiontype : 'word',
43474 html: 'Tidy HTML Source',
43475 handler: function(a,b) {
43476 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43477 editorcore.syncValue();
43486 if (!this.disable.specialElements) {
43489 cls: 'x-edit-none',
43494 for (var i =0; i < this.specialElements.length; i++) {
43495 semenu.menu.items.push(
43497 handler: function(a,b) {
43498 editor.insertAtCursor(this.ihtml);
43500 }, this.specialElements[i])
43512 for(var i =0; i< this.btns.length;i++) {
43513 var b = Roo.factory(this.btns[i],Roo.form);
43514 b.cls = 'x-edit-none';
43515 b.scope = editorcore;
43523 // disable everything...
43525 this.tb.items.each(function(item){
43526 if(item.id != editorcore.frameId+ '-sourceedit'){
43530 this.rendered = true;
43532 // the all the btns;
43533 editor.on('editorevent', this.updateToolbar, this);
43534 // other toolbars need to implement this..
43535 //editor.on('editmodechange', this.updateToolbar, this);
43539 relayBtnCmd : function(btn) {
43540 this.editorcore.relayCmd(btn.cmd);
43542 // private used internally
43543 createLink : function(){
43544 Roo.log("create link?");
43545 var url = prompt(this.createLinkText, this.defaultLinkValue);
43546 if(url && url != 'http:/'+'/'){
43547 this.editorcore.relayCmd('createlink', url);
43553 * Protected method that will not generally be called directly. It triggers
43554 * a toolbar update by reading the markup state of the current selection in the editor.
43556 updateToolbar: function(){
43558 if(!this.editorcore.activated){
43559 this.editor.onFirstFocus();
43563 var btns = this.tb.items.map,
43564 doc = this.editorcore.doc,
43565 frameId = this.editorcore.frameId;
43567 if(!this.disable.font && !Roo.isSafari){
43569 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43570 if(name != this.fontSelect.dom.value){
43571 this.fontSelect.dom.value = name;
43575 if(!this.disable.format){
43576 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43577 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43578 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43580 if(!this.disable.alignments){
43581 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43582 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43583 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43585 if(!Roo.isSafari && !this.disable.lists){
43586 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43587 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43590 var ans = this.editorcore.getAllAncestors();
43591 if (this.formatCombo) {
43594 var store = this.formatCombo.store;
43595 this.formatCombo.setValue("");
43596 for (var i =0; i < ans.length;i++) {
43597 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43599 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43607 // hides menus... - so this cant be on a menu...
43608 Roo.menu.MenuMgr.hideAll();
43610 //this.editorsyncValue();
43614 createFontOptions : function(){
43615 var buf = [], fs = this.fontFamilies, ff, lc;
43619 for(var i = 0, len = fs.length; i< len; i++){
43621 lc = ff.toLowerCase();
43623 '<option value="',lc,'" style="font-family:',ff,';"',
43624 (this.defaultFont == lc ? ' selected="true">' : '>'),
43629 return buf.join('');
43632 toggleSourceEdit : function(sourceEditMode){
43634 Roo.log("toolbar toogle");
43635 if(sourceEditMode === undefined){
43636 sourceEditMode = !this.sourceEditMode;
43638 this.sourceEditMode = sourceEditMode === true;
43639 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43640 // just toggle the button?
43641 if(btn.pressed !== this.sourceEditMode){
43642 btn.toggle(this.sourceEditMode);
43646 if(sourceEditMode){
43647 Roo.log("disabling buttons");
43648 this.tb.items.each(function(item){
43649 if(item.cmd != 'sourceedit'){
43655 Roo.log("enabling buttons");
43656 if(this.editorcore.initialized){
43657 this.tb.items.each(function(item){
43663 Roo.log("calling toggole on editor");
43664 // tell the editor that it's been pressed..
43665 this.editor.toggleSourceEdit(sourceEditMode);
43669 * Object collection of toolbar tooltips for the buttons in the editor. The key
43670 * is the command id associated with that button and the value is a valid QuickTips object.
43675 title: 'Bold (Ctrl+B)',
43676 text: 'Make the selected text bold.',
43677 cls: 'x-html-editor-tip'
43680 title: 'Italic (Ctrl+I)',
43681 text: 'Make the selected text italic.',
43682 cls: 'x-html-editor-tip'
43690 title: 'Bold (Ctrl+B)',
43691 text: 'Make the selected text bold.',
43692 cls: 'x-html-editor-tip'
43695 title: 'Italic (Ctrl+I)',
43696 text: 'Make the selected text italic.',
43697 cls: 'x-html-editor-tip'
43700 title: 'Underline (Ctrl+U)',
43701 text: 'Underline the selected text.',
43702 cls: 'x-html-editor-tip'
43704 increasefontsize : {
43705 title: 'Grow Text',
43706 text: 'Increase the font size.',
43707 cls: 'x-html-editor-tip'
43709 decreasefontsize : {
43710 title: 'Shrink Text',
43711 text: 'Decrease the font size.',
43712 cls: 'x-html-editor-tip'
43715 title: 'Text Highlight Color',
43716 text: 'Change the background color of the selected text.',
43717 cls: 'x-html-editor-tip'
43720 title: 'Font Color',
43721 text: 'Change the color of the selected text.',
43722 cls: 'x-html-editor-tip'
43725 title: 'Align Text Left',
43726 text: 'Align text to the left.',
43727 cls: 'x-html-editor-tip'
43730 title: 'Center Text',
43731 text: 'Center text in the editor.',
43732 cls: 'x-html-editor-tip'
43735 title: 'Align Text Right',
43736 text: 'Align text to the right.',
43737 cls: 'x-html-editor-tip'
43739 insertunorderedlist : {
43740 title: 'Bullet List',
43741 text: 'Start a bulleted list.',
43742 cls: 'x-html-editor-tip'
43744 insertorderedlist : {
43745 title: 'Numbered List',
43746 text: 'Start a numbered list.',
43747 cls: 'x-html-editor-tip'
43750 title: 'Hyperlink',
43751 text: 'Make the selected text a hyperlink.',
43752 cls: 'x-html-editor-tip'
43755 title: 'Source Edit',
43756 text: 'Switch to source editing mode.',
43757 cls: 'x-html-editor-tip'
43761 onDestroy : function(){
43764 this.tb.items.each(function(item){
43766 item.menu.removeAll();
43768 item.menu.el.destroy();
43776 onFirstFocus: function() {
43777 this.tb.items.each(function(item){
43786 // <script type="text/javascript">
43789 * Ext JS Library 1.1.1
43790 * Copyright(c) 2006-2007, Ext JS, LLC.
43797 * @class Roo.form.HtmlEditor.ToolbarContext
43802 new Roo.form.HtmlEditor({
43805 { xtype: 'ToolbarStandard', styles : {} }
43806 { xtype: 'ToolbarContext', disable : {} }
43812 * @config : {Object} disable List of elements to disable.. (not done yet.)
43813 * @config : {Object} styles Map of styles available.
43817 Roo.form.HtmlEditor.ToolbarContext = function(config)
43820 Roo.apply(this, config);
43821 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43822 // dont call parent... till later.
43823 this.styles = this.styles || {};
43828 Roo.form.HtmlEditor.ToolbarContext.types = {
43840 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43906 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43911 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43921 style : 'fontFamily',
43922 displayField: 'display',
43923 optname : 'font-family',
43972 // should we really allow this??
43973 // should this just be
43984 style : 'fontFamily',
43985 displayField: 'display',
43986 optname : 'font-family',
43993 style : 'fontFamily',
43994 displayField: 'display',
43995 optname : 'font-family',
44002 style : 'fontFamily',
44003 displayField: 'display',
44004 optname : 'font-family',
44015 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44016 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44018 Roo.form.HtmlEditor.ToolbarContext.options = {
44020 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44021 [ 'Courier New', 'Courier New'],
44022 [ 'Tahoma', 'Tahoma'],
44023 [ 'Times New Roman,serif', 'Times'],
44024 [ 'Verdana','Verdana' ]
44028 // fixme - these need to be configurable..
44031 Roo.form.HtmlEditor.ToolbarContext.types
44034 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44041 editorcore : false,
44043 * @cfg {Object} disable List of toolbar elements to disable
44048 * @cfg {Object} styles List of styles
44049 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44051 * These must be defined in the page, so they get rendered correctly..
44062 init : function(editor)
44064 this.editor = editor;
44065 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44066 var editorcore = this.editorcore;
44068 var fid = editorcore.frameId;
44070 function btn(id, toggle, handler){
44071 var xid = fid + '-'+ id ;
44075 cls : 'x-btn-icon x-edit-'+id,
44076 enableToggle:toggle !== false,
44077 scope: editorcore, // was editor...
44078 handler:handler||editorcore.relayBtnCmd,
44079 clickEvent:'mousedown',
44080 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44084 // create a new element.
44085 var wdiv = editor.wrap.createChild({
44087 }, editor.wrap.dom.firstChild.nextSibling, true);
44089 // can we do this more than once??
44091 // stop form submits
44094 // disable everything...
44095 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44096 this.toolbars = {};
44098 for (var i in ty) {
44100 this.toolbars[i] = this.buildToolbar(ty[i],i);
44102 this.tb = this.toolbars.BODY;
44104 this.buildFooter();
44105 this.footer.show();
44106 editor.on('hide', function( ) { this.footer.hide() }, this);
44107 editor.on('show', function( ) { this.footer.show() }, this);
44110 this.rendered = true;
44112 // the all the btns;
44113 editor.on('editorevent', this.updateToolbar, this);
44114 // other toolbars need to implement this..
44115 //editor.on('editmodechange', this.updateToolbar, this);
44121 * Protected method that will not generally be called directly. It triggers
44122 * a toolbar update by reading the markup state of the current selection in the editor.
44124 updateToolbar: function(editor,ev,sel){
44127 // capture mouse up - this is handy for selecting images..
44128 // perhaps should go somewhere else...
44129 if(!this.editorcore.activated){
44130 this.editor.onFirstFocus();
44134 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44135 // selectNode - might want to handle IE?
44137 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44138 ev.target && ev.target.tagName == 'IMG') {
44139 // they have click on an image...
44140 // let's see if we can change the selection...
44143 var nodeRange = sel.ownerDocument.createRange();
44145 nodeRange.selectNode(sel);
44147 nodeRange.selectNodeContents(sel);
44149 //nodeRange.collapse(true);
44150 var s = this.editorcore.win.getSelection();
44151 s.removeAllRanges();
44152 s.addRange(nodeRange);
44156 var updateFooter = sel ? false : true;
44159 var ans = this.editorcore.getAllAncestors();
44162 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44165 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44166 sel = sel ? sel : this.editorcore.doc.body;
44167 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44170 // pick a menu that exists..
44171 var tn = sel.tagName.toUpperCase();
44172 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44174 tn = sel.tagName.toUpperCase();
44176 var lastSel = this.tb.selectedNode
44178 this.tb.selectedNode = sel;
44180 // if current menu does not match..
44181 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
44184 ///console.log("show: " + tn);
44185 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44188 this.tb.items.first().el.innerHTML = tn + ': ';
44191 // update attributes
44192 if (this.tb.fields) {
44193 this.tb.fields.each(function(e) {
44195 e.setValue(sel.style[e.stylename]);
44198 e.setValue(sel.getAttribute(e.attrname));
44202 var hasStyles = false;
44203 for(var i in this.styles) {
44210 var st = this.tb.fields.item(0);
44212 st.store.removeAll();
44215 var cn = sel.className.split(/\s+/);
44218 if (this.styles['*']) {
44220 Roo.each(this.styles['*'], function(v) {
44221 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44224 if (this.styles[tn]) {
44225 Roo.each(this.styles[tn], function(v) {
44226 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44230 st.store.loadData(avs);
44234 // flag our selected Node.
44235 this.tb.selectedNode = sel;
44238 Roo.menu.MenuMgr.hideAll();
44242 if (!updateFooter) {
44243 //this.footDisp.dom.innerHTML = '';
44246 // update the footer
44250 this.footerEls = ans.reverse();
44251 Roo.each(this.footerEls, function(a,i) {
44252 if (!a) { return; }
44253 html += html.length ? ' > ' : '';
44255 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44260 var sz = this.footDisp.up('td').getSize();
44261 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44262 this.footDisp.dom.style.marginLeft = '5px';
44264 this.footDisp.dom.style.overflow = 'hidden';
44266 this.footDisp.dom.innerHTML = html;
44268 //this.editorsyncValue();
44275 onDestroy : function(){
44278 this.tb.items.each(function(item){
44280 item.menu.removeAll();
44282 item.menu.el.destroy();
44290 onFirstFocus: function() {
44291 // need to do this for all the toolbars..
44292 this.tb.items.each(function(item){
44296 buildToolbar: function(tlist, nm)
44298 var editor = this.editor;
44299 var editorcore = this.editorcore;
44300 // create a new element.
44301 var wdiv = editor.wrap.createChild({
44303 }, editor.wrap.dom.firstChild.nextSibling, true);
44306 var tb = new Roo.Toolbar(wdiv);
44309 tb.add(nm+ ": ");
44312 for(var i in this.styles) {
44317 if (styles && styles.length) {
44319 // this needs a multi-select checkbox...
44320 tb.addField( new Roo.form.ComboBox({
44321 store: new Roo.data.SimpleStore({
44323 fields: ['val', 'selected'],
44326 name : '-roo-edit-className',
44327 attrname : 'className',
44328 displayField: 'val',
44332 triggerAction: 'all',
44333 emptyText:'Select Style',
44334 selectOnFocus:true,
44337 'select': function(c, r, i) {
44338 // initial support only for on class per el..
44339 tb.selectedNode.className = r ? r.get('val') : '';
44340 editorcore.syncValue();
44347 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44348 var tbops = tbc.options;
44350 for (var i in tlist) {
44352 var item = tlist[i];
44353 tb.add(item.title + ": ");
44356 //optname == used so you can configure the options available..
44357 var opts = item.opts ? item.opts : false;
44358 if (item.optname) {
44359 opts = tbops[item.optname];
44364 // opts == pulldown..
44365 tb.addField( new Roo.form.ComboBox({
44366 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44368 fields: ['val', 'display'],
44371 name : '-roo-edit-' + i,
44373 stylename : item.style ? item.style : false,
44374 displayField: item.displayField ? item.displayField : 'val',
44375 valueField : 'val',
44377 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44379 triggerAction: 'all',
44380 emptyText:'Select',
44381 selectOnFocus:true,
44382 width: item.width ? item.width : 130,
44384 'select': function(c, r, i) {
44386 tb.selectedNode.style[c.stylename] = r.get('val');
44389 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44398 tb.addField( new Roo.form.TextField({
44401 //allowBlank:false,
44406 tb.addField( new Roo.form.TextField({
44407 name: '-roo-edit-' + i,
44414 'change' : function(f, nv, ov) {
44415 tb.selectedNode.setAttribute(f.attrname, nv);
44424 text: 'Remove Tag',
44427 click : function ()
44430 // undo does not work.
44432 var sn = tb.selectedNode;
44434 var pn = sn.parentNode;
44436 var stn = sn.childNodes[0];
44437 var en = sn.childNodes[sn.childNodes.length - 1 ];
44438 while (sn.childNodes.length) {
44439 var node = sn.childNodes[0];
44440 sn.removeChild(node);
44442 pn.insertBefore(node, sn);
44445 pn.removeChild(sn);
44446 var range = editorcore.createRange();
44448 range.setStart(stn,0);
44449 range.setEnd(en,0); //????
44450 //range.selectNode(sel);
44453 var selection = editorcore.getSelection();
44454 selection.removeAllRanges();
44455 selection.addRange(range);
44459 //_this.updateToolbar(null, null, pn);
44460 _this.updateToolbar(null, null, null);
44461 _this.footDisp.dom.innerHTML = '';
44471 tb.el.on('click', function(e){
44472 e.preventDefault(); // what does this do?
44474 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44477 // dont need to disable them... as they will get hidden
44482 buildFooter : function()
44485 var fel = this.editor.wrap.createChild();
44486 this.footer = new Roo.Toolbar(fel);
44487 // toolbar has scrolly on left / right?
44488 var footDisp= new Roo.Toolbar.Fill();
44494 handler : function() {
44495 _t.footDisp.scrollTo('left',0,true)
44499 this.footer.add( footDisp );
44504 handler : function() {
44506 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44510 var fel = Roo.get(footDisp.el);
44511 fel.addClass('x-editor-context');
44512 this.footDispWrap = fel;
44513 this.footDispWrap.overflow = 'hidden';
44515 this.footDisp = fel.createChild();
44516 this.footDispWrap.on('click', this.onContextClick, this)
44520 onContextClick : function (ev,dom)
44522 ev.preventDefault();
44523 var cn = dom.className;
44525 if (!cn.match(/x-ed-loc-/)) {
44528 var n = cn.split('-').pop();
44529 var ans = this.footerEls;
44533 var range = this.editorcore.createRange();
44535 range.selectNodeContents(sel);
44536 //range.selectNode(sel);
44539 var selection = this.editorcore.getSelection();
44540 selection.removeAllRanges();
44541 selection.addRange(range);
44545 this.updateToolbar(null, null, sel);
44562 * Ext JS Library 1.1.1
44563 * Copyright(c) 2006-2007, Ext JS, LLC.
44565 * Originally Released Under LGPL - original licence link has changed is not relivant.
44568 * <script type="text/javascript">
44572 * @class Roo.form.BasicForm
44573 * @extends Roo.util.Observable
44574 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44576 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44577 * @param {Object} config Configuration options
44579 Roo.form.BasicForm = function(el, config){
44580 this.allItems = [];
44581 this.childForms = [];
44582 Roo.apply(this, config);
44584 * The Roo.form.Field items in this form.
44585 * @type MixedCollection
44589 this.items = new Roo.util.MixedCollection(false, function(o){
44590 return o.id || (o.id = Roo.id());
44594 * @event beforeaction
44595 * Fires before any action is performed. Return false to cancel the action.
44596 * @param {Form} this
44597 * @param {Action} action The action to be performed
44599 beforeaction: true,
44601 * @event actionfailed
44602 * Fires when an action fails.
44603 * @param {Form} this
44604 * @param {Action} action The action that failed
44606 actionfailed : true,
44608 * @event actioncomplete
44609 * Fires when an action is completed.
44610 * @param {Form} this
44611 * @param {Action} action The action that completed
44613 actioncomplete : true
44618 Roo.form.BasicForm.superclass.constructor.call(this);
44621 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44623 * @cfg {String} method
44624 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44627 * @cfg {DataReader} reader
44628 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44629 * This is optional as there is built-in support for processing JSON.
44632 * @cfg {DataReader} errorReader
44633 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44634 * This is completely optional as there is built-in support for processing JSON.
44637 * @cfg {String} url
44638 * The URL to use for form actions if one isn't supplied in the action options.
44641 * @cfg {Boolean} fileUpload
44642 * Set to true if this form is a file upload.
44646 * @cfg {Object} baseParams
44647 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44652 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44657 activeAction : null,
44660 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44661 * or setValues() data instead of when the form was first created.
44663 trackResetOnLoad : false,
44667 * childForms - used for multi-tab forms
44670 childForms : false,
44673 * allItems - full list of fields.
44679 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44680 * element by passing it or its id or mask the form itself by passing in true.
44683 waitMsgTarget : false,
44686 initEl : function(el){
44687 this.el = Roo.get(el);
44688 this.id = this.el.id || Roo.id();
44689 this.el.on('submit', this.onSubmit, this);
44690 this.el.addClass('x-form');
44694 onSubmit : function(e){
44699 * Returns true if client-side validation on the form is successful.
44702 isValid : function(){
44704 this.items.each(function(f){
44713 * Returns true if any fields in this form have changed since their original load.
44716 isDirty : function(){
44718 this.items.each(function(f){
44728 * Performs a predefined action (submit or load) or custom actions you define on this form.
44729 * @param {String} actionName The name of the action type
44730 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44731 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44732 * accept other config options):
44734 Property Type Description
44735 ---------------- --------------- ----------------------------------------------------------------------------------
44736 url String The url for the action (defaults to the form's url)
44737 method String The form method to use (defaults to the form's method, or POST if not defined)
44738 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44739 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44740 validate the form on the client (defaults to false)
44742 * @return {BasicForm} this
44744 doAction : function(action, options){
44745 if(typeof action == 'string'){
44746 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44748 if(this.fireEvent('beforeaction', this, action) !== false){
44749 this.beforeAction(action);
44750 action.run.defer(100, action);
44756 * Shortcut to do a submit action.
44757 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44758 * @return {BasicForm} this
44760 submit : function(options){
44761 this.doAction('submit', options);
44766 * Shortcut to do a load action.
44767 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44768 * @return {BasicForm} this
44770 load : function(options){
44771 this.doAction('load', options);
44776 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44777 * @param {Record} record The record to edit
44778 * @return {BasicForm} this
44780 updateRecord : function(record){
44781 record.beginEdit();
44782 var fs = record.fields;
44783 fs.each(function(f){
44784 var field = this.findField(f.name);
44786 record.set(f.name, field.getValue());
44794 * Loads an Roo.data.Record into this form.
44795 * @param {Record} record The record to load
44796 * @return {BasicForm} this
44798 loadRecord : function(record){
44799 this.setValues(record.data);
44804 beforeAction : function(action){
44805 var o = action.options;
44808 if(this.waitMsgTarget === true){
44809 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44810 }else if(this.waitMsgTarget){
44811 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44812 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44814 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44820 afterAction : function(action, success){
44821 this.activeAction = null;
44822 var o = action.options;
44824 if(this.waitMsgTarget === true){
44826 }else if(this.waitMsgTarget){
44827 this.waitMsgTarget.unmask();
44829 Roo.MessageBox.updateProgress(1);
44830 Roo.MessageBox.hide();
44837 Roo.callback(o.success, o.scope, [this, action]);
44838 this.fireEvent('actioncomplete', this, action);
44842 // failure condition..
44843 // we have a scenario where updates need confirming.
44844 // eg. if a locking scenario exists..
44845 // we look for { errors : { needs_confirm : true }} in the response.
44847 (typeof(action.result) != 'undefined') &&
44848 (typeof(action.result.errors) != 'undefined') &&
44849 (typeof(action.result.errors.needs_confirm) != 'undefined')
44852 Roo.MessageBox.confirm(
44853 "Change requires confirmation",
44854 action.result.errorMsg,
44859 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44869 Roo.callback(o.failure, o.scope, [this, action]);
44870 // show an error message if no failed handler is set..
44871 if (!this.hasListener('actionfailed')) {
44872 Roo.MessageBox.alert("Error",
44873 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44874 action.result.errorMsg :
44875 "Saving Failed, please check your entries or try again"
44879 this.fireEvent('actionfailed', this, action);
44885 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44886 * @param {String} id The value to search for
44889 findField : function(id){
44890 var field = this.items.get(id);
44892 this.items.each(function(f){
44893 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44899 return field || null;
44903 * Add a secondary form to this one,
44904 * Used to provide tabbed forms. One form is primary, with hidden values
44905 * which mirror the elements from the other forms.
44907 * @param {Roo.form.Form} form to add.
44910 addForm : function(form)
44913 if (this.childForms.indexOf(form) > -1) {
44917 this.childForms.push(form);
44919 Roo.each(form.allItems, function (fe) {
44921 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44922 if (this.findField(n)) { // already added..
44925 var add = new Roo.form.Hidden({
44928 add.render(this.el);
44935 * Mark fields in this form invalid in bulk.
44936 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44937 * @return {BasicForm} this
44939 markInvalid : function(errors){
44940 if(errors instanceof Array){
44941 for(var i = 0, len = errors.length; i < len; i++){
44942 var fieldError = errors[i];
44943 var f = this.findField(fieldError.id);
44945 f.markInvalid(fieldError.msg);
44951 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44952 field.markInvalid(errors[id]);
44956 Roo.each(this.childForms || [], function (f) {
44957 f.markInvalid(errors);
44964 * Set values for fields in this form in bulk.
44965 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44966 * @return {BasicForm} this
44968 setValues : function(values){
44969 if(values instanceof Array){ // array of objects
44970 for(var i = 0, len = values.length; i < len; i++){
44972 var f = this.findField(v.id);
44974 f.setValue(v.value);
44975 if(this.trackResetOnLoad){
44976 f.originalValue = f.getValue();
44980 }else{ // object hash
44983 if(typeof values[id] != 'function' && (field = this.findField(id))){
44985 if (field.setFromData &&
44986 field.valueField &&
44987 field.displayField &&
44988 // combos' with local stores can
44989 // be queried via setValue()
44990 // to set their value..
44991 (field.store && !field.store.isLocal)
44995 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44996 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44997 field.setFromData(sd);
45000 field.setValue(values[id]);
45004 if(this.trackResetOnLoad){
45005 field.originalValue = field.getValue();
45011 Roo.each(this.childForms || [], function (f) {
45012 f.setValues(values);
45019 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45020 * they are returned as an array.
45021 * @param {Boolean} asString
45024 getValues : function(asString){
45025 if (this.childForms) {
45026 // copy values from the child forms
45027 Roo.each(this.childForms, function (f) {
45028 this.setValues(f.getValues());
45034 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45035 if(asString === true){
45038 return Roo.urlDecode(fs);
45042 * Returns the fields in this form as an object with key/value pairs.
45043 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45046 getFieldValues : function(with_hidden)
45048 if (this.childForms) {
45049 // copy values from the child forms
45050 // should this call getFieldValues - probably not as we do not currently copy
45051 // hidden fields when we generate..
45052 Roo.each(this.childForms, function (f) {
45053 this.setValues(f.getValues());
45058 this.items.each(function(f){
45059 if (!f.getName()) {
45062 var v = f.getValue();
45063 if (f.inputType =='radio') {
45064 if (typeof(ret[f.getName()]) == 'undefined') {
45065 ret[f.getName()] = ''; // empty..
45068 if (!f.el.dom.checked) {
45072 v = f.el.dom.value;
45076 // not sure if this supported any more..
45077 if ((typeof(v) == 'object') && f.getRawValue) {
45078 v = f.getRawValue() ; // dates..
45080 // combo boxes where name != hiddenName...
45081 if (f.name != f.getName()) {
45082 ret[f.name] = f.getRawValue();
45084 ret[f.getName()] = v;
45091 * Clears all invalid messages in this form.
45092 * @return {BasicForm} this
45094 clearInvalid : function(){
45095 this.items.each(function(f){
45099 Roo.each(this.childForms || [], function (f) {
45108 * Resets this form.
45109 * @return {BasicForm} this
45111 reset : function(){
45112 this.items.each(function(f){
45116 Roo.each(this.childForms || [], function (f) {
45125 * Add Roo.form components to this form.
45126 * @param {Field} field1
45127 * @param {Field} field2 (optional)
45128 * @param {Field} etc (optional)
45129 * @return {BasicForm} this
45132 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45138 * Removes a field from the items collection (does NOT remove its markup).
45139 * @param {Field} field
45140 * @return {BasicForm} this
45142 remove : function(field){
45143 this.items.remove(field);
45148 * Looks at the fields in this form, checks them for an id attribute,
45149 * and calls applyTo on the existing dom element with that id.
45150 * @return {BasicForm} this
45152 render : function(){
45153 this.items.each(function(f){
45154 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45162 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45163 * @param {Object} values
45164 * @return {BasicForm} this
45166 applyToFields : function(o){
45167 this.items.each(function(f){
45174 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45175 * @param {Object} values
45176 * @return {BasicForm} this
45178 applyIfToFields : function(o){
45179 this.items.each(function(f){
45187 Roo.BasicForm = Roo.form.BasicForm;/*
45189 * Ext JS Library 1.1.1
45190 * Copyright(c) 2006-2007, Ext JS, LLC.
45192 * Originally Released Under LGPL - original licence link has changed is not relivant.
45195 * <script type="text/javascript">
45199 * @class Roo.form.Form
45200 * @extends Roo.form.BasicForm
45201 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45203 * @param {Object} config Configuration options
45205 Roo.form.Form = function(config){
45207 if (config.items) {
45208 xitems = config.items;
45209 delete config.items;
45213 Roo.form.Form.superclass.constructor.call(this, null, config);
45214 this.url = this.url || this.action;
45216 this.root = new Roo.form.Layout(Roo.applyIf({
45220 this.active = this.root;
45222 * Array of all the buttons that have been added to this form via {@link addButton}
45226 this.allItems = [];
45229 * @event clientvalidation
45230 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45231 * @param {Form} this
45232 * @param {Boolean} valid true if the form has passed client-side validation
45234 clientvalidation: true,
45237 * Fires when the form is rendered
45238 * @param {Roo.form.Form} form
45243 if (this.progressUrl) {
45244 // push a hidden field onto the list of fields..
45248 name : 'UPLOAD_IDENTIFIER'
45253 Roo.each(xitems, this.addxtype, this);
45259 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45261 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45264 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45267 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45269 buttonAlign:'center',
45272 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45277 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45278 * This property cascades to child containers if not set.
45283 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45284 * fires a looping event with that state. This is required to bind buttons to the valid
45285 * state using the config value formBind:true on the button.
45287 monitorValid : false,
45290 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45295 * @cfg {String} progressUrl - Url to return progress data
45298 progressUrl : false,
45301 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45302 * fields are added and the column is closed. If no fields are passed the column remains open
45303 * until end() is called.
45304 * @param {Object} config The config to pass to the column
45305 * @param {Field} field1 (optional)
45306 * @param {Field} field2 (optional)
45307 * @param {Field} etc (optional)
45308 * @return Column The column container object
45310 column : function(c){
45311 var col = new Roo.form.Column(c);
45313 if(arguments.length > 1){ // duplicate code required because of Opera
45314 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45321 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45322 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45323 * until end() is called.
45324 * @param {Object} config The config to pass to the fieldset
45325 * @param {Field} field1 (optional)
45326 * @param {Field} field2 (optional)
45327 * @param {Field} etc (optional)
45328 * @return FieldSet The fieldset container object
45330 fieldset : function(c){
45331 var fs = new Roo.form.FieldSet(c);
45333 if(arguments.length > 1){ // duplicate code required because of Opera
45334 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45341 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45342 * fields are added and the container is closed. If no fields are passed the container remains open
45343 * until end() is called.
45344 * @param {Object} config The config to pass to the Layout
45345 * @param {Field} field1 (optional)
45346 * @param {Field} field2 (optional)
45347 * @param {Field} etc (optional)
45348 * @return Layout The container object
45350 container : function(c){
45351 var l = new Roo.form.Layout(c);
45353 if(arguments.length > 1){ // duplicate code required because of Opera
45354 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45361 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45362 * @param {Object} container A Roo.form.Layout or subclass of Layout
45363 * @return {Form} this
45365 start : function(c){
45366 // cascade label info
45367 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45368 this.active.stack.push(c);
45369 c.ownerCt = this.active;
45375 * Closes the current open container
45376 * @return {Form} this
45379 if(this.active == this.root){
45382 this.active = this.active.ownerCt;
45387 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45388 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45389 * as the label of the field.
45390 * @param {Field} field1
45391 * @param {Field} field2 (optional)
45392 * @param {Field} etc. (optional)
45393 * @return {Form} this
45396 this.active.stack.push.apply(this.active.stack, arguments);
45397 this.allItems.push.apply(this.allItems,arguments);
45399 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45400 if(a[i].isFormField){
45405 Roo.form.Form.superclass.add.apply(this, r);
45415 * Find any element that has been added to a form, using it's ID or name
45416 * This can include framesets, columns etc. along with regular fields..
45417 * @param {String} id - id or name to find.
45419 * @return {Element} e - or false if nothing found.
45421 findbyId : function(id)
45427 Roo.each(this.allItems, function(f){
45428 if (f.id == id || f.name == id ){
45439 * Render this form into the passed container. This should only be called once!
45440 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45441 * @return {Form} this
45443 render : function(ct)
45449 var o = this.autoCreate || {
45451 method : this.method || 'POST',
45452 id : this.id || Roo.id()
45454 this.initEl(ct.createChild(o));
45456 this.root.render(this.el);
45460 this.items.each(function(f){
45461 f.render('x-form-el-'+f.id);
45464 if(this.buttons.length > 0){
45465 // tables are required to maintain order and for correct IE layout
45466 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45467 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45468 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45470 var tr = tb.getElementsByTagName('tr')[0];
45471 for(var i = 0, len = this.buttons.length; i < len; i++) {
45472 var b = this.buttons[i];
45473 var td = document.createElement('td');
45474 td.className = 'x-form-btn-td';
45475 b.render(tr.appendChild(td));
45478 if(this.monitorValid){ // initialize after render
45479 this.startMonitoring();
45481 this.fireEvent('rendered', this);
45486 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45487 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45488 * object or a valid Roo.DomHelper element config
45489 * @param {Function} handler The function called when the button is clicked
45490 * @param {Object} scope (optional) The scope of the handler function
45491 * @return {Roo.Button}
45493 addButton : function(config, handler, scope){
45497 minWidth: this.minButtonWidth,
45500 if(typeof config == "string"){
45503 Roo.apply(bc, config);
45505 var btn = new Roo.Button(null, bc);
45506 this.buttons.push(btn);
45511 * Adds a series of form elements (using the xtype property as the factory method.
45512 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45513 * @param {Object} config
45516 addxtype : function()
45518 var ar = Array.prototype.slice.call(arguments, 0);
45520 for(var i = 0; i < ar.length; i++) {
45522 continue; // skip -- if this happends something invalid got sent, we
45523 // should ignore it, as basically that interface element will not show up
45524 // and that should be pretty obvious!!
45527 if (Roo.form[ar[i].xtype]) {
45529 var fe = Roo.factory(ar[i], Roo.form);
45535 fe.store.form = this;
45540 this.allItems.push(fe);
45541 if (fe.items && fe.addxtype) {
45542 fe.addxtype.apply(fe, fe.items);
45552 // console.log('adding ' + ar[i].xtype);
45554 if (ar[i].xtype == 'Button') {
45555 //console.log('adding button');
45556 //console.log(ar[i]);
45557 this.addButton(ar[i]);
45558 this.allItems.push(fe);
45562 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45563 alert('end is not supported on xtype any more, use items');
45565 // //console.log('adding end');
45573 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45574 * option "monitorValid"
45576 startMonitoring : function(){
45579 Roo.TaskMgr.start({
45580 run : this.bindHandler,
45581 interval : this.monitorPoll || 200,
45588 * Stops monitoring of the valid state of this form
45590 stopMonitoring : function(){
45591 this.bound = false;
45595 bindHandler : function(){
45597 return false; // stops binding
45600 this.items.each(function(f){
45601 if(!f.isValid(true)){
45606 for(var i = 0, len = this.buttons.length; i < len; i++){
45607 var btn = this.buttons[i];
45608 if(btn.formBind === true && btn.disabled === valid){
45609 btn.setDisabled(!valid);
45612 this.fireEvent('clientvalidation', this, valid);
45626 Roo.Form = Roo.form.Form;
45629 * Ext JS Library 1.1.1
45630 * Copyright(c) 2006-2007, Ext JS, LLC.
45632 * Originally Released Under LGPL - original licence link has changed is not relivant.
45635 * <script type="text/javascript">
45638 // as we use this in bootstrap.
45639 Roo.namespace('Roo.form');
45641 * @class Roo.form.Action
45642 * Internal Class used to handle form actions
45644 * @param {Roo.form.BasicForm} el The form element or its id
45645 * @param {Object} config Configuration options
45650 // define the action interface
45651 Roo.form.Action = function(form, options){
45653 this.options = options || {};
45656 * Client Validation Failed
45659 Roo.form.Action.CLIENT_INVALID = 'client';
45661 * Server Validation Failed
45664 Roo.form.Action.SERVER_INVALID = 'server';
45666 * Connect to Server Failed
45669 Roo.form.Action.CONNECT_FAILURE = 'connect';
45671 * Reading Data from Server Failed
45674 Roo.form.Action.LOAD_FAILURE = 'load';
45676 Roo.form.Action.prototype = {
45678 failureType : undefined,
45679 response : undefined,
45680 result : undefined,
45682 // interface method
45683 run : function(options){
45687 // interface method
45688 success : function(response){
45692 // interface method
45693 handleResponse : function(response){
45697 // default connection failure
45698 failure : function(response){
45700 this.response = response;
45701 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45702 this.form.afterAction(this, false);
45705 processResponse : function(response){
45706 this.response = response;
45707 if(!response.responseText){
45710 this.result = this.handleResponse(response);
45711 return this.result;
45714 // utility functions used internally
45715 getUrl : function(appendParams){
45716 var url = this.options.url || this.form.url || this.form.el.dom.action;
45718 var p = this.getParams();
45720 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45726 getMethod : function(){
45727 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45730 getParams : function(){
45731 var bp = this.form.baseParams;
45732 var p = this.options.params;
45734 if(typeof p == "object"){
45735 p = Roo.urlEncode(Roo.applyIf(p, bp));
45736 }else if(typeof p == 'string' && bp){
45737 p += '&' + Roo.urlEncode(bp);
45740 p = Roo.urlEncode(bp);
45745 createCallback : function(){
45747 success: this.success,
45748 failure: this.failure,
45750 timeout: (this.form.timeout*1000),
45751 upload: this.form.fileUpload ? this.success : undefined
45756 Roo.form.Action.Submit = function(form, options){
45757 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45760 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45763 haveProgress : false,
45764 uploadComplete : false,
45766 // uploadProgress indicator.
45767 uploadProgress : function()
45769 if (!this.form.progressUrl) {
45773 if (!this.haveProgress) {
45774 Roo.MessageBox.progress("Uploading", "Uploading");
45776 if (this.uploadComplete) {
45777 Roo.MessageBox.hide();
45781 this.haveProgress = true;
45783 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45785 var c = new Roo.data.Connection();
45787 url : this.form.progressUrl,
45792 success : function(req){
45793 //console.log(data);
45797 rdata = Roo.decode(req.responseText)
45799 Roo.log("Invalid data from server..");
45803 if (!rdata || !rdata.success) {
45805 Roo.MessageBox.alert(Roo.encode(rdata));
45808 var data = rdata.data;
45810 if (this.uploadComplete) {
45811 Roo.MessageBox.hide();
45816 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45817 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45820 this.uploadProgress.defer(2000,this);
45823 failure: function(data) {
45824 Roo.log('progress url failed ');
45835 // run get Values on the form, so it syncs any secondary forms.
45836 this.form.getValues();
45838 var o = this.options;
45839 var method = this.getMethod();
45840 var isPost = method == 'POST';
45841 if(o.clientValidation === false || this.form.isValid()){
45843 if (this.form.progressUrl) {
45844 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45845 (new Date() * 1) + '' + Math.random());
45850 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45851 form:this.form.el.dom,
45852 url:this.getUrl(!isPost),
45854 params:isPost ? this.getParams() : null,
45855 isUpload: this.form.fileUpload
45858 this.uploadProgress();
45860 }else if (o.clientValidation !== false){ // client validation failed
45861 this.failureType = Roo.form.Action.CLIENT_INVALID;
45862 this.form.afterAction(this, false);
45866 success : function(response)
45868 this.uploadComplete= true;
45869 if (this.haveProgress) {
45870 Roo.MessageBox.hide();
45874 var result = this.processResponse(response);
45875 if(result === true || result.success){
45876 this.form.afterAction(this, true);
45880 this.form.markInvalid(result.errors);
45881 this.failureType = Roo.form.Action.SERVER_INVALID;
45883 this.form.afterAction(this, false);
45885 failure : function(response)
45887 this.uploadComplete= true;
45888 if (this.haveProgress) {
45889 Roo.MessageBox.hide();
45892 this.response = response;
45893 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45894 this.form.afterAction(this, false);
45897 handleResponse : function(response){
45898 if(this.form.errorReader){
45899 var rs = this.form.errorReader.read(response);
45902 for(var i = 0, len = rs.records.length; i < len; i++) {
45903 var r = rs.records[i];
45904 errors[i] = r.data;
45907 if(errors.length < 1){
45911 success : rs.success,
45917 ret = Roo.decode(response.responseText);
45921 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45931 Roo.form.Action.Load = function(form, options){
45932 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45933 this.reader = this.form.reader;
45936 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45941 Roo.Ajax.request(Roo.apply(
45942 this.createCallback(), {
45943 method:this.getMethod(),
45944 url:this.getUrl(false),
45945 params:this.getParams()
45949 success : function(response){
45951 var result = this.processResponse(response);
45952 if(result === true || !result.success || !result.data){
45953 this.failureType = Roo.form.Action.LOAD_FAILURE;
45954 this.form.afterAction(this, false);
45957 this.form.clearInvalid();
45958 this.form.setValues(result.data);
45959 this.form.afterAction(this, true);
45962 handleResponse : function(response){
45963 if(this.form.reader){
45964 var rs = this.form.reader.read(response);
45965 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45967 success : rs.success,
45971 return Roo.decode(response.responseText);
45975 Roo.form.Action.ACTION_TYPES = {
45976 'load' : Roo.form.Action.Load,
45977 'submit' : Roo.form.Action.Submit
45980 * Ext JS Library 1.1.1
45981 * Copyright(c) 2006-2007, Ext JS, LLC.
45983 * Originally Released Under LGPL - original licence link has changed is not relivant.
45986 * <script type="text/javascript">
45990 * @class Roo.form.Layout
45991 * @extends Roo.Component
45992 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45994 * @param {Object} config Configuration options
45996 Roo.form.Layout = function(config){
45998 if (config.items) {
45999 xitems = config.items;
46000 delete config.items;
46002 Roo.form.Layout.superclass.constructor.call(this, config);
46004 Roo.each(xitems, this.addxtype, this);
46008 Roo.extend(Roo.form.Layout, Roo.Component, {
46010 * @cfg {String/Object} autoCreate
46011 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46014 * @cfg {String/Object/Function} style
46015 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46016 * a function which returns such a specification.
46019 * @cfg {String} labelAlign
46020 * Valid values are "left," "top" and "right" (defaults to "left")
46023 * @cfg {Number} labelWidth
46024 * Fixed width in pixels of all field labels (defaults to undefined)
46027 * @cfg {Boolean} clear
46028 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46032 * @cfg {String} labelSeparator
46033 * The separator to use after field labels (defaults to ':')
46035 labelSeparator : ':',
46037 * @cfg {Boolean} hideLabels
46038 * True to suppress the display of field labels in this layout (defaults to false)
46040 hideLabels : false,
46043 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46048 onRender : function(ct, position){
46049 if(this.el){ // from markup
46050 this.el = Roo.get(this.el);
46051 }else { // generate
46052 var cfg = this.getAutoCreate();
46053 this.el = ct.createChild(cfg, position);
46056 this.el.applyStyles(this.style);
46058 if(this.labelAlign){
46059 this.el.addClass('x-form-label-'+this.labelAlign);
46061 if(this.hideLabels){
46062 this.labelStyle = "display:none";
46063 this.elementStyle = "padding-left:0;";
46065 if(typeof this.labelWidth == 'number'){
46066 this.labelStyle = "width:"+this.labelWidth+"px;";
46067 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46069 if(this.labelAlign == 'top'){
46070 this.labelStyle = "width:auto;";
46071 this.elementStyle = "padding-left:0;";
46074 var stack = this.stack;
46075 var slen = stack.length;
46077 if(!this.fieldTpl){
46078 var t = new Roo.Template(
46079 '<div class="x-form-item {5}">',
46080 '<label for="{0}" style="{2}">{1}{4}</label>',
46081 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46083 '</div><div class="x-form-clear-left"></div>'
46085 t.disableFormats = true;
46087 Roo.form.Layout.prototype.fieldTpl = t;
46089 for(var i = 0; i < slen; i++) {
46090 if(stack[i].isFormField){
46091 this.renderField(stack[i]);
46093 this.renderComponent(stack[i]);
46098 this.el.createChild({cls:'x-form-clear'});
46103 renderField : function(f){
46104 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46107 f.labelStyle||this.labelStyle||'', //2
46108 this.elementStyle||'', //3
46109 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46110 f.itemCls||this.itemCls||'' //5
46111 ], true).getPrevSibling());
46115 renderComponent : function(c){
46116 c.render(c.isLayout ? this.el : this.el.createChild());
46119 * Adds a object form elements (using the xtype property as the factory method.)
46120 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46121 * @param {Object} config
46123 addxtype : function(o)
46125 // create the lement.
46126 o.form = this.form;
46127 var fe = Roo.factory(o, Roo.form);
46128 this.form.allItems.push(fe);
46129 this.stack.push(fe);
46131 if (fe.isFormField) {
46132 this.form.items.add(fe);
46140 * @class Roo.form.Column
46141 * @extends Roo.form.Layout
46142 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46144 * @param {Object} config Configuration options
46146 Roo.form.Column = function(config){
46147 Roo.form.Column.superclass.constructor.call(this, config);
46150 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46152 * @cfg {Number/String} width
46153 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46156 * @cfg {String/Object} autoCreate
46157 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46161 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46164 onRender : function(ct, position){
46165 Roo.form.Column.superclass.onRender.call(this, ct, position);
46167 this.el.setWidth(this.width);
46174 * @class Roo.form.Row
46175 * @extends Roo.form.Layout
46176 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46178 * @param {Object} config Configuration options
46182 Roo.form.Row = function(config){
46183 Roo.form.Row.superclass.constructor.call(this, config);
46186 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46188 * @cfg {Number/String} width
46189 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46192 * @cfg {Number/String} height
46193 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46195 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46199 onRender : function(ct, position){
46200 //console.log('row render');
46202 var t = new Roo.Template(
46203 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46204 '<label for="{0}" style="{2}">{1}{4}</label>',
46205 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46209 t.disableFormats = true;
46211 Roo.form.Layout.prototype.rowTpl = t;
46213 this.fieldTpl = this.rowTpl;
46215 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46216 var labelWidth = 100;
46218 if ((this.labelAlign != 'top')) {
46219 if (typeof this.labelWidth == 'number') {
46220 labelWidth = this.labelWidth
46222 this.padWidth = 20 + labelWidth;
46226 Roo.form.Column.superclass.onRender.call(this, ct, position);
46228 this.el.setWidth(this.width);
46231 this.el.setHeight(this.height);
46236 renderField : function(f){
46237 f.fieldEl = this.fieldTpl.append(this.el, [
46238 f.id, f.fieldLabel,
46239 f.labelStyle||this.labelStyle||'',
46240 this.elementStyle||'',
46241 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46242 f.itemCls||this.itemCls||'',
46243 f.width ? f.width + this.padWidth : 160 + this.padWidth
46250 * @class Roo.form.FieldSet
46251 * @extends Roo.form.Layout
46252 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46254 * @param {Object} config Configuration options
46256 Roo.form.FieldSet = function(config){
46257 Roo.form.FieldSet.superclass.constructor.call(this, config);
46260 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46262 * @cfg {String} legend
46263 * The text to display as the legend for the FieldSet (defaults to '')
46266 * @cfg {String/Object} autoCreate
46267 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46271 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46274 onRender : function(ct, position){
46275 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46277 this.setLegend(this.legend);
46282 setLegend : function(text){
46284 this.el.child('legend').update(text);
46289 * Ext JS Library 1.1.1
46290 * Copyright(c) 2006-2007, Ext JS, LLC.
46292 * Originally Released Under LGPL - original licence link has changed is not relivant.
46295 * <script type="text/javascript">
46298 * @class Roo.form.VTypes
46299 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46302 Roo.form.VTypes = function(){
46303 // closure these in so they are only created once.
46304 var alpha = /^[a-zA-Z_]+$/;
46305 var alphanum = /^[a-zA-Z0-9_]+$/;
46306 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46307 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46309 // All these messages and functions are configurable
46312 * The function used to validate email addresses
46313 * @param {String} value The email address
46315 'email' : function(v){
46316 return email.test(v);
46319 * The error text to display when the email validation function returns false
46322 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46324 * The keystroke filter mask to be applied on email input
46327 'emailMask' : /[a-z0-9_\.\-@]/i,
46330 * The function used to validate URLs
46331 * @param {String} value The URL
46333 'url' : function(v){
46334 return url.test(v);
46337 * The error text to display when the url validation function returns false
46340 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46343 * The function used to validate alpha values
46344 * @param {String} value The value
46346 'alpha' : function(v){
46347 return alpha.test(v);
46350 * The error text to display when the alpha validation function returns false
46353 'alphaText' : 'This field should only contain letters and _',
46355 * The keystroke filter mask to be applied on alpha input
46358 'alphaMask' : /[a-z_]/i,
46361 * The function used to validate alphanumeric values
46362 * @param {String} value The value
46364 'alphanum' : function(v){
46365 return alphanum.test(v);
46368 * The error text to display when the alphanumeric validation function returns false
46371 'alphanumText' : 'This field should only contain letters, numbers and _',
46373 * The keystroke filter mask to be applied on alphanumeric input
46376 'alphanumMask' : /[a-z0-9_]/i
46378 }();//<script type="text/javascript">
46381 * @class Roo.form.FCKeditor
46382 * @extends Roo.form.TextArea
46383 * Wrapper around the FCKEditor http://www.fckeditor.net
46385 * Creates a new FCKeditor
46386 * @param {Object} config Configuration options
46388 Roo.form.FCKeditor = function(config){
46389 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46392 * @event editorinit
46393 * Fired when the editor is initialized - you can add extra handlers here..
46394 * @param {FCKeditor} this
46395 * @param {Object} the FCK object.
46402 Roo.form.FCKeditor.editors = { };
46403 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46405 //defaultAutoCreate : {
46406 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46410 * @cfg {Object} fck options - see fck manual for details.
46415 * @cfg {Object} fck toolbar set (Basic or Default)
46417 toolbarSet : 'Basic',
46419 * @cfg {Object} fck BasePath
46421 basePath : '/fckeditor/',
46429 onRender : function(ct, position)
46432 this.defaultAutoCreate = {
46434 style:"width:300px;height:60px;",
46435 autocomplete: "off"
46438 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46441 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46442 if(this.preventScrollbars){
46443 this.el.setStyle("overflow", "hidden");
46445 this.el.setHeight(this.growMin);
46448 //console.log('onrender' + this.getId() );
46449 Roo.form.FCKeditor.editors[this.getId()] = this;
46452 this.replaceTextarea() ;
46456 getEditor : function() {
46457 return this.fckEditor;
46460 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46461 * @param {Mixed} value The value to set
46465 setValue : function(value)
46467 //console.log('setValue: ' + value);
46469 if(typeof(value) == 'undefined') { // not sure why this is happending...
46472 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46474 //if(!this.el || !this.getEditor()) {
46475 // this.value = value;
46476 //this.setValue.defer(100,this,[value]);
46480 if(!this.getEditor()) {
46484 this.getEditor().SetData(value);
46491 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46492 * @return {Mixed} value The field value
46494 getValue : function()
46497 if (this.frame && this.frame.dom.style.display == 'none') {
46498 return Roo.form.FCKeditor.superclass.getValue.call(this);
46501 if(!this.el || !this.getEditor()) {
46503 // this.getValue.defer(100,this);
46508 var value=this.getEditor().GetData();
46509 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46510 return Roo.form.FCKeditor.superclass.getValue.call(this);
46516 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46517 * @return {Mixed} value The field value
46519 getRawValue : function()
46521 if (this.frame && this.frame.dom.style.display == 'none') {
46522 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46525 if(!this.el || !this.getEditor()) {
46526 //this.getRawValue.defer(100,this);
46533 var value=this.getEditor().GetData();
46534 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46535 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46539 setSize : function(w,h) {
46543 //if (this.frame && this.frame.dom.style.display == 'none') {
46544 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46547 //if(!this.el || !this.getEditor()) {
46548 // this.setSize.defer(100,this, [w,h]);
46554 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46556 this.frame.dom.setAttribute('width', w);
46557 this.frame.dom.setAttribute('height', h);
46558 this.frame.setSize(w,h);
46562 toggleSourceEdit : function(value) {
46566 this.el.dom.style.display = value ? '' : 'none';
46567 this.frame.dom.style.display = value ? 'none' : '';
46572 focus: function(tag)
46574 if (this.frame.dom.style.display == 'none') {
46575 return Roo.form.FCKeditor.superclass.focus.call(this);
46577 if(!this.el || !this.getEditor()) {
46578 this.focus.defer(100,this, [tag]);
46585 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46586 this.getEditor().Focus();
46588 if (!this.getEditor().Selection.GetSelection()) {
46589 this.focus.defer(100,this, [tag]);
46594 var r = this.getEditor().EditorDocument.createRange();
46595 r.setStart(tgs[0],0);
46596 r.setEnd(tgs[0],0);
46597 this.getEditor().Selection.GetSelection().removeAllRanges();
46598 this.getEditor().Selection.GetSelection().addRange(r);
46599 this.getEditor().Focus();
46606 replaceTextarea : function()
46608 if ( document.getElementById( this.getId() + '___Frame' ) )
46610 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46612 // We must check the elements firstly using the Id and then the name.
46613 var oTextarea = document.getElementById( this.getId() );
46615 var colElementsByName = document.getElementsByName( this.getId() ) ;
46617 oTextarea.style.display = 'none' ;
46619 if ( oTextarea.tabIndex ) {
46620 this.TabIndex = oTextarea.tabIndex ;
46623 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46624 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46625 this.frame = Roo.get(this.getId() + '___Frame')
46628 _getConfigHtml : function()
46632 for ( var o in this.fckconfig ) {
46633 sConfig += sConfig.length > 0 ? '&' : '';
46634 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46637 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46641 _getIFrameHtml : function()
46643 var sFile = 'fckeditor.html' ;
46644 /* no idea what this is about..
46647 if ( (/fcksource=true/i).test( window.top.location.search ) )
46648 sFile = 'fckeditor.original.html' ;
46653 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46654 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46657 var html = '<iframe id="' + this.getId() +
46658 '___Frame" src="' + sLink +
46659 '" width="' + this.width +
46660 '" height="' + this.height + '"' +
46661 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46662 ' frameborder="0" scrolling="no"></iframe>' ;
46667 _insertHtmlBefore : function( html, element )
46669 if ( element.insertAdjacentHTML ) {
46671 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46673 var oRange = document.createRange() ;
46674 oRange.setStartBefore( element ) ;
46675 var oFragment = oRange.createContextualFragment( html );
46676 element.parentNode.insertBefore( oFragment, element ) ;
46689 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46691 function FCKeditor_OnComplete(editorInstance){
46692 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46693 f.fckEditor = editorInstance;
46694 //console.log("loaded");
46695 f.fireEvent('editorinit', f, editorInstance);
46715 //<script type="text/javascript">
46717 * @class Roo.form.GridField
46718 * @extends Roo.form.Field
46719 * Embed a grid (or editable grid into a form)
46722 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46724 * xgrid.store = Roo.data.Store
46725 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46726 * xgrid.store.reader = Roo.data.JsonReader
46730 * Creates a new GridField
46731 * @param {Object} config Configuration options
46733 Roo.form.GridField = function(config){
46734 Roo.form.GridField.superclass.constructor.call(this, config);
46738 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46740 * @cfg {Number} width - used to restrict width of grid..
46744 * @cfg {Number} height - used to restrict height of grid..
46748 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46754 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46755 * {tag: "input", type: "checkbox", autocomplete: "off"})
46757 // defaultAutoCreate : { tag: 'div' },
46758 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46760 * @cfg {String} addTitle Text to include for adding a title.
46764 onResize : function(){
46765 Roo.form.Field.superclass.onResize.apply(this, arguments);
46768 initEvents : function(){
46769 // Roo.form.Checkbox.superclass.initEvents.call(this);
46770 // has no events...
46775 getResizeEl : function(){
46779 getPositionEl : function(){
46784 onRender : function(ct, position){
46786 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46787 var style = this.style;
46790 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46791 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46792 this.viewEl = this.wrap.createChild({ tag: 'div' });
46794 this.viewEl.applyStyles(style);
46797 this.viewEl.setWidth(this.width);
46800 this.viewEl.setHeight(this.height);
46802 //if(this.inputValue !== undefined){
46803 //this.setValue(this.value);
46806 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46809 this.grid.render();
46810 this.grid.getDataSource().on('remove', this.refreshValue, this);
46811 this.grid.getDataSource().on('update', this.refreshValue, this);
46812 this.grid.on('afteredit', this.refreshValue, this);
46818 * Sets the value of the item.
46819 * @param {String} either an object or a string..
46821 setValue : function(v){
46823 v = v || []; // empty set..
46824 // this does not seem smart - it really only affects memoryproxy grids..
46825 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46826 var ds = this.grid.getDataSource();
46827 // assumes a json reader..
46829 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46830 ds.loadData( data);
46832 // clear selection so it does not get stale.
46833 if (this.grid.sm) {
46834 this.grid.sm.clearSelections();
46837 Roo.form.GridField.superclass.setValue.call(this, v);
46838 this.refreshValue();
46839 // should load data in the grid really....
46843 refreshValue: function() {
46845 this.grid.getDataSource().each(function(r) {
46848 this.el.dom.value = Roo.encode(val);
46856 * Ext JS Library 1.1.1
46857 * Copyright(c) 2006-2007, Ext JS, LLC.
46859 * Originally Released Under LGPL - original licence link has changed is not relivant.
46862 * <script type="text/javascript">
46865 * @class Roo.form.DisplayField
46866 * @extends Roo.form.Field
46867 * A generic Field to display non-editable data.
46869 * Creates a new Display Field item.
46870 * @param {Object} config Configuration options
46872 Roo.form.DisplayField = function(config){
46873 Roo.form.DisplayField.superclass.constructor.call(this, config);
46877 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46878 inputType: 'hidden',
46884 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46886 focusClass : undefined,
46888 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46890 fieldClass: 'x-form-field',
46893 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46895 valueRenderer: undefined,
46899 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46900 * {tag: "input", type: "checkbox", autocomplete: "off"})
46903 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46905 onResize : function(){
46906 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46910 initEvents : function(){
46911 // Roo.form.Checkbox.superclass.initEvents.call(this);
46912 // has no events...
46917 getResizeEl : function(){
46921 getPositionEl : function(){
46926 onRender : function(ct, position){
46928 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46929 //if(this.inputValue !== undefined){
46930 this.wrap = this.el.wrap();
46932 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46934 if (this.bodyStyle) {
46935 this.viewEl.applyStyles(this.bodyStyle);
46937 //this.viewEl.setStyle('padding', '2px');
46939 this.setValue(this.value);
46944 initValue : Roo.emptyFn,
46949 onClick : function(){
46954 * Sets the checked state of the checkbox.
46955 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46957 setValue : function(v){
46959 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46960 // this might be called before we have a dom element..
46961 if (!this.viewEl) {
46964 this.viewEl.dom.innerHTML = html;
46965 Roo.form.DisplayField.superclass.setValue.call(this, v);
46975 * @class Roo.form.DayPicker
46976 * @extends Roo.form.Field
46977 * A Day picker show [M] [T] [W] ....
46979 * Creates a new Day Picker
46980 * @param {Object} config Configuration options
46982 Roo.form.DayPicker= function(config){
46983 Roo.form.DayPicker.superclass.constructor.call(this, config);
46987 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46989 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46991 focusClass : undefined,
46993 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46995 fieldClass: "x-form-field",
46998 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46999 * {tag: "input", type: "checkbox", autocomplete: "off"})
47001 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
47004 actionMode : 'viewEl',
47008 inputType : 'hidden',
47011 inputElement: false, // real input element?
47012 basedOn: false, // ????
47014 isFormField: true, // not sure where this is needed!!!!
47016 onResize : function(){
47017 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47018 if(!this.boxLabel){
47019 this.el.alignTo(this.wrap, 'c-c');
47023 initEvents : function(){
47024 Roo.form.Checkbox.superclass.initEvents.call(this);
47025 this.el.on("click", this.onClick, this);
47026 this.el.on("change", this.onClick, this);
47030 getResizeEl : function(){
47034 getPositionEl : function(){
47040 onRender : function(ct, position){
47041 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47043 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47045 var r1 = '<table><tr>';
47046 var r2 = '<tr class="x-form-daypick-icons">';
47047 for (var i=0; i < 7; i++) {
47048 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47049 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47052 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47053 viewEl.select('img').on('click', this.onClick, this);
47054 this.viewEl = viewEl;
47057 // this will not work on Chrome!!!
47058 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47059 this.el.on('propertychange', this.setFromHidden, this); //ie
47067 initValue : Roo.emptyFn,
47070 * Returns the checked state of the checkbox.
47071 * @return {Boolean} True if checked, else false
47073 getValue : function(){
47074 return this.el.dom.value;
47079 onClick : function(e){
47080 //this.setChecked(!this.checked);
47081 Roo.get(e.target).toggleClass('x-menu-item-checked');
47082 this.refreshValue();
47083 //if(this.el.dom.checked != this.checked){
47084 // this.setValue(this.el.dom.checked);
47089 refreshValue : function()
47092 this.viewEl.select('img',true).each(function(e,i,n) {
47093 val += e.is(".x-menu-item-checked") ? String(n) : '';
47095 this.setValue(val, true);
47099 * Sets the checked state of the checkbox.
47100 * On is always based on a string comparison between inputValue and the param.
47101 * @param {Boolean/String} value - the value to set
47102 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47104 setValue : function(v,suppressEvent){
47105 if (!this.el.dom) {
47108 var old = this.el.dom.value ;
47109 this.el.dom.value = v;
47110 if (suppressEvent) {
47114 // update display..
47115 this.viewEl.select('img',true).each(function(e,i,n) {
47117 var on = e.is(".x-menu-item-checked");
47118 var newv = v.indexOf(String(n)) > -1;
47120 e.toggleClass('x-menu-item-checked');
47126 this.fireEvent('change', this, v, old);
47131 // handle setting of hidden value by some other method!!?!?
47132 setFromHidden: function()
47137 //console.log("SET FROM HIDDEN");
47138 //alert('setFrom hidden');
47139 this.setValue(this.el.dom.value);
47142 onDestroy : function()
47145 Roo.get(this.viewEl).remove();
47148 Roo.form.DayPicker.superclass.onDestroy.call(this);
47152 * RooJS Library 1.1.1
47153 * Copyright(c) 2008-2011 Alan Knowles
47160 * @class Roo.form.ComboCheck
47161 * @extends Roo.form.ComboBox
47162 * A combobox for multiple select items.
47164 * FIXME - could do with a reset button..
47167 * Create a new ComboCheck
47168 * @param {Object} config Configuration options
47170 Roo.form.ComboCheck = function(config){
47171 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47172 // should verify some data...
47174 // hiddenName = required..
47175 // displayField = required
47176 // valudField == required
47177 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47179 Roo.each(req, function(e) {
47180 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47181 throw "Roo.form.ComboCheck : missing value for: " + e;
47188 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47193 selectedClass: 'x-menu-item-checked',
47196 onRender : function(ct, position){
47202 var cls = 'x-combo-list';
47205 this.tpl = new Roo.Template({
47206 html : '<div class="'+cls+'-item x-menu-check-item">' +
47207 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47208 '<span>{' + this.displayField + '}</span>' +
47215 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47216 this.view.singleSelect = false;
47217 this.view.multiSelect = true;
47218 this.view.toggleSelect = true;
47219 this.pageTb.add(new Roo.Toolbar.Fill(), {
47222 handler: function()
47229 onViewOver : function(e, t){
47235 onViewClick : function(doFocus,index){
47239 select: function () {
47240 //Roo.log("SELECT CALLED");
47243 selectByValue : function(xv, scrollIntoView){
47244 var ar = this.getValueArray();
47247 Roo.each(ar, function(v) {
47248 if(v === undefined || v === null){
47251 var r = this.findRecord(this.valueField, v);
47253 sels.push(this.store.indexOf(r))
47257 this.view.select(sels);
47263 onSelect : function(record, index){
47264 // Roo.log("onselect Called");
47265 // this is only called by the clear button now..
47266 this.view.clearSelections();
47267 this.setValue('[]');
47268 if (this.value != this.valueBefore) {
47269 this.fireEvent('change', this, this.value, this.valueBefore);
47270 this.valueBefore = this.value;
47273 getValueArray : function()
47278 //Roo.log(this.value);
47279 if (typeof(this.value) == 'undefined') {
47282 var ar = Roo.decode(this.value);
47283 return ar instanceof Array ? ar : []; //?? valid?
47286 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47291 expand : function ()
47294 Roo.form.ComboCheck.superclass.expand.call(this);
47295 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47296 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47301 collapse : function(){
47302 Roo.form.ComboCheck.superclass.collapse.call(this);
47303 var sl = this.view.getSelectedIndexes();
47304 var st = this.store;
47308 Roo.each(sl, function(i) {
47310 nv.push(r.get(this.valueField));
47312 this.setValue(Roo.encode(nv));
47313 if (this.value != this.valueBefore) {
47315 this.fireEvent('change', this, this.value, this.valueBefore);
47316 this.valueBefore = this.value;
47321 setValue : function(v){
47325 var vals = this.getValueArray();
47327 Roo.each(vals, function(k) {
47328 var r = this.findRecord(this.valueField, k);
47330 tv.push(r.data[this.displayField]);
47331 }else if(this.valueNotFoundText !== undefined){
47332 tv.push( this.valueNotFoundText );
47337 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47338 this.hiddenField.value = v;
47344 * Ext JS Library 1.1.1
47345 * Copyright(c) 2006-2007, Ext JS, LLC.
47347 * Originally Released Under LGPL - original licence link has changed is not relivant.
47350 * <script type="text/javascript">
47354 * @class Roo.form.Signature
47355 * @extends Roo.form.Field
47359 * @param {Object} config Configuration options
47362 Roo.form.Signature = function(config){
47363 Roo.form.Signature.superclass.constructor.call(this, config);
47365 this.addEvents({// not in used??
47368 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47369 * @param {Roo.form.Signature} combo This combo box
47374 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47375 * @param {Roo.form.ComboBox} combo This combo box
47376 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47382 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47384 * @cfg {Object} labels Label to use when rendering a form.
47388 * confirm : "Confirm"
47393 confirm : "Confirm"
47396 * @cfg {Number} width The signature panel width (defaults to 300)
47400 * @cfg {Number} height The signature panel height (defaults to 100)
47404 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47406 allowBlank : false,
47409 // {Object} signPanel The signature SVG panel element (defaults to {})
47411 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47412 isMouseDown : false,
47413 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47414 isConfirmed : false,
47415 // {String} signatureTmp SVG mapping string (defaults to empty string)
47419 defaultAutoCreate : { // modified by initCompnoent..
47425 onRender : function(ct, position){
47427 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47429 this.wrap = this.el.wrap({
47430 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47433 this.createToolbar(this);
47434 this.signPanel = this.wrap.createChild({
47436 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47440 this.svgID = Roo.id();
47441 this.svgEl = this.signPanel.createChild({
47442 xmlns : 'http://www.w3.org/2000/svg',
47444 id : this.svgID + "-svg",
47446 height: this.height,
47447 viewBox: '0 0 '+this.width+' '+this.height,
47451 id: this.svgID + "-svg-r",
47453 height: this.height,
47458 id: this.svgID + "-svg-l",
47460 y1: (this.height*0.8), // start set the line in 80% of height
47461 x2: this.width, // end
47462 y2: (this.height*0.8), // end set the line in 80% of height
47464 'stroke-width': "1",
47465 'stroke-dasharray': "3",
47466 'shape-rendering': "crispEdges",
47467 'pointer-events': "none"
47471 id: this.svgID + "-svg-p",
47473 'stroke-width': "3",
47475 'pointer-events': 'none'
47480 this.svgBox = this.svgEl.dom.getScreenCTM();
47482 createSVG : function(){
47483 var svg = this.signPanel;
47484 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47487 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47488 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47489 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47490 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47491 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47492 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47493 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47496 isTouchEvent : function(e){
47497 return e.type.match(/^touch/);
47499 getCoords : function (e) {
47500 var pt = this.svgEl.dom.createSVGPoint();
47503 if (this.isTouchEvent(e)) {
47504 pt.x = e.targetTouches[0].clientX
47505 pt.y = e.targetTouches[0].clientY;
47507 var a = this.svgEl.dom.getScreenCTM();
47508 var b = a.inverse();
47509 var mx = pt.matrixTransform(b);
47510 return mx.x + ',' + mx.y;
47512 //mouse event headler
47513 down : function (e) {
47514 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47515 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47517 this.isMouseDown = true;
47519 e.preventDefault();
47521 move : function (e) {
47522 if (this.isMouseDown) {
47523 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47524 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47527 e.preventDefault();
47529 up : function (e) {
47530 this.isMouseDown = false;
47531 var sp = this.signatureTmp.split(' ');
47534 if(!sp[sp.length-2].match(/^L/)){
47538 this.signatureTmp = sp.join(" ");
47541 if(this.getValue() != this.signatureTmp){
47542 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47543 this.isConfirmed = false;
47545 e.preventDefault();
47549 * Protected method that will not generally be called directly. It
47550 * is called when the editor creates its toolbar. Override this method if you need to
47551 * add custom toolbar buttons.
47552 * @param {HtmlEditor} editor
47554 createToolbar : function(editor){
47555 function btn(id, toggle, handler){
47556 var xid = fid + '-'+ id ;
47560 cls : 'x-btn-icon x-edit-'+id,
47561 enableToggle:toggle !== false,
47562 scope: editor, // was editor...
47563 handler:handler||editor.relayBtnCmd,
47564 clickEvent:'mousedown',
47565 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47571 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47575 cls : ' x-signature-btn x-signature-'+id,
47576 scope: editor, // was editor...
47577 handler: this.reset,
47578 clickEvent:'mousedown',
47579 text: this.labels.clear
47586 cls : ' x-signature-btn x-signature-'+id,
47587 scope: editor, // was editor...
47588 handler: this.confirmHandler,
47589 clickEvent:'mousedown',
47590 text: this.labels.confirm
47597 * when user is clicked confirm then show this image.....
47599 * @return {String} Image Data URI
47601 getImageDataURI : function(){
47602 var svg = this.svgEl.dom.parentNode.innerHTML;
47603 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47608 * @return {Boolean} this.isConfirmed
47610 getConfirmed : function(){
47611 return this.isConfirmed;
47615 * @return {Number} this.width
47617 getWidth : function(){
47622 * @return {Number} this.height
47624 getHeight : function(){
47625 return this.height;
47628 getSignature : function(){
47629 return this.signatureTmp;
47632 reset : function(){
47633 this.signatureTmp = '';
47634 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47635 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47636 this.isConfirmed = false;
47637 Roo.form.Signature.superclass.reset.call(this);
47639 setSignature : function(s){
47640 this.signatureTmp = s;
47641 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47642 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47644 this.isConfirmed = false;
47645 Roo.form.Signature.superclass.reset.call(this);
47648 // Roo.log(this.signPanel.dom.contentWindow.up())
47651 setConfirmed : function(){
47655 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47658 confirmHandler : function(){
47659 if(!this.getSignature()){
47663 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47664 this.setValue(this.getSignature());
47665 this.isConfirmed = true;
47667 this.fireEvent('confirm', this);
47670 // Subclasses should provide the validation implementation by overriding this
47671 validateValue : function(value){
47672 if(this.allowBlank){
47676 if(this.isConfirmed){
47683 * Ext JS Library 1.1.1
47684 * Copyright(c) 2006-2007, Ext JS, LLC.
47686 * Originally Released Under LGPL - original licence link has changed is not relivant.
47689 * <script type="text/javascript">
47694 * @class Roo.form.ComboBox
47695 * @extends Roo.form.TriggerField
47696 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47698 * Create a new ComboBox.
47699 * @param {Object} config Configuration options
47701 Roo.form.Select = function(config){
47702 Roo.form.Select.superclass.constructor.call(this, config);
47706 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47708 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47711 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47712 * rendering into an Roo.Editor, defaults to false)
47715 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47716 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47719 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47722 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47723 * the dropdown list (defaults to undefined, with no header element)
47727 * @cfg {String/Roo.Template} tpl The template to use to render the output
47731 defaultAutoCreate : {tag: "select" },
47733 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47735 listWidth: undefined,
47737 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47738 * mode = 'remote' or 'text' if mode = 'local')
47740 displayField: undefined,
47742 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47743 * mode = 'remote' or 'value' if mode = 'local').
47744 * Note: use of a valueField requires the user make a selection
47745 * in order for a value to be mapped.
47747 valueField: undefined,
47751 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47752 * field's data value (defaults to the underlying DOM element's name)
47754 hiddenName: undefined,
47756 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47760 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47762 selectedClass: 'x-combo-selected',
47764 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47765 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47766 * which displays a downward arrow icon).
47768 triggerClass : 'x-form-arrow-trigger',
47770 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47774 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47775 * anchor positions (defaults to 'tl-bl')
47777 listAlign: 'tl-bl?',
47779 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47783 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47784 * query specified by the allQuery config option (defaults to 'query')
47786 triggerAction: 'query',
47788 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47789 * (defaults to 4, does not apply if editable = false)
47793 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47794 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47798 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47799 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47803 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47804 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47808 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47809 * when editable = true (defaults to false)
47811 selectOnFocus:false,
47813 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47815 queryParam: 'query',
47817 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47818 * when mode = 'remote' (defaults to 'Loading...')
47820 loadingText: 'Loading...',
47822 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47826 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47830 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47831 * traditional select (defaults to true)
47835 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47839 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47843 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47844 * listWidth has a higher value)
47848 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47849 * allow the user to set arbitrary text into the field (defaults to false)
47851 forceSelection:false,
47853 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47854 * if typeAhead = true (defaults to 250)
47856 typeAheadDelay : 250,
47858 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47859 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47861 valueNotFoundText : undefined,
47864 * @cfg {String} defaultValue The value displayed after loading the store.
47869 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47871 blockFocus : false,
47874 * @cfg {Boolean} disableClear Disable showing of clear button.
47876 disableClear : false,
47878 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47880 alwaysQuery : false,
47886 // element that contains real text value.. (when hidden is used..)
47889 onRender : function(ct, position){
47890 Roo.form.Field.prototype.onRender.call(this, ct, position);
47893 this.store.on('beforeload', this.onBeforeLoad, this);
47894 this.store.on('load', this.onLoad, this);
47895 this.store.on('loadexception', this.onLoadException, this);
47896 this.store.load({});
47904 initEvents : function(){
47905 //Roo.form.ComboBox.superclass.initEvents.call(this);
47909 onDestroy : function(){
47912 this.store.un('beforeload', this.onBeforeLoad, this);
47913 this.store.un('load', this.onLoad, this);
47914 this.store.un('loadexception', this.onLoadException, this);
47916 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47920 fireKey : function(e){
47921 if(e.isNavKeyPress() && !this.list.isVisible()){
47922 this.fireEvent("specialkey", this, e);
47927 onResize: function(w, h){
47935 * Allow or prevent the user from directly editing the field text. If false is passed,
47936 * the user will only be able to select from the items defined in the dropdown list. This method
47937 * is the runtime equivalent of setting the 'editable' config option at config time.
47938 * @param {Boolean} value True to allow the user to directly edit the field text
47940 setEditable : function(value){
47945 onBeforeLoad : function(){
47947 Roo.log("Select before load");
47950 this.innerList.update(this.loadingText ?
47951 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47952 //this.restrictHeight();
47953 this.selectedIndex = -1;
47957 onLoad : function(){
47960 var dom = this.el.dom;
47961 dom.innerHTML = '';
47962 var od = dom.ownerDocument;
47964 if (this.emptyText) {
47965 var op = od.createElement('option');
47966 op.setAttribute('value', '');
47967 op.innerHTML = String.format('{0}', this.emptyText);
47968 dom.appendChild(op);
47970 if(this.store.getCount() > 0){
47972 var vf = this.valueField;
47973 var df = this.displayField;
47974 this.store.data.each(function(r) {
47975 // which colmsn to use... testing - cdoe / title..
47976 var op = od.createElement('option');
47977 op.setAttribute('value', r.data[vf]);
47978 op.innerHTML = String.format('{0}', r.data[df]);
47979 dom.appendChild(op);
47981 if (typeof(this.defaultValue != 'undefined')) {
47982 this.setValue(this.defaultValue);
47987 //this.onEmptyResults();
47992 onLoadException : function()
47994 dom.innerHTML = '';
47996 Roo.log("Select on load exception");
48000 Roo.log(this.store.reader.jsonData);
48001 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48002 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48008 onTypeAhead : function(){
48013 onSelect : function(record, index){
48014 Roo.log('on select?');
48016 if(this.fireEvent('beforeselect', this, record, index) !== false){
48017 this.setFromData(index > -1 ? record.data : false);
48019 this.fireEvent('select', this, record, index);
48024 * Returns the currently selected field value or empty string if no value is set.
48025 * @return {String} value The selected value
48027 getValue : function(){
48028 var dom = this.el.dom;
48029 this.value = dom.options[dom.selectedIndex].value;
48035 * Clears any text/value currently set in the field
48037 clearValue : function(){
48039 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48044 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48045 * will be displayed in the field. If the value does not match the data value of an existing item,
48046 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48047 * Otherwise the field will be blank (although the value will still be set).
48048 * @param {String} value The value to match
48050 setValue : function(v){
48051 var d = this.el.dom;
48052 for (var i =0; i < d.options.length;i++) {
48053 if (v == d.options[i].value) {
48054 d.selectedIndex = i;
48062 * @property {Object} the last set data for the element
48067 * Sets the value of the field based on a object which is related to the record format for the store.
48068 * @param {Object} value the value to set as. or false on reset?
48070 setFromData : function(o){
48071 Roo.log('setfrom data?');
48077 reset : function(){
48081 findRecord : function(prop, value){
48086 if(this.store.getCount() > 0){
48087 this.store.each(function(r){
48088 if(r.data[prop] == value){
48098 getName: function()
48100 // returns hidden if it's set..
48101 if (!this.rendered) {return ''};
48102 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48110 onEmptyResults : function(){
48111 Roo.log('empty results');
48116 * Returns true if the dropdown list is expanded, else false.
48118 isExpanded : function(){
48123 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48124 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48125 * @param {String} value The data value of the item to select
48126 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48127 * selected item if it is not currently in view (defaults to true)
48128 * @return {Boolean} True if the value matched an item in the list, else false
48130 selectByValue : function(v, scrollIntoView){
48131 Roo.log('select By Value');
48134 if(v !== undefined && v !== null){
48135 var r = this.findRecord(this.valueField || this.displayField, v);
48137 this.select(this.store.indexOf(r), scrollIntoView);
48145 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48146 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48147 * @param {Number} index The zero-based index of the list item to select
48148 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48149 * selected item if it is not currently in view (defaults to true)
48151 select : function(index, scrollIntoView){
48152 Roo.log('select ');
48155 this.selectedIndex = index;
48156 this.view.select(index);
48157 if(scrollIntoView !== false){
48158 var el = this.view.getNode(index);
48160 this.innerList.scrollChildIntoView(el, false);
48168 validateBlur : function(){
48175 initQuery : function(){
48176 this.doQuery(this.getRawValue());
48180 doForce : function(){
48181 if(this.el.dom.value.length > 0){
48182 this.el.dom.value =
48183 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48189 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48190 * query allowing the query action to be canceled if needed.
48191 * @param {String} query The SQL query to execute
48192 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48193 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48194 * saved in the current store (defaults to false)
48196 doQuery : function(q, forceAll){
48198 Roo.log('doQuery?');
48199 if(q === undefined || q === null){
48204 forceAll: forceAll,
48208 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48212 forceAll = qe.forceAll;
48213 if(forceAll === true || (q.length >= this.minChars)){
48214 if(this.lastQuery != q || this.alwaysQuery){
48215 this.lastQuery = q;
48216 if(this.mode == 'local'){
48217 this.selectedIndex = -1;
48219 this.store.clearFilter();
48221 this.store.filter(this.displayField, q);
48225 this.store.baseParams[this.queryParam] = q;
48227 params: this.getParams(q)
48232 this.selectedIndex = -1;
48239 getParams : function(q){
48241 //p[this.queryParam] = q;
48244 p.limit = this.pageSize;
48250 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48252 collapse : function(){
48257 collapseIf : function(e){
48262 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48264 expand : function(){
48272 * @cfg {Boolean} grow
48276 * @cfg {Number} growMin
48280 * @cfg {Number} growMax
48288 setWidth : function()
48292 getResizeEl : function(){
48295 });//<script type="text/javasscript">
48299 * @class Roo.DDView
48300 * A DnD enabled version of Roo.View.
48301 * @param {Element/String} container The Element in which to create the View.
48302 * @param {String} tpl The template string used to create the markup for each element of the View
48303 * @param {Object} config The configuration properties. These include all the config options of
48304 * {@link Roo.View} plus some specific to this class.<br>
48306 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48307 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48309 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48310 .x-view-drag-insert-above {
48311 border-top:1px dotted #3366cc;
48313 .x-view-drag-insert-below {
48314 border-bottom:1px dotted #3366cc;
48320 Roo.DDView = function(container, tpl, config) {
48321 Roo.DDView.superclass.constructor.apply(this, arguments);
48322 this.getEl().setStyle("outline", "0px none");
48323 this.getEl().unselectable();
48324 if (this.dragGroup) {
48325 this.setDraggable(this.dragGroup.split(","));
48327 if (this.dropGroup) {
48328 this.setDroppable(this.dropGroup.split(","));
48330 if (this.deletable) {
48331 this.setDeletable();
48333 this.isDirtyFlag = false;
48339 Roo.extend(Roo.DDView, Roo.View, {
48340 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48341 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48342 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48343 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48347 reset: Roo.emptyFn,
48349 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48351 validate: function() {
48355 destroy: function() {
48356 this.purgeListeners();
48357 this.getEl.removeAllListeners();
48358 this.getEl().remove();
48359 if (this.dragZone) {
48360 if (this.dragZone.destroy) {
48361 this.dragZone.destroy();
48364 if (this.dropZone) {
48365 if (this.dropZone.destroy) {
48366 this.dropZone.destroy();
48371 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48372 getName: function() {
48376 /** Loads the View from a JSON string representing the Records to put into the Store. */
48377 setValue: function(v) {
48379 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48382 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48383 this.store.proxy = new Roo.data.MemoryProxy(data);
48387 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48388 getValue: function() {
48390 this.store.each(function(rec) {
48391 result += rec.id + ',';
48393 return result.substr(0, result.length - 1) + ')';
48396 getIds: function() {
48397 var i = 0, result = new Array(this.store.getCount());
48398 this.store.each(function(rec) {
48399 result[i++] = rec.id;
48404 isDirty: function() {
48405 return this.isDirtyFlag;
48409 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48410 * whole Element becomes the target, and this causes the drop gesture to append.
48412 getTargetFromEvent : function(e) {
48413 var target = e.getTarget();
48414 while ((target !== null) && (target.parentNode != this.el.dom)) {
48415 target = target.parentNode;
48418 target = this.el.dom.lastChild || this.el.dom;
48424 * Create the drag data which consists of an object which has the property "ddel" as
48425 * the drag proxy element.
48427 getDragData : function(e) {
48428 var target = this.findItemFromChild(e.getTarget());
48430 this.handleSelection(e);
48431 var selNodes = this.getSelectedNodes();
48434 copy: this.copy || (this.allowCopy && e.ctrlKey),
48438 var selectedIndices = this.getSelectedIndexes();
48439 for (var i = 0; i < selectedIndices.length; i++) {
48440 dragData.records.push(this.store.getAt(selectedIndices[i]));
48442 if (selNodes.length == 1) {
48443 dragData.ddel = target.cloneNode(true); // the div element
48445 var div = document.createElement('div'); // create the multi element drag "ghost"
48446 div.className = 'multi-proxy';
48447 for (var i = 0, len = selNodes.length; i < len; i++) {
48448 div.appendChild(selNodes[i].cloneNode(true));
48450 dragData.ddel = div;
48452 //console.log(dragData)
48453 //console.log(dragData.ddel.innerHTML)
48456 //console.log('nodragData')
48460 /** Specify to which ddGroup items in this DDView may be dragged. */
48461 setDraggable: function(ddGroup) {
48462 if (ddGroup instanceof Array) {
48463 Roo.each(ddGroup, this.setDraggable, this);
48466 if (this.dragZone) {
48467 this.dragZone.addToGroup(ddGroup);
48469 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48470 containerScroll: true,
48474 // Draggability implies selection. DragZone's mousedown selects the element.
48475 if (!this.multiSelect) { this.singleSelect = true; }
48477 // Wire the DragZone's handlers up to methods in *this*
48478 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48482 /** Specify from which ddGroup this DDView accepts drops. */
48483 setDroppable: function(ddGroup) {
48484 if (ddGroup instanceof Array) {
48485 Roo.each(ddGroup, this.setDroppable, this);
48488 if (this.dropZone) {
48489 this.dropZone.addToGroup(ddGroup);
48491 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48492 containerScroll: true,
48496 // Wire the DropZone's handlers up to methods in *this*
48497 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48498 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48499 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48500 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48501 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48505 /** Decide whether to drop above or below a View node. */
48506 getDropPoint : function(e, n, dd){
48507 if (n == this.el.dom) { return "above"; }
48508 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48509 var c = t + (b - t) / 2;
48510 var y = Roo.lib.Event.getPageY(e);
48518 onNodeEnter : function(n, dd, e, data){
48522 onNodeOver : function(n, dd, e, data){
48523 var pt = this.getDropPoint(e, n, dd);
48524 // set the insert point style on the target node
48525 var dragElClass = this.dropNotAllowed;
48528 if (pt == "above"){
48529 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48530 targetElClass = "x-view-drag-insert-above";
48532 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48533 targetElClass = "x-view-drag-insert-below";
48535 if (this.lastInsertClass != targetElClass){
48536 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48537 this.lastInsertClass = targetElClass;
48540 return dragElClass;
48543 onNodeOut : function(n, dd, e, data){
48544 this.removeDropIndicators(n);
48547 onNodeDrop : function(n, dd, e, data){
48548 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48551 var pt = this.getDropPoint(e, n, dd);
48552 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48553 if (pt == "below") { insertAt++; }
48554 for (var i = 0; i < data.records.length; i++) {
48555 var r = data.records[i];
48556 var dup = this.store.getById(r.id);
48557 if (dup && (dd != this.dragZone)) {
48558 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48561 this.store.insert(insertAt++, r.copy());
48563 data.source.isDirtyFlag = true;
48565 this.store.insert(insertAt++, r);
48567 this.isDirtyFlag = true;
48570 this.dragZone.cachedTarget = null;
48574 removeDropIndicators : function(n){
48576 Roo.fly(n).removeClass([
48577 "x-view-drag-insert-above",
48578 "x-view-drag-insert-below"]);
48579 this.lastInsertClass = "_noclass";
48584 * Utility method. Add a delete option to the DDView's context menu.
48585 * @param {String} imageUrl The URL of the "delete" icon image.
48587 setDeletable: function(imageUrl) {
48588 if (!this.singleSelect && !this.multiSelect) {
48589 this.singleSelect = true;
48591 var c = this.getContextMenu();
48592 this.contextMenu.on("itemclick", function(item) {
48595 this.remove(this.getSelectedIndexes());
48599 this.contextMenu.add({
48606 /** Return the context menu for this DDView. */
48607 getContextMenu: function() {
48608 if (!this.contextMenu) {
48609 // Create the View's context menu
48610 this.contextMenu = new Roo.menu.Menu({
48611 id: this.id + "-contextmenu"
48613 this.el.on("contextmenu", this.showContextMenu, this);
48615 return this.contextMenu;
48618 disableContextMenu: function() {
48619 if (this.contextMenu) {
48620 this.el.un("contextmenu", this.showContextMenu, this);
48624 showContextMenu: function(e, item) {
48625 item = this.findItemFromChild(e.getTarget());
48628 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48629 this.contextMenu.showAt(e.getXY());
48634 * Remove {@link Roo.data.Record}s at the specified indices.
48635 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48637 remove: function(selectedIndices) {
48638 selectedIndices = [].concat(selectedIndices);
48639 for (var i = 0; i < selectedIndices.length; i++) {
48640 var rec = this.store.getAt(selectedIndices[i]);
48641 this.store.remove(rec);
48646 * Double click fires the event, but also, if this is draggable, and there is only one other
48647 * related DropZone, it transfers the selected node.
48649 onDblClick : function(e){
48650 var item = this.findItemFromChild(e.getTarget());
48652 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48655 if (this.dragGroup) {
48656 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48657 while (targets.indexOf(this.dropZone) > -1) {
48658 targets.remove(this.dropZone);
48660 if (targets.length == 1) {
48661 this.dragZone.cachedTarget = null;
48662 var el = Roo.get(targets[0].getEl());
48663 var box = el.getBox(true);
48664 targets[0].onNodeDrop(el.dom, {
48666 xy: [box.x, box.y + box.height - 1]
48667 }, null, this.getDragData(e));
48673 handleSelection: function(e) {
48674 this.dragZone.cachedTarget = null;
48675 var item = this.findItemFromChild(e.getTarget());
48677 this.clearSelections(true);
48680 if (item && (this.multiSelect || this.singleSelect)){
48681 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48682 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48683 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48684 this.unselect(item);
48686 this.select(item, this.multiSelect && e.ctrlKey);
48687 this.lastSelection = item;
48692 onItemClick : function(item, index, e){
48693 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48699 unselect : function(nodeInfo, suppressEvent){
48700 var node = this.getNode(nodeInfo);
48701 if(node && this.isSelected(node)){
48702 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48703 Roo.fly(node).removeClass(this.selectedClass);
48704 this.selections.remove(node);
48705 if(!suppressEvent){
48706 this.fireEvent("selectionchange", this, this.selections);
48714 * Ext JS Library 1.1.1
48715 * Copyright(c) 2006-2007, Ext JS, LLC.
48717 * Originally Released Under LGPL - original licence link has changed is not relivant.
48720 * <script type="text/javascript">
48724 * @class Roo.LayoutManager
48725 * @extends Roo.util.Observable
48726 * Base class for layout managers.
48728 Roo.LayoutManager = function(container, config){
48729 Roo.LayoutManager.superclass.constructor.call(this);
48730 this.el = Roo.get(container);
48731 // ie scrollbar fix
48732 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48733 document.body.scroll = "no";
48734 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48735 this.el.position('relative');
48737 this.id = this.el.id;
48738 this.el.addClass("x-layout-container");
48739 /** false to disable window resize monitoring @type Boolean */
48740 this.monitorWindowResize = true;
48745 * Fires when a layout is performed.
48746 * @param {Roo.LayoutManager} this
48750 * @event regionresized
48751 * Fires when the user resizes a region.
48752 * @param {Roo.LayoutRegion} region The resized region
48753 * @param {Number} newSize The new size (width for east/west, height for north/south)
48755 "regionresized" : true,
48757 * @event regioncollapsed
48758 * Fires when a region is collapsed.
48759 * @param {Roo.LayoutRegion} region The collapsed region
48761 "regioncollapsed" : true,
48763 * @event regionexpanded
48764 * Fires when a region is expanded.
48765 * @param {Roo.LayoutRegion} region The expanded region
48767 "regionexpanded" : true
48769 this.updating = false;
48770 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48773 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48775 * Returns true if this layout is currently being updated
48776 * @return {Boolean}
48778 isUpdating : function(){
48779 return this.updating;
48783 * Suspend the LayoutManager from doing auto-layouts while
48784 * making multiple add or remove calls
48786 beginUpdate : function(){
48787 this.updating = true;
48791 * Restore auto-layouts and optionally disable the manager from performing a layout
48792 * @param {Boolean} noLayout true to disable a layout update
48794 endUpdate : function(noLayout){
48795 this.updating = false;
48801 layout: function(){
48805 onRegionResized : function(region, newSize){
48806 this.fireEvent("regionresized", region, newSize);
48810 onRegionCollapsed : function(region){
48811 this.fireEvent("regioncollapsed", region);
48814 onRegionExpanded : function(region){
48815 this.fireEvent("regionexpanded", region);
48819 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48820 * performs box-model adjustments.
48821 * @return {Object} The size as an object {width: (the width), height: (the height)}
48823 getViewSize : function(){
48825 if(this.el.dom != document.body){
48826 size = this.el.getSize();
48828 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48830 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48831 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48836 * Returns the Element this layout is bound to.
48837 * @return {Roo.Element}
48839 getEl : function(){
48844 * Returns the specified region.
48845 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48846 * @return {Roo.LayoutRegion}
48848 getRegion : function(target){
48849 return this.regions[target.toLowerCase()];
48852 onWindowResize : function(){
48853 if(this.monitorWindowResize){
48859 * Ext JS Library 1.1.1
48860 * Copyright(c) 2006-2007, Ext JS, LLC.
48862 * Originally Released Under LGPL - original licence link has changed is not relivant.
48865 * <script type="text/javascript">
48868 * @class Roo.BorderLayout
48869 * @extends Roo.LayoutManager
48870 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48871 * please see: <br><br>
48872 * <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>
48873 * <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>
48876 var layout = new Roo.BorderLayout(document.body, {
48910 preferredTabWidth: 150
48915 var CP = Roo.ContentPanel;
48917 layout.beginUpdate();
48918 layout.add("north", new CP("north", "North"));
48919 layout.add("south", new CP("south", {title: "South", closable: true}));
48920 layout.add("west", new CP("west", {title: "West"}));
48921 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48922 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48923 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48924 layout.getRegion("center").showPanel("center1");
48925 layout.endUpdate();
48928 <b>The container the layout is rendered into can be either the body element or any other element.
48929 If it is not the body element, the container needs to either be an absolute positioned element,
48930 or you will need to add "position:relative" to the css of the container. You will also need to specify
48931 the container size if it is not the body element.</b>
48934 * Create a new BorderLayout
48935 * @param {String/HTMLElement/Element} container The container this layout is bound to
48936 * @param {Object} config Configuration options
48938 Roo.BorderLayout = function(container, config){
48939 config = config || {};
48940 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48941 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48942 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48943 var target = this.factory.validRegions[i];
48944 if(config[target]){
48945 this.addRegion(target, config[target]);
48950 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48952 * Creates and adds a new region if it doesn't already exist.
48953 * @param {String} target The target region key (north, south, east, west or center).
48954 * @param {Object} config The regions config object
48955 * @return {BorderLayoutRegion} The new region
48957 addRegion : function(target, config){
48958 if(!this.regions[target]){
48959 var r = this.factory.create(target, this, config);
48960 this.bindRegion(target, r);
48962 return this.regions[target];
48966 bindRegion : function(name, r){
48967 this.regions[name] = r;
48968 r.on("visibilitychange", this.layout, this);
48969 r.on("paneladded", this.layout, this);
48970 r.on("panelremoved", this.layout, this);
48971 r.on("invalidated", this.layout, this);
48972 r.on("resized", this.onRegionResized, this);
48973 r.on("collapsed", this.onRegionCollapsed, this);
48974 r.on("expanded", this.onRegionExpanded, this);
48978 * Performs a layout update.
48980 layout : function(){
48981 if(this.updating) return;
48982 var size = this.getViewSize();
48983 var w = size.width;
48984 var h = size.height;
48989 //var x = 0, y = 0;
48991 var rs = this.regions;
48992 var north = rs["north"];
48993 var south = rs["south"];
48994 var west = rs["west"];
48995 var east = rs["east"];
48996 var center = rs["center"];
48997 //if(this.hideOnLayout){ // not supported anymore
48998 //c.el.setStyle("display", "none");
49000 if(north && north.isVisible()){
49001 var b = north.getBox();
49002 var m = north.getMargins();
49003 b.width = w - (m.left+m.right);
49006 centerY = b.height + b.y + m.bottom;
49007 centerH -= centerY;
49008 north.updateBox(this.safeBox(b));
49010 if(south && south.isVisible()){
49011 var b = south.getBox();
49012 var m = south.getMargins();
49013 b.width = w - (m.left+m.right);
49015 var totalHeight = (b.height + m.top + m.bottom);
49016 b.y = h - totalHeight + m.top;
49017 centerH -= totalHeight;
49018 south.updateBox(this.safeBox(b));
49020 if(west && west.isVisible()){
49021 var b = west.getBox();
49022 var m = west.getMargins();
49023 b.height = centerH - (m.top+m.bottom);
49025 b.y = centerY + m.top;
49026 var totalWidth = (b.width + m.left + m.right);
49027 centerX += totalWidth;
49028 centerW -= totalWidth;
49029 west.updateBox(this.safeBox(b));
49031 if(east && east.isVisible()){
49032 var b = east.getBox();
49033 var m = east.getMargins();
49034 b.height = centerH - (m.top+m.bottom);
49035 var totalWidth = (b.width + m.left + m.right);
49036 b.x = w - totalWidth + m.left;
49037 b.y = centerY + m.top;
49038 centerW -= totalWidth;
49039 east.updateBox(this.safeBox(b));
49042 var m = center.getMargins();
49044 x: centerX + m.left,
49045 y: centerY + m.top,
49046 width: centerW - (m.left+m.right),
49047 height: centerH - (m.top+m.bottom)
49049 //if(this.hideOnLayout){
49050 //center.el.setStyle("display", "block");
49052 center.updateBox(this.safeBox(centerBox));
49055 this.fireEvent("layout", this);
49059 safeBox : function(box){
49060 box.width = Math.max(0, box.width);
49061 box.height = Math.max(0, box.height);
49066 * Adds a ContentPanel (or subclass) to this layout.
49067 * @param {String} target The target region key (north, south, east, west or center).
49068 * @param {Roo.ContentPanel} panel The panel to add
49069 * @return {Roo.ContentPanel} The added panel
49071 add : function(target, panel){
49073 target = target.toLowerCase();
49074 return this.regions[target].add(panel);
49078 * Remove a ContentPanel (or subclass) to this layout.
49079 * @param {String} target The target region key (north, south, east, west or center).
49080 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49081 * @return {Roo.ContentPanel} The removed panel
49083 remove : function(target, panel){
49084 target = target.toLowerCase();
49085 return this.regions[target].remove(panel);
49089 * Searches all regions for a panel with the specified id
49090 * @param {String} panelId
49091 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49093 findPanel : function(panelId){
49094 var rs = this.regions;
49095 for(var target in rs){
49096 if(typeof rs[target] != "function"){
49097 var p = rs[target].getPanel(panelId);
49107 * Searches all regions for a panel with the specified id and activates (shows) it.
49108 * @param {String/ContentPanel} panelId The panels id or the panel itself
49109 * @return {Roo.ContentPanel} The shown panel or null
49111 showPanel : function(panelId) {
49112 var rs = this.regions;
49113 for(var target in rs){
49114 var r = rs[target];
49115 if(typeof r != "function"){
49116 if(r.hasPanel(panelId)){
49117 return r.showPanel(panelId);
49125 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49126 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49128 restoreState : function(provider){
49130 provider = Roo.state.Manager;
49132 var sm = new Roo.LayoutStateManager();
49133 sm.init(this, provider);
49137 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49138 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49139 * a valid ContentPanel config object. Example:
49141 // Create the main layout
49142 var layout = new Roo.BorderLayout('main-ct', {
49153 // Create and add multiple ContentPanels at once via configs
49156 id: 'source-files',
49158 title:'Ext Source Files',
49171 * @param {Object} regions An object containing ContentPanel configs by region name
49173 batchAdd : function(regions){
49174 this.beginUpdate();
49175 for(var rname in regions){
49176 var lr = this.regions[rname];
49178 this.addTypedPanels(lr, regions[rname]);
49185 addTypedPanels : function(lr, ps){
49186 if(typeof ps == 'string'){
49187 lr.add(new Roo.ContentPanel(ps));
49189 else if(ps instanceof Array){
49190 for(var i =0, len = ps.length; i < len; i++){
49191 this.addTypedPanels(lr, ps[i]);
49194 else if(!ps.events){ // raw config?
49196 delete ps.el; // prevent conflict
49197 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49199 else { // panel object assumed!
49204 * Adds a xtype elements to the layout.
49208 xtype : 'ContentPanel',
49215 xtype : 'NestedLayoutPanel',
49221 items : [ ... list of content panels or nested layout panels.. ]
49225 * @param {Object} cfg Xtype definition of item to add.
49227 addxtype : function(cfg)
49229 // basically accepts a pannel...
49230 // can accept a layout region..!?!?
49231 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49233 if (!cfg.xtype.match(/Panel$/)) {
49238 if (typeof(cfg.region) == 'undefined') {
49239 Roo.log("Failed to add Panel, region was not set");
49243 var region = cfg.region;
49249 xitems = cfg.items;
49256 case 'ContentPanel': // ContentPanel (el, cfg)
49257 case 'ScrollPanel': // ContentPanel (el, cfg)
49259 if(cfg.autoCreate) {
49260 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49262 var el = this.el.createChild();
49263 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49266 this.add(region, ret);
49270 case 'TreePanel': // our new panel!
49271 cfg.el = this.el.createChild();
49272 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49273 this.add(region, ret);
49276 case 'NestedLayoutPanel':
49277 // create a new Layout (which is a Border Layout...
49278 var el = this.el.createChild();
49279 var clayout = cfg.layout;
49281 clayout.items = clayout.items || [];
49282 // replace this exitems with the clayout ones..
49283 xitems = clayout.items;
49286 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49287 cfg.background = false;
49289 var layout = new Roo.BorderLayout(el, clayout);
49291 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49292 //console.log('adding nested layout panel ' + cfg.toSource());
49293 this.add(region, ret);
49294 nb = {}; /// find first...
49299 // needs grid and region
49301 //var el = this.getRegion(region).el.createChild();
49302 var el = this.el.createChild();
49303 // create the grid first...
49305 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49307 if (region == 'center' && this.active ) {
49308 cfg.background = false;
49310 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49312 this.add(region, ret);
49313 if (cfg.background) {
49314 ret.on('activate', function(gp) {
49315 if (!gp.grid.rendered) {
49330 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49332 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49333 this.add(region, ret);
49336 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49340 // GridPanel (grid, cfg)
49343 this.beginUpdate();
49347 Roo.each(xitems, function(i) {
49348 region = nb && i.region ? i.region : false;
49350 var add = ret.addxtype(i);
49353 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49354 if (!i.background) {
49355 abn[region] = nb[region] ;
49362 // make the last non-background panel active..
49363 //if (nb) { Roo.log(abn); }
49366 for(var r in abn) {
49367 region = this.getRegion(r);
49369 // tried using nb[r], but it does not work..
49371 region.showPanel(abn[r]);
49382 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49383 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49384 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49385 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49388 var CP = Roo.ContentPanel;
49390 var layout = Roo.BorderLayout.create({
49394 panels: [new CP("north", "North")]
49403 panels: [new CP("west", {title: "West"})]
49412 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49421 panels: [new CP("south", {title: "South", closable: true})]
49428 preferredTabWidth: 150,
49430 new CP("center1", {title: "Close Me", closable: true}),
49431 new CP("center2", {title: "Center Panel", closable: false})
49436 layout.getRegion("center").showPanel("center1");
49441 Roo.BorderLayout.create = function(config, targetEl){
49442 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49443 layout.beginUpdate();
49444 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49445 for(var j = 0, jlen = regions.length; j < jlen; j++){
49446 var lr = regions[j];
49447 if(layout.regions[lr] && config[lr].panels){
49448 var r = layout.regions[lr];
49449 var ps = config[lr].panels;
49450 layout.addTypedPanels(r, ps);
49453 layout.endUpdate();
49458 Roo.BorderLayout.RegionFactory = {
49460 validRegions : ["north","south","east","west","center"],
49463 create : function(target, mgr, config){
49464 target = target.toLowerCase();
49465 if(config.lightweight || config.basic){
49466 return new Roo.BasicLayoutRegion(mgr, config, target);
49470 return new Roo.NorthLayoutRegion(mgr, config);
49472 return new Roo.SouthLayoutRegion(mgr, config);
49474 return new Roo.EastLayoutRegion(mgr, config);
49476 return new Roo.WestLayoutRegion(mgr, config);
49478 return new Roo.CenterLayoutRegion(mgr, config);
49480 throw 'Layout region "'+target+'" not supported.';
49484 * Ext JS Library 1.1.1
49485 * Copyright(c) 2006-2007, Ext JS, LLC.
49487 * Originally Released Under LGPL - original licence link has changed is not relivant.
49490 * <script type="text/javascript">
49494 * @class Roo.BasicLayoutRegion
49495 * @extends Roo.util.Observable
49496 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49497 * and does not have a titlebar, tabs or any other features. All it does is size and position
49498 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49500 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49502 this.position = pos;
49505 * @scope Roo.BasicLayoutRegion
49509 * @event beforeremove
49510 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49511 * @param {Roo.LayoutRegion} this
49512 * @param {Roo.ContentPanel} panel The panel
49513 * @param {Object} e The cancel event object
49515 "beforeremove" : true,
49517 * @event invalidated
49518 * Fires when the layout for this region is changed.
49519 * @param {Roo.LayoutRegion} this
49521 "invalidated" : true,
49523 * @event visibilitychange
49524 * Fires when this region is shown or hidden
49525 * @param {Roo.LayoutRegion} this
49526 * @param {Boolean} visibility true or false
49528 "visibilitychange" : true,
49530 * @event paneladded
49531 * Fires when a panel is added.
49532 * @param {Roo.LayoutRegion} this
49533 * @param {Roo.ContentPanel} panel The panel
49535 "paneladded" : true,
49537 * @event panelremoved
49538 * Fires when a panel is removed.
49539 * @param {Roo.LayoutRegion} this
49540 * @param {Roo.ContentPanel} panel The panel
49542 "panelremoved" : true,
49545 * Fires when this region is collapsed.
49546 * @param {Roo.LayoutRegion} this
49548 "collapsed" : true,
49551 * Fires when this region is expanded.
49552 * @param {Roo.LayoutRegion} this
49557 * Fires when this region is slid into view.
49558 * @param {Roo.LayoutRegion} this
49560 "slideshow" : true,
49563 * Fires when this region slides out of view.
49564 * @param {Roo.LayoutRegion} this
49566 "slidehide" : true,
49568 * @event panelactivated
49569 * Fires when a panel is activated.
49570 * @param {Roo.LayoutRegion} this
49571 * @param {Roo.ContentPanel} panel The activated panel
49573 "panelactivated" : true,
49576 * Fires when the user resizes this region.
49577 * @param {Roo.LayoutRegion} this
49578 * @param {Number} newSize The new size (width for east/west, height for north/south)
49582 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49583 this.panels = new Roo.util.MixedCollection();
49584 this.panels.getKey = this.getPanelId.createDelegate(this);
49586 this.activePanel = null;
49587 // ensure listeners are added...
49589 if (config.listeners || config.events) {
49590 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49591 listeners : config.listeners || {},
49592 events : config.events || {}
49596 if(skipConfig !== true){
49597 this.applyConfig(config);
49601 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49602 getPanelId : function(p){
49606 applyConfig : function(config){
49607 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49608 this.config = config;
49613 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49614 * the width, for horizontal (north, south) the height.
49615 * @param {Number} newSize The new width or height
49617 resizeTo : function(newSize){
49618 var el = this.el ? this.el :
49619 (this.activePanel ? this.activePanel.getEl() : null);
49621 switch(this.position){
49624 el.setWidth(newSize);
49625 this.fireEvent("resized", this, newSize);
49629 el.setHeight(newSize);
49630 this.fireEvent("resized", this, newSize);
49636 getBox : function(){
49637 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49640 getMargins : function(){
49641 return this.margins;
49644 updateBox : function(box){
49646 var el = this.activePanel.getEl();
49647 el.dom.style.left = box.x + "px";
49648 el.dom.style.top = box.y + "px";
49649 this.activePanel.setSize(box.width, box.height);
49653 * Returns the container element for this region.
49654 * @return {Roo.Element}
49656 getEl : function(){
49657 return this.activePanel;
49661 * Returns true if this region is currently visible.
49662 * @return {Boolean}
49664 isVisible : function(){
49665 return this.activePanel ? true : false;
49668 setActivePanel : function(panel){
49669 panel = this.getPanel(panel);
49670 if(this.activePanel && this.activePanel != panel){
49671 this.activePanel.setActiveState(false);
49672 this.activePanel.getEl().setLeftTop(-10000,-10000);
49674 this.activePanel = panel;
49675 panel.setActiveState(true);
49677 panel.setSize(this.box.width, this.box.height);
49679 this.fireEvent("panelactivated", this, panel);
49680 this.fireEvent("invalidated");
49684 * Show the specified panel.
49685 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49686 * @return {Roo.ContentPanel} The shown panel or null
49688 showPanel : function(panel){
49689 if(panel = this.getPanel(panel)){
49690 this.setActivePanel(panel);
49696 * Get the active panel for this region.
49697 * @return {Roo.ContentPanel} The active panel or null
49699 getActivePanel : function(){
49700 return this.activePanel;
49704 * Add the passed ContentPanel(s)
49705 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49706 * @return {Roo.ContentPanel} The panel added (if only one was added)
49708 add : function(panel){
49709 if(arguments.length > 1){
49710 for(var i = 0, len = arguments.length; i < len; i++) {
49711 this.add(arguments[i]);
49715 if(this.hasPanel(panel)){
49716 this.showPanel(panel);
49719 var el = panel.getEl();
49720 if(el.dom.parentNode != this.mgr.el.dom){
49721 this.mgr.el.dom.appendChild(el.dom);
49723 if(panel.setRegion){
49724 panel.setRegion(this);
49726 this.panels.add(panel);
49727 el.setStyle("position", "absolute");
49728 if(!panel.background){
49729 this.setActivePanel(panel);
49730 if(this.config.initialSize && this.panels.getCount()==1){
49731 this.resizeTo(this.config.initialSize);
49734 this.fireEvent("paneladded", this, panel);
49739 * Returns true if the panel is in this region.
49740 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49741 * @return {Boolean}
49743 hasPanel : function(panel){
49744 if(typeof panel == "object"){ // must be panel obj
49745 panel = panel.getId();
49747 return this.getPanel(panel) ? true : false;
49751 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49752 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49753 * @param {Boolean} preservePanel Overrides the config preservePanel option
49754 * @return {Roo.ContentPanel} The panel that was removed
49756 remove : function(panel, preservePanel){
49757 panel = this.getPanel(panel);
49762 this.fireEvent("beforeremove", this, panel, e);
49763 if(e.cancel === true){
49766 var panelId = panel.getId();
49767 this.panels.removeKey(panelId);
49772 * Returns the panel specified or null if it's not in this region.
49773 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49774 * @return {Roo.ContentPanel}
49776 getPanel : function(id){
49777 if(typeof id == "object"){ // must be panel obj
49780 return this.panels.get(id);
49784 * Returns this regions position (north/south/east/west/center).
49787 getPosition: function(){
49788 return this.position;
49792 * Ext JS Library 1.1.1
49793 * Copyright(c) 2006-2007, Ext JS, LLC.
49795 * Originally Released Under LGPL - original licence link has changed is not relivant.
49798 * <script type="text/javascript">
49802 * @class Roo.LayoutRegion
49803 * @extends Roo.BasicLayoutRegion
49804 * This class represents a region in a layout manager.
49805 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49806 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49807 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49808 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49809 * @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})
49810 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49811 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49812 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49813 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49814 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49815 * @cfg {String} title The title for the region (overrides panel titles)
49816 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49817 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49818 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49819 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49820 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49821 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49822 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49823 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49824 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49825 * @cfg {Boolean} showPin True to show a pin button
49826 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49827 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49828 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49829 * @cfg {Number} width For East/West panels
49830 * @cfg {Number} height For North/South panels
49831 * @cfg {Boolean} split To show the splitter
49832 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49834 Roo.LayoutRegion = function(mgr, config, pos){
49835 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49836 var dh = Roo.DomHelper;
49837 /** This region's container element
49838 * @type Roo.Element */
49839 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49840 /** This region's title element
49841 * @type Roo.Element */
49843 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49844 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49845 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49847 this.titleEl.enableDisplayMode();
49848 /** This region's title text element
49849 * @type HTMLElement */
49850 this.titleTextEl = this.titleEl.dom.firstChild;
49851 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49852 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49853 this.closeBtn.enableDisplayMode();
49854 this.closeBtn.on("click", this.closeClicked, this);
49855 this.closeBtn.hide();
49857 this.createBody(config);
49858 this.visible = true;
49859 this.collapsed = false;
49861 if(config.hideWhenEmpty){
49863 this.on("paneladded", this.validateVisibility, this);
49864 this.on("panelremoved", this.validateVisibility, this);
49866 this.applyConfig(config);
49869 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49871 createBody : function(){
49872 /** This region's body element
49873 * @type Roo.Element */
49874 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49877 applyConfig : function(c){
49878 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49879 var dh = Roo.DomHelper;
49880 if(c.titlebar !== false){
49881 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49882 this.collapseBtn.on("click", this.collapse, this);
49883 this.collapseBtn.enableDisplayMode();
49885 if(c.showPin === true || this.showPin){
49886 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49887 this.stickBtn.enableDisplayMode();
49888 this.stickBtn.on("click", this.expand, this);
49889 this.stickBtn.hide();
49892 /** This region's collapsed element
49893 * @type Roo.Element */
49894 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49895 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49897 if(c.floatable !== false){
49898 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49899 this.collapsedEl.on("click", this.collapseClick, this);
49902 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49903 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49904 id: "message", unselectable: "on", style:{"float":"left"}});
49905 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49907 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49908 this.expandBtn.on("click", this.expand, this);
49910 if(this.collapseBtn){
49911 this.collapseBtn.setVisible(c.collapsible == true);
49913 this.cmargins = c.cmargins || this.cmargins ||
49914 (this.position == "west" || this.position == "east" ?
49915 {top: 0, left: 2, right:2, bottom: 0} :
49916 {top: 2, left: 0, right:0, bottom: 2});
49917 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49918 this.bottomTabs = c.tabPosition != "top";
49919 this.autoScroll = c.autoScroll || false;
49920 if(this.autoScroll){
49921 this.bodyEl.setStyle("overflow", "auto");
49923 this.bodyEl.setStyle("overflow", "hidden");
49925 //if(c.titlebar !== false){
49926 if((!c.titlebar && !c.title) || c.titlebar === false){
49927 this.titleEl.hide();
49929 this.titleEl.show();
49931 this.titleTextEl.innerHTML = c.title;
49935 this.duration = c.duration || .30;
49936 this.slideDuration = c.slideDuration || .45;
49939 this.collapse(true);
49946 * Returns true if this region is currently visible.
49947 * @return {Boolean}
49949 isVisible : function(){
49950 return this.visible;
49954 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49955 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49957 setCollapsedTitle : function(title){
49958 title = title || " ";
49959 if(this.collapsedTitleTextEl){
49960 this.collapsedTitleTextEl.innerHTML = title;
49964 getBox : function(){
49966 if(!this.collapsed){
49967 b = this.el.getBox(false, true);
49969 b = this.collapsedEl.getBox(false, true);
49974 getMargins : function(){
49975 return this.collapsed ? this.cmargins : this.margins;
49978 highlight : function(){
49979 this.el.addClass("x-layout-panel-dragover");
49982 unhighlight : function(){
49983 this.el.removeClass("x-layout-panel-dragover");
49986 updateBox : function(box){
49988 if(!this.collapsed){
49989 this.el.dom.style.left = box.x + "px";
49990 this.el.dom.style.top = box.y + "px";
49991 this.updateBody(box.width, box.height);
49993 this.collapsedEl.dom.style.left = box.x + "px";
49994 this.collapsedEl.dom.style.top = box.y + "px";
49995 this.collapsedEl.setSize(box.width, box.height);
49998 this.tabs.autoSizeTabs();
50002 updateBody : function(w, h){
50004 this.el.setWidth(w);
50005 w -= this.el.getBorderWidth("rl");
50006 if(this.config.adjustments){
50007 w += this.config.adjustments[0];
50011 this.el.setHeight(h);
50012 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50013 h -= this.el.getBorderWidth("tb");
50014 if(this.config.adjustments){
50015 h += this.config.adjustments[1];
50017 this.bodyEl.setHeight(h);
50019 h = this.tabs.syncHeight(h);
50022 if(this.panelSize){
50023 w = w !== null ? w : this.panelSize.width;
50024 h = h !== null ? h : this.panelSize.height;
50026 if(this.activePanel){
50027 var el = this.activePanel.getEl();
50028 w = w !== null ? w : el.getWidth();
50029 h = h !== null ? h : el.getHeight();
50030 this.panelSize = {width: w, height: h};
50031 this.activePanel.setSize(w, h);
50033 if(Roo.isIE && this.tabs){
50034 this.tabs.el.repaint();
50039 * Returns the container element for this region.
50040 * @return {Roo.Element}
50042 getEl : function(){
50047 * Hides this region.
50050 if(!this.collapsed){
50051 this.el.dom.style.left = "-2000px";
50054 this.collapsedEl.dom.style.left = "-2000px";
50055 this.collapsedEl.hide();
50057 this.visible = false;
50058 this.fireEvent("visibilitychange", this, false);
50062 * Shows this region if it was previously hidden.
50065 if(!this.collapsed){
50068 this.collapsedEl.show();
50070 this.visible = true;
50071 this.fireEvent("visibilitychange", this, true);
50074 closeClicked : function(){
50075 if(this.activePanel){
50076 this.remove(this.activePanel);
50080 collapseClick : function(e){
50082 e.stopPropagation();
50085 e.stopPropagation();
50091 * Collapses this region.
50092 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50094 collapse : function(skipAnim){
50095 if(this.collapsed) return;
50096 this.collapsed = true;
50098 this.split.el.hide();
50100 if(this.config.animate && skipAnim !== true){
50101 this.fireEvent("invalidated", this);
50102 this.animateCollapse();
50104 this.el.setLocation(-20000,-20000);
50106 this.collapsedEl.show();
50107 this.fireEvent("collapsed", this);
50108 this.fireEvent("invalidated", this);
50112 animateCollapse : function(){
50117 * Expands this region if it was previously collapsed.
50118 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50119 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50121 expand : function(e, skipAnim){
50122 if(e) e.stopPropagation();
50123 if(!this.collapsed || this.el.hasActiveFx()) return;
50125 this.afterSlideIn();
50128 this.collapsed = false;
50129 if(this.config.animate && skipAnim !== true){
50130 this.animateExpand();
50134 this.split.el.show();
50136 this.collapsedEl.setLocation(-2000,-2000);
50137 this.collapsedEl.hide();
50138 this.fireEvent("invalidated", this);
50139 this.fireEvent("expanded", this);
50143 animateExpand : function(){
50147 initTabs : function()
50149 this.bodyEl.setStyle("overflow", "hidden");
50150 var ts = new Roo.TabPanel(
50153 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50154 disableTooltips: this.config.disableTabTips,
50155 toolbar : this.config.toolbar
50158 if(this.config.hideTabs){
50159 ts.stripWrap.setDisplayed(false);
50162 ts.resizeTabs = this.config.resizeTabs === true;
50163 ts.minTabWidth = this.config.minTabWidth || 40;
50164 ts.maxTabWidth = this.config.maxTabWidth || 250;
50165 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50166 ts.monitorResize = false;
50167 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50168 ts.bodyEl.addClass('x-layout-tabs-body');
50169 this.panels.each(this.initPanelAsTab, this);
50172 initPanelAsTab : function(panel){
50173 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50174 this.config.closeOnTab && panel.isClosable());
50175 if(panel.tabTip !== undefined){
50176 ti.setTooltip(panel.tabTip);
50178 ti.on("activate", function(){
50179 this.setActivePanel(panel);
50181 if(this.config.closeOnTab){
50182 ti.on("beforeclose", function(t, e){
50184 this.remove(panel);
50190 updatePanelTitle : function(panel, title){
50191 if(this.activePanel == panel){
50192 this.updateTitle(title);
50195 var ti = this.tabs.getTab(panel.getEl().id);
50197 if(panel.tabTip !== undefined){
50198 ti.setTooltip(panel.tabTip);
50203 updateTitle : function(title){
50204 if(this.titleTextEl && !this.config.title){
50205 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50209 setActivePanel : function(panel){
50210 panel = this.getPanel(panel);
50211 if(this.activePanel && this.activePanel != panel){
50212 this.activePanel.setActiveState(false);
50214 this.activePanel = panel;
50215 panel.setActiveState(true);
50216 if(this.panelSize){
50217 panel.setSize(this.panelSize.width, this.panelSize.height);
50220 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50222 this.updateTitle(panel.getTitle());
50224 this.fireEvent("invalidated", this);
50226 this.fireEvent("panelactivated", this, panel);
50230 * Shows the specified panel.
50231 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50232 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50234 showPanel : function(panel){
50235 if(panel = this.getPanel(panel)){
50237 var tab = this.tabs.getTab(panel.getEl().id);
50238 if(tab.isHidden()){
50239 this.tabs.unhideTab(tab.id);
50243 this.setActivePanel(panel);
50250 * Get the active panel for this region.
50251 * @return {Roo.ContentPanel} The active panel or null
50253 getActivePanel : function(){
50254 return this.activePanel;
50257 validateVisibility : function(){
50258 if(this.panels.getCount() < 1){
50259 this.updateTitle(" ");
50260 this.closeBtn.hide();
50263 if(!this.isVisible()){
50270 * Adds the passed ContentPanel(s) to this region.
50271 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50272 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50274 add : function(panel){
50275 if(arguments.length > 1){
50276 for(var i = 0, len = arguments.length; i < len; i++) {
50277 this.add(arguments[i]);
50281 if(this.hasPanel(panel)){
50282 this.showPanel(panel);
50285 panel.setRegion(this);
50286 this.panels.add(panel);
50287 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50288 this.bodyEl.dom.appendChild(panel.getEl().dom);
50289 if(panel.background !== true){
50290 this.setActivePanel(panel);
50292 this.fireEvent("paneladded", this, panel);
50298 this.initPanelAsTab(panel);
50300 if(panel.background !== true){
50301 this.tabs.activate(panel.getEl().id);
50303 this.fireEvent("paneladded", this, panel);
50308 * Hides the tab for the specified panel.
50309 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50311 hidePanel : function(panel){
50312 if(this.tabs && (panel = this.getPanel(panel))){
50313 this.tabs.hideTab(panel.getEl().id);
50318 * Unhides the tab for a previously hidden panel.
50319 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50321 unhidePanel : function(panel){
50322 if(this.tabs && (panel = this.getPanel(panel))){
50323 this.tabs.unhideTab(panel.getEl().id);
50327 clearPanels : function(){
50328 while(this.panels.getCount() > 0){
50329 this.remove(this.panels.first());
50334 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50335 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50336 * @param {Boolean} preservePanel Overrides the config preservePanel option
50337 * @return {Roo.ContentPanel} The panel that was removed
50339 remove : function(panel, preservePanel){
50340 panel = this.getPanel(panel);
50345 this.fireEvent("beforeremove", this, panel, e);
50346 if(e.cancel === true){
50349 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50350 var panelId = panel.getId();
50351 this.panels.removeKey(panelId);
50353 document.body.appendChild(panel.getEl().dom);
50356 this.tabs.removeTab(panel.getEl().id);
50357 }else if (!preservePanel){
50358 this.bodyEl.dom.removeChild(panel.getEl().dom);
50360 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50361 var p = this.panels.first();
50362 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50363 tempEl.appendChild(p.getEl().dom);
50364 this.bodyEl.update("");
50365 this.bodyEl.dom.appendChild(p.getEl().dom);
50367 this.updateTitle(p.getTitle());
50369 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50370 this.setActivePanel(p);
50372 panel.setRegion(null);
50373 if(this.activePanel == panel){
50374 this.activePanel = null;
50376 if(this.config.autoDestroy !== false && preservePanel !== true){
50377 try{panel.destroy();}catch(e){}
50379 this.fireEvent("panelremoved", this, panel);
50384 * Returns the TabPanel component used by this region
50385 * @return {Roo.TabPanel}
50387 getTabs : function(){
50391 createTool : function(parentEl, className){
50392 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50393 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50394 btn.addClassOnOver("x-layout-tools-button-over");
50399 * Ext JS Library 1.1.1
50400 * Copyright(c) 2006-2007, Ext JS, LLC.
50402 * Originally Released Under LGPL - original licence link has changed is not relivant.
50405 * <script type="text/javascript">
50411 * @class Roo.SplitLayoutRegion
50412 * @extends Roo.LayoutRegion
50413 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50415 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50416 this.cursor = cursor;
50417 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50420 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50421 splitTip : "Drag to resize.",
50422 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50423 useSplitTips : false,
50425 applyConfig : function(config){
50426 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50429 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50430 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50431 /** The SplitBar for this region
50432 * @type Roo.SplitBar */
50433 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50434 this.split.on("moved", this.onSplitMove, this);
50435 this.split.useShim = config.useShim === true;
50436 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50437 if(this.useSplitTips){
50438 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50440 if(config.collapsible){
50441 this.split.el.on("dblclick", this.collapse, this);
50444 if(typeof config.minSize != "undefined"){
50445 this.split.minSize = config.minSize;
50447 if(typeof config.maxSize != "undefined"){
50448 this.split.maxSize = config.maxSize;
50450 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50451 this.hideSplitter();
50456 getHMaxSize : function(){
50457 var cmax = this.config.maxSize || 10000;
50458 var center = this.mgr.getRegion("center");
50459 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50462 getVMaxSize : function(){
50463 var cmax = this.config.maxSize || 10000;
50464 var center = this.mgr.getRegion("center");
50465 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50468 onSplitMove : function(split, newSize){
50469 this.fireEvent("resized", this, newSize);
50473 * Returns the {@link Roo.SplitBar} for this region.
50474 * @return {Roo.SplitBar}
50476 getSplitBar : function(){
50481 this.hideSplitter();
50482 Roo.SplitLayoutRegion.superclass.hide.call(this);
50485 hideSplitter : function(){
50487 this.split.el.setLocation(-2000,-2000);
50488 this.split.el.hide();
50494 this.split.el.show();
50496 Roo.SplitLayoutRegion.superclass.show.call(this);
50499 beforeSlide: function(){
50500 if(Roo.isGecko){// firefox overflow auto bug workaround
50501 this.bodyEl.clip();
50502 if(this.tabs) this.tabs.bodyEl.clip();
50503 if(this.activePanel){
50504 this.activePanel.getEl().clip();
50506 if(this.activePanel.beforeSlide){
50507 this.activePanel.beforeSlide();
50513 afterSlide : function(){
50514 if(Roo.isGecko){// firefox overflow auto bug workaround
50515 this.bodyEl.unclip();
50516 if(this.tabs) this.tabs.bodyEl.unclip();
50517 if(this.activePanel){
50518 this.activePanel.getEl().unclip();
50519 if(this.activePanel.afterSlide){
50520 this.activePanel.afterSlide();
50526 initAutoHide : function(){
50527 if(this.autoHide !== false){
50528 if(!this.autoHideHd){
50529 var st = new Roo.util.DelayedTask(this.slideIn, this);
50530 this.autoHideHd = {
50531 "mouseout": function(e){
50532 if(!e.within(this.el, true)){
50536 "mouseover" : function(e){
50542 this.el.on(this.autoHideHd);
50546 clearAutoHide : function(){
50547 if(this.autoHide !== false){
50548 this.el.un("mouseout", this.autoHideHd.mouseout);
50549 this.el.un("mouseover", this.autoHideHd.mouseover);
50553 clearMonitor : function(){
50554 Roo.get(document).un("click", this.slideInIf, this);
50557 // these names are backwards but not changed for compat
50558 slideOut : function(){
50559 if(this.isSlid || this.el.hasActiveFx()){
50562 this.isSlid = true;
50563 if(this.collapseBtn){
50564 this.collapseBtn.hide();
50566 this.closeBtnState = this.closeBtn.getStyle('display');
50567 this.closeBtn.hide();
50569 this.stickBtn.show();
50572 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50573 this.beforeSlide();
50574 this.el.setStyle("z-index", 10001);
50575 this.el.slideIn(this.getSlideAnchor(), {
50576 callback: function(){
50578 this.initAutoHide();
50579 Roo.get(document).on("click", this.slideInIf, this);
50580 this.fireEvent("slideshow", this);
50587 afterSlideIn : function(){
50588 this.clearAutoHide();
50589 this.isSlid = false;
50590 this.clearMonitor();
50591 this.el.setStyle("z-index", "");
50592 if(this.collapseBtn){
50593 this.collapseBtn.show();
50595 this.closeBtn.setStyle('display', this.closeBtnState);
50597 this.stickBtn.hide();
50599 this.fireEvent("slidehide", this);
50602 slideIn : function(cb){
50603 if(!this.isSlid || this.el.hasActiveFx()){
50607 this.isSlid = false;
50608 this.beforeSlide();
50609 this.el.slideOut(this.getSlideAnchor(), {
50610 callback: function(){
50611 this.el.setLeftTop(-10000, -10000);
50613 this.afterSlideIn();
50621 slideInIf : function(e){
50622 if(!e.within(this.el)){
50627 animateCollapse : function(){
50628 this.beforeSlide();
50629 this.el.setStyle("z-index", 20000);
50630 var anchor = this.getSlideAnchor();
50631 this.el.slideOut(anchor, {
50632 callback : function(){
50633 this.el.setStyle("z-index", "");
50634 this.collapsedEl.slideIn(anchor, {duration:.3});
50636 this.el.setLocation(-10000,-10000);
50638 this.fireEvent("collapsed", this);
50645 animateExpand : function(){
50646 this.beforeSlide();
50647 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50648 this.el.setStyle("z-index", 20000);
50649 this.collapsedEl.hide({
50652 this.el.slideIn(this.getSlideAnchor(), {
50653 callback : function(){
50654 this.el.setStyle("z-index", "");
50657 this.split.el.show();
50659 this.fireEvent("invalidated", this);
50660 this.fireEvent("expanded", this);
50688 getAnchor : function(){
50689 return this.anchors[this.position];
50692 getCollapseAnchor : function(){
50693 return this.canchors[this.position];
50696 getSlideAnchor : function(){
50697 return this.sanchors[this.position];
50700 getAlignAdj : function(){
50701 var cm = this.cmargins;
50702 switch(this.position){
50718 getExpandAdj : function(){
50719 var c = this.collapsedEl, cm = this.cmargins;
50720 switch(this.position){
50722 return [-(cm.right+c.getWidth()+cm.left), 0];
50725 return [cm.right+c.getWidth()+cm.left, 0];
50728 return [0, -(cm.top+cm.bottom+c.getHeight())];
50731 return [0, cm.top+cm.bottom+c.getHeight()];
50737 * Ext JS Library 1.1.1
50738 * Copyright(c) 2006-2007, Ext JS, LLC.
50740 * Originally Released Under LGPL - original licence link has changed is not relivant.
50743 * <script type="text/javascript">
50746 * These classes are private internal classes
50748 Roo.CenterLayoutRegion = function(mgr, config){
50749 Roo.LayoutRegion.call(this, mgr, config, "center");
50750 this.visible = true;
50751 this.minWidth = config.minWidth || 20;
50752 this.minHeight = config.minHeight || 20;
50755 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50757 // center panel can't be hidden
50761 // center panel can't be hidden
50764 getMinWidth: function(){
50765 return this.minWidth;
50768 getMinHeight: function(){
50769 return this.minHeight;
50774 Roo.NorthLayoutRegion = function(mgr, config){
50775 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50777 this.split.placement = Roo.SplitBar.TOP;
50778 this.split.orientation = Roo.SplitBar.VERTICAL;
50779 this.split.el.addClass("x-layout-split-v");
50781 var size = config.initialSize || config.height;
50782 if(typeof size != "undefined"){
50783 this.el.setHeight(size);
50786 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50787 orientation: Roo.SplitBar.VERTICAL,
50788 getBox : function(){
50789 if(this.collapsed){
50790 return this.collapsedEl.getBox();
50792 var box = this.el.getBox();
50794 box.height += this.split.el.getHeight();
50799 updateBox : function(box){
50800 if(this.split && !this.collapsed){
50801 box.height -= this.split.el.getHeight();
50802 this.split.el.setLeft(box.x);
50803 this.split.el.setTop(box.y+box.height);
50804 this.split.el.setWidth(box.width);
50806 if(this.collapsed){
50807 this.updateBody(box.width, null);
50809 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50813 Roo.SouthLayoutRegion = function(mgr, config){
50814 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50816 this.split.placement = Roo.SplitBar.BOTTOM;
50817 this.split.orientation = Roo.SplitBar.VERTICAL;
50818 this.split.el.addClass("x-layout-split-v");
50820 var size = config.initialSize || config.height;
50821 if(typeof size != "undefined"){
50822 this.el.setHeight(size);
50825 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50826 orientation: Roo.SplitBar.VERTICAL,
50827 getBox : function(){
50828 if(this.collapsed){
50829 return this.collapsedEl.getBox();
50831 var box = this.el.getBox();
50833 var sh = this.split.el.getHeight();
50840 updateBox : function(box){
50841 if(this.split && !this.collapsed){
50842 var sh = this.split.el.getHeight();
50845 this.split.el.setLeft(box.x);
50846 this.split.el.setTop(box.y-sh);
50847 this.split.el.setWidth(box.width);
50849 if(this.collapsed){
50850 this.updateBody(box.width, null);
50852 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50856 Roo.EastLayoutRegion = function(mgr, config){
50857 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50859 this.split.placement = Roo.SplitBar.RIGHT;
50860 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50861 this.split.el.addClass("x-layout-split-h");
50863 var size = config.initialSize || config.width;
50864 if(typeof size != "undefined"){
50865 this.el.setWidth(size);
50868 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50869 orientation: Roo.SplitBar.HORIZONTAL,
50870 getBox : function(){
50871 if(this.collapsed){
50872 return this.collapsedEl.getBox();
50874 var box = this.el.getBox();
50876 var sw = this.split.el.getWidth();
50883 updateBox : function(box){
50884 if(this.split && !this.collapsed){
50885 var sw = this.split.el.getWidth();
50887 this.split.el.setLeft(box.x);
50888 this.split.el.setTop(box.y);
50889 this.split.el.setHeight(box.height);
50892 if(this.collapsed){
50893 this.updateBody(null, box.height);
50895 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50899 Roo.WestLayoutRegion = function(mgr, config){
50900 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50902 this.split.placement = Roo.SplitBar.LEFT;
50903 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50904 this.split.el.addClass("x-layout-split-h");
50906 var size = config.initialSize || config.width;
50907 if(typeof size != "undefined"){
50908 this.el.setWidth(size);
50911 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50912 orientation: Roo.SplitBar.HORIZONTAL,
50913 getBox : function(){
50914 if(this.collapsed){
50915 return this.collapsedEl.getBox();
50917 var box = this.el.getBox();
50919 box.width += this.split.el.getWidth();
50924 updateBox : function(box){
50925 if(this.split && !this.collapsed){
50926 var sw = this.split.el.getWidth();
50928 this.split.el.setLeft(box.x+box.width);
50929 this.split.el.setTop(box.y);
50930 this.split.el.setHeight(box.height);
50932 if(this.collapsed){
50933 this.updateBody(null, box.height);
50935 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50940 * Ext JS Library 1.1.1
50941 * Copyright(c) 2006-2007, Ext JS, LLC.
50943 * Originally Released Under LGPL - original licence link has changed is not relivant.
50946 * <script type="text/javascript">
50951 * Private internal class for reading and applying state
50953 Roo.LayoutStateManager = function(layout){
50954 // default empty state
50963 Roo.LayoutStateManager.prototype = {
50964 init : function(layout, provider){
50965 this.provider = provider;
50966 var state = provider.get(layout.id+"-layout-state");
50968 var wasUpdating = layout.isUpdating();
50970 layout.beginUpdate();
50972 for(var key in state){
50973 if(typeof state[key] != "function"){
50974 var rstate = state[key];
50975 var r = layout.getRegion(key);
50978 r.resizeTo(rstate.size);
50980 if(rstate.collapsed == true){
50983 r.expand(null, true);
50989 layout.endUpdate();
50991 this.state = state;
50993 this.layout = layout;
50994 layout.on("regionresized", this.onRegionResized, this);
50995 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50996 layout.on("regionexpanded", this.onRegionExpanded, this);
50999 storeState : function(){
51000 this.provider.set(this.layout.id+"-layout-state", this.state);
51003 onRegionResized : function(region, newSize){
51004 this.state[region.getPosition()].size = newSize;
51008 onRegionCollapsed : function(region){
51009 this.state[region.getPosition()].collapsed = true;
51013 onRegionExpanded : function(region){
51014 this.state[region.getPosition()].collapsed = false;
51019 * Ext JS Library 1.1.1
51020 * Copyright(c) 2006-2007, Ext JS, LLC.
51022 * Originally Released Under LGPL - original licence link has changed is not relivant.
51025 * <script type="text/javascript">
51028 * @class Roo.ContentPanel
51029 * @extends Roo.util.Observable
51030 * A basic ContentPanel element.
51031 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51032 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51033 * @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
51034 * @cfg {Boolean} closable True if the panel can be closed/removed
51035 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51036 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51037 * @cfg {Toolbar} toolbar A toolbar for this panel
51038 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51039 * @cfg {String} title The title for this panel
51040 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51041 * @cfg {String} url Calls {@link #setUrl} with this value
51042 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51043 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51044 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51045 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51048 * Create a new ContentPanel.
51049 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51050 * @param {String/Object} config A string to set only the title or a config object
51051 * @param {String} content (optional) Set the HTML content for this panel
51052 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51054 Roo.ContentPanel = function(el, config, content){
51058 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51062 if (config && config.parentLayout) {
51063 el = config.parentLayout.el.createChild();
51066 if(el.autoCreate){ // xtype is available if this is called from factory
51070 this.el = Roo.get(el);
51071 if(!this.el && config && config.autoCreate){
51072 if(typeof config.autoCreate == "object"){
51073 if(!config.autoCreate.id){
51074 config.autoCreate.id = config.id||el;
51076 this.el = Roo.DomHelper.append(document.body,
51077 config.autoCreate, true);
51079 this.el = Roo.DomHelper.append(document.body,
51080 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51083 this.closable = false;
51084 this.loaded = false;
51085 this.active = false;
51086 if(typeof config == "string"){
51087 this.title = config;
51089 Roo.apply(this, config);
51092 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51093 this.wrapEl = this.el.wrap();
51094 this.toolbar.container = this.el.insertSibling(false, 'before');
51095 this.toolbar = new Roo.Toolbar(this.toolbar);
51098 // xtype created footer. - not sure if will work as we normally have to render first..
51099 if (this.footer && !this.footer.el && this.footer.xtype) {
51100 if (!this.wrapEl) {
51101 this.wrapEl = this.el.wrap();
51104 this.footer.container = this.wrapEl.createChild();
51106 this.footer = Roo.factory(this.footer, Roo);
51111 this.resizeEl = Roo.get(this.resizeEl, true);
51113 this.resizeEl = this.el;
51115 // handle view.xtype
51123 * Fires when this panel is activated.
51124 * @param {Roo.ContentPanel} this
51128 * @event deactivate
51129 * Fires when this panel is activated.
51130 * @param {Roo.ContentPanel} this
51132 "deactivate" : true,
51136 * Fires when this panel is resized if fitToFrame is true.
51137 * @param {Roo.ContentPanel} this
51138 * @param {Number} width The width after any component adjustments
51139 * @param {Number} height The height after any component adjustments
51145 * Fires when this tab is created
51146 * @param {Roo.ContentPanel} this
51157 if(this.autoScroll){
51158 this.resizeEl.setStyle("overflow", "auto");
51160 // fix randome scrolling
51161 this.el.on('scroll', function() {
51162 Roo.log('fix random scolling');
51163 this.scrollTo('top',0);
51166 content = content || this.content;
51168 this.setContent(content);
51170 if(config && config.url){
51171 this.setUrl(this.url, this.params, this.loadOnce);
51176 Roo.ContentPanel.superclass.constructor.call(this);
51178 if (this.view && typeof(this.view.xtype) != 'undefined') {
51179 this.view.el = this.el.appendChild(document.createElement("div"));
51180 this.view = Roo.factory(this.view);
51181 this.view.render && this.view.render(false, '');
51185 this.fireEvent('render', this);
51188 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51190 setRegion : function(region){
51191 this.region = region;
51193 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51195 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51200 * Returns the toolbar for this Panel if one was configured.
51201 * @return {Roo.Toolbar}
51203 getToolbar : function(){
51204 return this.toolbar;
51207 setActiveState : function(active){
51208 this.active = active;
51210 this.fireEvent("deactivate", this);
51212 this.fireEvent("activate", this);
51216 * Updates this panel's element
51217 * @param {String} content The new content
51218 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51220 setContent : function(content, loadScripts){
51221 this.el.update(content, loadScripts);
51224 ignoreResize : function(w, h){
51225 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51228 this.lastSize = {width: w, height: h};
51233 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51234 * @return {Roo.UpdateManager} The UpdateManager
51236 getUpdateManager : function(){
51237 return this.el.getUpdateManager();
51240 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51241 * @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:
51244 url: "your-url.php",
51245 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51246 callback: yourFunction,
51247 scope: yourObject, //(optional scope)
51250 text: "Loading...",
51255 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51256 * 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.
51257 * @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}
51258 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51259 * @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.
51260 * @return {Roo.ContentPanel} this
51263 var um = this.el.getUpdateManager();
51264 um.update.apply(um, arguments);
51270 * 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.
51271 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51272 * @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)
51273 * @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)
51274 * @return {Roo.UpdateManager} The UpdateManager
51276 setUrl : function(url, params, loadOnce){
51277 if(this.refreshDelegate){
51278 this.removeListener("activate", this.refreshDelegate);
51280 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51281 this.on("activate", this.refreshDelegate);
51282 return this.el.getUpdateManager();
51285 _handleRefresh : function(url, params, loadOnce){
51286 if(!loadOnce || !this.loaded){
51287 var updater = this.el.getUpdateManager();
51288 updater.update(url, params, this._setLoaded.createDelegate(this));
51292 _setLoaded : function(){
51293 this.loaded = true;
51297 * Returns this panel's id
51300 getId : function(){
51305 * Returns this panel's element - used by regiosn to add.
51306 * @return {Roo.Element}
51308 getEl : function(){
51309 return this.wrapEl || this.el;
51312 adjustForComponents : function(width, height)
51314 //Roo.log('adjustForComponents ');
51315 if(this.resizeEl != this.el){
51316 width -= this.el.getFrameWidth('lr');
51317 height -= this.el.getFrameWidth('tb');
51320 var te = this.toolbar.getEl();
51321 height -= te.getHeight();
51322 te.setWidth(width);
51325 var te = this.footer.getEl();
51326 Roo.log("footer:" + te.getHeight());
51328 height -= te.getHeight();
51329 te.setWidth(width);
51333 if(this.adjustments){
51334 width += this.adjustments[0];
51335 height += this.adjustments[1];
51337 return {"width": width, "height": height};
51340 setSize : function(width, height){
51341 if(this.fitToFrame && !this.ignoreResize(width, height)){
51342 if(this.fitContainer && this.resizeEl != this.el){
51343 this.el.setSize(width, height);
51345 var size = this.adjustForComponents(width, height);
51346 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51347 this.fireEvent('resize', this, size.width, size.height);
51352 * Returns this panel's title
51355 getTitle : function(){
51360 * Set this panel's title
51361 * @param {String} title
51363 setTitle : function(title){
51364 this.title = title;
51366 this.region.updatePanelTitle(this, title);
51371 * Returns true is this panel was configured to be closable
51372 * @return {Boolean}
51374 isClosable : function(){
51375 return this.closable;
51378 beforeSlide : function(){
51380 this.resizeEl.clip();
51383 afterSlide : function(){
51385 this.resizeEl.unclip();
51389 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51390 * Will fail silently if the {@link #setUrl} method has not been called.
51391 * This does not activate the panel, just updates its content.
51393 refresh : function(){
51394 if(this.refreshDelegate){
51395 this.loaded = false;
51396 this.refreshDelegate();
51401 * Destroys this panel
51403 destroy : function(){
51404 this.el.removeAllListeners();
51405 var tempEl = document.createElement("span");
51406 tempEl.appendChild(this.el.dom);
51407 tempEl.innerHTML = "";
51413 * form - if the content panel contains a form - this is a reference to it.
51414 * @type {Roo.form.Form}
51418 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51419 * This contains a reference to it.
51425 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51435 * @param {Object} cfg Xtype definition of item to add.
51438 addxtype : function(cfg) {
51440 if (cfg.xtype.match(/^Form$/)) {
51443 //if (this.footer) {
51444 // el = this.footer.container.insertSibling(false, 'before');
51446 el = this.el.createChild();
51449 this.form = new Roo.form.Form(cfg);
51452 if ( this.form.allItems.length) this.form.render(el.dom);
51455 // should only have one of theses..
51456 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51457 // views.. should not be just added - used named prop 'view''
51459 cfg.el = this.el.appendChild(document.createElement("div"));
51462 var ret = new Roo.factory(cfg);
51464 ret.render && ret.render(false, ''); // render blank..
51473 * @class Roo.GridPanel
51474 * @extends Roo.ContentPanel
51476 * Create a new GridPanel.
51477 * @param {Roo.grid.Grid} grid The grid for this panel
51478 * @param {String/Object} config A string to set only the panel's title, or a config object
51480 Roo.GridPanel = function(grid, config){
51483 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51484 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51486 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51488 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51491 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51493 // xtype created footer. - not sure if will work as we normally have to render first..
51494 if (this.footer && !this.footer.el && this.footer.xtype) {
51496 this.footer.container = this.grid.getView().getFooterPanel(true);
51497 this.footer.dataSource = this.grid.dataSource;
51498 this.footer = Roo.factory(this.footer, Roo);
51502 grid.monitorWindowResize = false; // turn off autosizing
51503 grid.autoHeight = false;
51504 grid.autoWidth = false;
51506 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51509 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51510 getId : function(){
51511 return this.grid.id;
51515 * Returns the grid for this panel
51516 * @return {Roo.grid.Grid}
51518 getGrid : function(){
51522 setSize : function(width, height){
51523 if(!this.ignoreResize(width, height)){
51524 var grid = this.grid;
51525 var size = this.adjustForComponents(width, height);
51526 grid.getGridEl().setSize(size.width, size.height);
51531 beforeSlide : function(){
51532 this.grid.getView().scroller.clip();
51535 afterSlide : function(){
51536 this.grid.getView().scroller.unclip();
51539 destroy : function(){
51540 this.grid.destroy();
51542 Roo.GridPanel.superclass.destroy.call(this);
51548 * @class Roo.NestedLayoutPanel
51549 * @extends Roo.ContentPanel
51551 * Create a new NestedLayoutPanel.
51554 * @param {Roo.BorderLayout} layout The layout for this panel
51555 * @param {String/Object} config A string to set only the title or a config object
51557 Roo.NestedLayoutPanel = function(layout, config)
51559 // construct with only one argument..
51560 /* FIXME - implement nicer consturctors
51561 if (layout.layout) {
51563 layout = config.layout;
51564 delete config.layout;
51566 if (layout.xtype && !layout.getEl) {
51567 // then layout needs constructing..
51568 layout = Roo.factory(layout, Roo);
51573 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51575 layout.monitorWindowResize = false; // turn off autosizing
51576 this.layout = layout;
51577 this.layout.getEl().addClass("x-layout-nested-layout");
51584 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51586 setSize : function(width, height){
51587 if(!this.ignoreResize(width, height)){
51588 var size = this.adjustForComponents(width, height);
51589 var el = this.layout.getEl();
51590 el.setSize(size.width, size.height);
51591 var touch = el.dom.offsetWidth;
51592 this.layout.layout();
51593 // ie requires a double layout on the first pass
51594 if(Roo.isIE && !this.initialized){
51595 this.initialized = true;
51596 this.layout.layout();
51601 // activate all subpanels if not currently active..
51603 setActiveState : function(active){
51604 this.active = active;
51606 this.fireEvent("deactivate", this);
51610 this.fireEvent("activate", this);
51611 // not sure if this should happen before or after..
51612 if (!this.layout) {
51613 return; // should not happen..
51616 for (var r in this.layout.regions) {
51617 reg = this.layout.getRegion(r);
51618 if (reg.getActivePanel()) {
51619 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51620 reg.setActivePanel(reg.getActivePanel());
51623 if (!reg.panels.length) {
51626 reg.showPanel(reg.getPanel(0));
51635 * Returns the nested BorderLayout for this panel
51636 * @return {Roo.BorderLayout}
51638 getLayout : function(){
51639 return this.layout;
51643 * Adds a xtype elements to the layout of the nested panel
51647 xtype : 'ContentPanel',
51654 xtype : 'NestedLayoutPanel',
51660 items : [ ... list of content panels or nested layout panels.. ]
51664 * @param {Object} cfg Xtype definition of item to add.
51666 addxtype : function(cfg) {
51667 return this.layout.addxtype(cfg);
51672 Roo.ScrollPanel = function(el, config, content){
51673 config = config || {};
51674 config.fitToFrame = true;
51675 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51677 this.el.dom.style.overflow = "hidden";
51678 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51679 this.el.removeClass("x-layout-inactive-content");
51680 this.el.on("mousewheel", this.onWheel, this);
51682 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51683 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51684 up.unselectable(); down.unselectable();
51685 up.on("click", this.scrollUp, this);
51686 down.on("click", this.scrollDown, this);
51687 up.addClassOnOver("x-scroller-btn-over");
51688 down.addClassOnOver("x-scroller-btn-over");
51689 up.addClassOnClick("x-scroller-btn-click");
51690 down.addClassOnClick("x-scroller-btn-click");
51691 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51693 this.resizeEl = this.el;
51694 this.el = wrap; this.up = up; this.down = down;
51697 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51699 wheelIncrement : 5,
51700 scrollUp : function(){
51701 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51704 scrollDown : function(){
51705 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51708 afterScroll : function(){
51709 var el = this.resizeEl;
51710 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51711 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51712 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51715 setSize : function(){
51716 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51717 this.afterScroll();
51720 onWheel : function(e){
51721 var d = e.getWheelDelta();
51722 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51723 this.afterScroll();
51727 setContent : function(content, loadScripts){
51728 this.resizeEl.update(content, loadScripts);
51742 * @class Roo.TreePanel
51743 * @extends Roo.ContentPanel
51745 * Create a new TreePanel. - defaults to fit/scoll contents.
51746 * @param {String/Object} config A string to set only the panel's title, or a config object
51747 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51749 Roo.TreePanel = function(config){
51750 var el = config.el;
51751 var tree = config.tree;
51752 delete config.tree;
51753 delete config.el; // hopefull!
51755 // wrapper for IE7 strict & safari scroll issue
51757 var treeEl = el.createChild();
51758 config.resizeEl = treeEl;
51762 Roo.TreePanel.superclass.constructor.call(this, el, config);
51765 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51766 //console.log(tree);
51767 this.on('activate', function()
51769 if (this.tree.rendered) {
51772 //console.log('render tree');
51773 this.tree.render();
51775 // this should not be needed.. - it's actually the 'el' that resizes?
51776 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51778 //this.on('resize', function (cp, w, h) {
51779 // this.tree.innerCt.setWidth(w);
51780 // this.tree.innerCt.setHeight(h);
51781 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51788 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51805 * Ext JS Library 1.1.1
51806 * Copyright(c) 2006-2007, Ext JS, LLC.
51808 * Originally Released Under LGPL - original licence link has changed is not relivant.
51811 * <script type="text/javascript">
51816 * @class Roo.ReaderLayout
51817 * @extends Roo.BorderLayout
51818 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51819 * center region containing two nested regions (a top one for a list view and one for item preview below),
51820 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51821 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51822 * expedites the setup of the overall layout and regions for this common application style.
51825 var reader = new Roo.ReaderLayout();
51826 var CP = Roo.ContentPanel; // shortcut for adding
51828 reader.beginUpdate();
51829 reader.add("north", new CP("north", "North"));
51830 reader.add("west", new CP("west", {title: "West"}));
51831 reader.add("east", new CP("east", {title: "East"}));
51833 reader.regions.listView.add(new CP("listView", "List"));
51834 reader.regions.preview.add(new CP("preview", "Preview"));
51835 reader.endUpdate();
51838 * Create a new ReaderLayout
51839 * @param {Object} config Configuration options
51840 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51841 * document.body if omitted)
51843 Roo.ReaderLayout = function(config, renderTo){
51844 var c = config || {size:{}};
51845 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51846 north: c.north !== false ? Roo.apply({
51850 }, c.north) : false,
51851 west: c.west !== false ? Roo.apply({
51859 margins:{left:5,right:0,bottom:5,top:5},
51860 cmargins:{left:5,right:5,bottom:5,top:5}
51861 }, c.west) : false,
51862 east: c.east !== false ? Roo.apply({
51870 margins:{left:0,right:5,bottom:5,top:5},
51871 cmargins:{left:5,right:5,bottom:5,top:5}
51872 }, c.east) : false,
51873 center: Roo.apply({
51874 tabPosition: 'top',
51878 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51882 this.el.addClass('x-reader');
51884 this.beginUpdate();
51886 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51887 south: c.preview !== false ? Roo.apply({
51894 cmargins:{top:5,left:0, right:0, bottom:0}
51895 }, c.preview) : false,
51896 center: Roo.apply({
51902 this.add('center', new Roo.NestedLayoutPanel(inner,
51903 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51907 this.regions.preview = inner.getRegion('south');
51908 this.regions.listView = inner.getRegion('center');
51911 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51913 * Ext JS Library 1.1.1
51914 * Copyright(c) 2006-2007, Ext JS, LLC.
51916 * Originally Released Under LGPL - original licence link has changed is not relivant.
51919 * <script type="text/javascript">
51923 * @class Roo.grid.Grid
51924 * @extends Roo.util.Observable
51925 * This class represents the primary interface of a component based grid control.
51926 * <br><br>Usage:<pre><code>
51927 var grid = new Roo.grid.Grid("my-container-id", {
51930 selModel: mySelectionModel,
51931 autoSizeColumns: true,
51932 monitorWindowResize: false,
51933 trackMouseOver: true
51938 * <b>Common Problems:</b><br/>
51939 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51940 * element will correct this<br/>
51941 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51942 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51943 * are unpredictable.<br/>
51944 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51945 * grid to calculate dimensions/offsets.<br/>
51947 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51948 * The container MUST have some type of size defined for the grid to fill. The container will be
51949 * automatically set to position relative if it isn't already.
51950 * @param {Object} config A config object that sets properties on this grid.
51952 Roo.grid.Grid = function(container, config){
51953 // initialize the container
51954 this.container = Roo.get(container);
51955 this.container.update("");
51956 this.container.setStyle("overflow", "hidden");
51957 this.container.addClass('x-grid-container');
51959 this.id = this.container.id;
51961 Roo.apply(this, config);
51962 // check and correct shorthanded configs
51964 this.dataSource = this.ds;
51968 this.colModel = this.cm;
51972 this.selModel = this.sm;
51976 if (this.selModel) {
51977 this.selModel = Roo.factory(this.selModel, Roo.grid);
51978 this.sm = this.selModel;
51979 this.sm.xmodule = this.xmodule || false;
51981 if (typeof(this.colModel.config) == 'undefined') {
51982 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51983 this.cm = this.colModel;
51984 this.cm.xmodule = this.xmodule || false;
51986 if (this.dataSource) {
51987 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51988 this.ds = this.dataSource;
51989 this.ds.xmodule = this.xmodule || false;
51996 this.container.setWidth(this.width);
52000 this.container.setHeight(this.height);
52007 * The raw click event for the entire grid.
52008 * @param {Roo.EventObject} e
52013 * The raw dblclick event for the entire grid.
52014 * @param {Roo.EventObject} e
52018 * @event contextmenu
52019 * The raw contextmenu event for the entire grid.
52020 * @param {Roo.EventObject} e
52022 "contextmenu" : true,
52025 * The raw mousedown event for the entire grid.
52026 * @param {Roo.EventObject} e
52028 "mousedown" : true,
52031 * The raw mouseup event for the entire grid.
52032 * @param {Roo.EventObject} e
52037 * The raw mouseover event for the entire grid.
52038 * @param {Roo.EventObject} e
52040 "mouseover" : true,
52043 * The raw mouseout event for the entire grid.
52044 * @param {Roo.EventObject} e
52049 * The raw keypress event for the entire grid.
52050 * @param {Roo.EventObject} e
52055 * The raw keydown event for the entire grid.
52056 * @param {Roo.EventObject} e
52064 * Fires when a cell is clicked
52065 * @param {Grid} this
52066 * @param {Number} rowIndex
52067 * @param {Number} columnIndex
52068 * @param {Roo.EventObject} e
52070 "cellclick" : true,
52072 * @event celldblclick
52073 * Fires when a cell is double clicked
52074 * @param {Grid} this
52075 * @param {Number} rowIndex
52076 * @param {Number} columnIndex
52077 * @param {Roo.EventObject} e
52079 "celldblclick" : true,
52082 * Fires when a row is clicked
52083 * @param {Grid} this
52084 * @param {Number} rowIndex
52085 * @param {Roo.EventObject} e
52089 * @event rowdblclick
52090 * Fires when a row is double clicked
52091 * @param {Grid} this
52092 * @param {Number} rowIndex
52093 * @param {Roo.EventObject} e
52095 "rowdblclick" : true,
52097 * @event headerclick
52098 * Fires when a header is clicked
52099 * @param {Grid} this
52100 * @param {Number} columnIndex
52101 * @param {Roo.EventObject} e
52103 "headerclick" : true,
52105 * @event headerdblclick
52106 * Fires when a header cell is double clicked
52107 * @param {Grid} this
52108 * @param {Number} columnIndex
52109 * @param {Roo.EventObject} e
52111 "headerdblclick" : true,
52113 * @event rowcontextmenu
52114 * Fires when a row is right clicked
52115 * @param {Grid} this
52116 * @param {Number} rowIndex
52117 * @param {Roo.EventObject} e
52119 "rowcontextmenu" : true,
52121 * @event cellcontextmenu
52122 * Fires when a cell is right clicked
52123 * @param {Grid} this
52124 * @param {Number} rowIndex
52125 * @param {Number} cellIndex
52126 * @param {Roo.EventObject} e
52128 "cellcontextmenu" : true,
52130 * @event headercontextmenu
52131 * Fires when a header is right clicked
52132 * @param {Grid} this
52133 * @param {Number} columnIndex
52134 * @param {Roo.EventObject} e
52136 "headercontextmenu" : true,
52138 * @event bodyscroll
52139 * Fires when the body element is scrolled
52140 * @param {Number} scrollLeft
52141 * @param {Number} scrollTop
52143 "bodyscroll" : true,
52145 * @event columnresize
52146 * Fires when the user resizes a column
52147 * @param {Number} columnIndex
52148 * @param {Number} newSize
52150 "columnresize" : true,
52152 * @event columnmove
52153 * Fires when the user moves a column
52154 * @param {Number} oldIndex
52155 * @param {Number} newIndex
52157 "columnmove" : true,
52160 * Fires when row(s) start being dragged
52161 * @param {Grid} this
52162 * @param {Roo.GridDD} dd The drag drop object
52163 * @param {event} e The raw browser event
52165 "startdrag" : true,
52168 * Fires when a drag operation is complete
52169 * @param {Grid} this
52170 * @param {Roo.GridDD} dd The drag drop object
52171 * @param {event} e The raw browser event
52176 * Fires when dragged row(s) are dropped on a valid DD target
52177 * @param {Grid} this
52178 * @param {Roo.GridDD} dd The drag drop object
52179 * @param {String} targetId The target drag drop object
52180 * @param {event} e The raw browser event
52185 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52186 * @param {Grid} this
52187 * @param {Roo.GridDD} dd The drag drop object
52188 * @param {String} targetId The target drag drop object
52189 * @param {event} e The raw browser event
52194 * Fires when the dragged row(s) first cross another DD target while being dragged
52195 * @param {Grid} this
52196 * @param {Roo.GridDD} dd The drag drop object
52197 * @param {String} targetId The target drag drop object
52198 * @param {event} e The raw browser event
52200 "dragenter" : true,
52203 * Fires when the dragged row(s) leave another DD target while being dragged
52204 * @param {Grid} this
52205 * @param {Roo.GridDD} dd The drag drop object
52206 * @param {String} targetId The target drag drop object
52207 * @param {event} e The raw browser event
52212 * Fires when a row is rendered, so you can change add a style to it.
52213 * @param {GridView} gridview The grid view
52214 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52220 * Fires when the grid is rendered
52221 * @param {Grid} grid
52226 Roo.grid.Grid.superclass.constructor.call(this);
52228 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52231 * @cfg {String} ddGroup - drag drop group.
52235 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52237 minColumnWidth : 25,
52240 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52241 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52242 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52244 autoSizeColumns : false,
52247 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52249 autoSizeHeaders : true,
52252 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52254 monitorWindowResize : true,
52257 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52258 * rows measured to get a columns size. Default is 0 (all rows).
52260 maxRowsToMeasure : 0,
52263 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52265 trackMouseOver : true,
52268 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52272 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52274 enableDragDrop : false,
52277 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52279 enableColumnMove : true,
52282 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52284 enableColumnHide : true,
52287 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52289 enableRowHeightSync : false,
52292 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52297 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52299 autoHeight : false,
52302 * @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.
52304 autoExpandColumn : false,
52307 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52310 autoExpandMin : 50,
52313 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52315 autoExpandMax : 1000,
52318 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52323 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52327 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52337 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52338 * of a fixed width. Default is false.
52341 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52344 * Called once after all setup has been completed and the grid is ready to be rendered.
52345 * @return {Roo.grid.Grid} this
52347 render : function()
52349 var c = this.container;
52350 // try to detect autoHeight/width mode
52351 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52352 this.autoHeight = true;
52354 var view = this.getView();
52357 c.on("click", this.onClick, this);
52358 c.on("dblclick", this.onDblClick, this);
52359 c.on("contextmenu", this.onContextMenu, this);
52360 c.on("keydown", this.onKeyDown, this);
52362 c.on("touchstart", this.onTouchStart, this);
52365 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52367 this.getSelectionModel().init(this);
52372 this.loadMask = new Roo.LoadMask(this.container,
52373 Roo.apply({store:this.dataSource}, this.loadMask));
52377 if (this.toolbar && this.toolbar.xtype) {
52378 this.toolbar.container = this.getView().getHeaderPanel(true);
52379 this.toolbar = new Roo.Toolbar(this.toolbar);
52381 if (this.footer && this.footer.xtype) {
52382 this.footer.dataSource = this.getDataSource();
52383 this.footer.container = this.getView().getFooterPanel(true);
52384 this.footer = Roo.factory(this.footer, Roo);
52386 if (this.dropTarget && this.dropTarget.xtype) {
52387 delete this.dropTarget.xtype;
52388 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52392 this.rendered = true;
52393 this.fireEvent('render', this);
52398 * Reconfigures the grid to use a different Store and Column Model.
52399 * The View will be bound to the new objects and refreshed.
52400 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52401 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52403 reconfigure : function(dataSource, colModel){
52405 this.loadMask.destroy();
52406 this.loadMask = new Roo.LoadMask(this.container,
52407 Roo.apply({store:dataSource}, this.loadMask));
52409 this.view.bind(dataSource, colModel);
52410 this.dataSource = dataSource;
52411 this.colModel = colModel;
52412 this.view.refresh(true);
52416 onKeyDown : function(e){
52417 this.fireEvent("keydown", e);
52421 * Destroy this grid.
52422 * @param {Boolean} removeEl True to remove the element
52424 destroy : function(removeEl, keepListeners){
52426 this.loadMask.destroy();
52428 var c = this.container;
52429 c.removeAllListeners();
52430 this.view.destroy();
52431 this.colModel.purgeListeners();
52432 if(!keepListeners){
52433 this.purgeListeners();
52436 if(removeEl === true){
52442 processEvent : function(name, e){
52443 // does this fire select???
52444 Roo.log('grid:processEvent ' + name);
52446 if (name != 'touchstart' ) {
52447 this.fireEvent(name, e);
52450 var t = e.getTarget();
52452 var header = v.findHeaderIndex(t);
52453 if(header !== false){
52454 var ename = name == 'touchstart' ? 'click' : name;
52456 this.fireEvent("header" + ename, this, header, e);
52458 var row = v.findRowIndex(t);
52459 var cell = v.findCellIndex(t);
52460 if (name == 'touchstart') {
52461 // first touch is always a click.
52462 // hopefull this happens after selection is updated.?
52465 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52466 var cs = this.selModel.getSelectedCell();
52467 if (row == cs[0] && cell == cs[1]){
52471 if (typeof(this.selModel.getSelections) != 'undefined') {
52472 var cs = this.selModel.getSelections();
52473 var ds = this.dataSource;
52474 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52485 this.fireEvent("row" + name, this, row, e);
52486 if(cell !== false){
52487 this.fireEvent("cell" + name, this, row, cell, e);
52494 onClick : function(e){
52495 this.processEvent("click", e);
52498 onTouchStart : function(e){
52499 this.processEvent("touchstart", e);
52503 onContextMenu : function(e, t){
52504 this.processEvent("contextmenu", e);
52508 onDblClick : function(e){
52509 this.processEvent("dblclick", e);
52513 walkCells : function(row, col, step, fn, scope){
52514 var cm = this.colModel, clen = cm.getColumnCount();
52515 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52527 if(fn.call(scope || this, row, col, cm) === true){
52545 if(fn.call(scope || this, row, col, cm) === true){
52557 getSelections : function(){
52558 return this.selModel.getSelections();
52562 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52563 * but if manual update is required this method will initiate it.
52565 autoSize : function(){
52567 this.view.layout();
52568 if(this.view.adjustForScroll){
52569 this.view.adjustForScroll();
52575 * Returns the grid's underlying element.
52576 * @return {Element} The element
52578 getGridEl : function(){
52579 return this.container;
52582 // private for compatibility, overridden by editor grid
52583 stopEditing : function(){},
52586 * Returns the grid's SelectionModel.
52587 * @return {SelectionModel}
52589 getSelectionModel : function(){
52590 if(!this.selModel){
52591 this.selModel = new Roo.grid.RowSelectionModel();
52593 return this.selModel;
52597 * Returns the grid's DataSource.
52598 * @return {DataSource}
52600 getDataSource : function(){
52601 return this.dataSource;
52605 * Returns the grid's ColumnModel.
52606 * @return {ColumnModel}
52608 getColumnModel : function(){
52609 return this.colModel;
52613 * Returns the grid's GridView object.
52614 * @return {GridView}
52616 getView : function(){
52618 this.view = new Roo.grid.GridView(this.viewConfig);
52623 * Called to get grid's drag proxy text, by default returns this.ddText.
52626 getDragDropText : function(){
52627 var count = this.selModel.getCount();
52628 return String.format(this.ddText, count, count == 1 ? '' : 's');
52632 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52633 * %0 is replaced with the number of selected rows.
52636 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52638 * Ext JS Library 1.1.1
52639 * Copyright(c) 2006-2007, Ext JS, LLC.
52641 * Originally Released Under LGPL - original licence link has changed is not relivant.
52644 * <script type="text/javascript">
52647 Roo.grid.AbstractGridView = function(){
52651 "beforerowremoved" : true,
52652 "beforerowsinserted" : true,
52653 "beforerefresh" : true,
52654 "rowremoved" : true,
52655 "rowsinserted" : true,
52656 "rowupdated" : true,
52659 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52662 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52663 rowClass : "x-grid-row",
52664 cellClass : "x-grid-cell",
52665 tdClass : "x-grid-td",
52666 hdClass : "x-grid-hd",
52667 splitClass : "x-grid-hd-split",
52669 init: function(grid){
52671 var cid = this.grid.getGridEl().id;
52672 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52673 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52674 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52675 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52678 getColumnRenderers : function(){
52679 var renderers = [];
52680 var cm = this.grid.colModel;
52681 var colCount = cm.getColumnCount();
52682 for(var i = 0; i < colCount; i++){
52683 renderers[i] = cm.getRenderer(i);
52688 getColumnIds : function(){
52690 var cm = this.grid.colModel;
52691 var colCount = cm.getColumnCount();
52692 for(var i = 0; i < colCount; i++){
52693 ids[i] = cm.getColumnId(i);
52698 getDataIndexes : function(){
52699 if(!this.indexMap){
52700 this.indexMap = this.buildIndexMap();
52702 return this.indexMap.colToData;
52705 getColumnIndexByDataIndex : function(dataIndex){
52706 if(!this.indexMap){
52707 this.indexMap = this.buildIndexMap();
52709 return this.indexMap.dataToCol[dataIndex];
52713 * Set a css style for a column dynamically.
52714 * @param {Number} colIndex The index of the column
52715 * @param {String} name The css property name
52716 * @param {String} value The css value
52718 setCSSStyle : function(colIndex, name, value){
52719 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52720 Roo.util.CSS.updateRule(selector, name, value);
52723 generateRules : function(cm){
52724 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52725 Roo.util.CSS.removeStyleSheet(rulesId);
52726 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52727 var cid = cm.getColumnId(i);
52728 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52729 this.tdSelector, cid, " {\n}\n",
52730 this.hdSelector, cid, " {\n}\n",
52731 this.splitSelector, cid, " {\n}\n");
52733 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52737 * Ext JS Library 1.1.1
52738 * Copyright(c) 2006-2007, Ext JS, LLC.
52740 * Originally Released Under LGPL - original licence link has changed is not relivant.
52743 * <script type="text/javascript">
52747 // This is a support class used internally by the Grid components
52748 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52750 this.view = grid.getView();
52751 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52752 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52754 this.setHandleElId(Roo.id(hd));
52755 this.setOuterHandleElId(Roo.id(hd2));
52757 this.scroll = false;
52759 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52761 getDragData : function(e){
52762 var t = Roo.lib.Event.getTarget(e);
52763 var h = this.view.findHeaderCell(t);
52765 return {ddel: h.firstChild, header:h};
52770 onInitDrag : function(e){
52771 this.view.headersDisabled = true;
52772 var clone = this.dragData.ddel.cloneNode(true);
52773 clone.id = Roo.id();
52774 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52775 this.proxy.update(clone);
52779 afterValidDrop : function(){
52781 setTimeout(function(){
52782 v.headersDisabled = false;
52786 afterInvalidDrop : function(){
52788 setTimeout(function(){
52789 v.headersDisabled = false;
52795 * Ext JS Library 1.1.1
52796 * Copyright(c) 2006-2007, Ext JS, LLC.
52798 * Originally Released Under LGPL - original licence link has changed is not relivant.
52801 * <script type="text/javascript">
52804 // This is a support class used internally by the Grid components
52805 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52807 this.view = grid.getView();
52808 // split the proxies so they don't interfere with mouse events
52809 this.proxyTop = Roo.DomHelper.append(document.body, {
52810 cls:"col-move-top", html:" "
52812 this.proxyBottom = Roo.DomHelper.append(document.body, {
52813 cls:"col-move-bottom", html:" "
52815 this.proxyTop.hide = this.proxyBottom.hide = function(){
52816 this.setLeftTop(-100,-100);
52817 this.setStyle("visibility", "hidden");
52819 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52820 // temporarily disabled
52821 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52822 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52824 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52825 proxyOffsets : [-4, -9],
52826 fly: Roo.Element.fly,
52828 getTargetFromEvent : function(e){
52829 var t = Roo.lib.Event.getTarget(e);
52830 var cindex = this.view.findCellIndex(t);
52831 if(cindex !== false){
52832 return this.view.getHeaderCell(cindex);
52837 nextVisible : function(h){
52838 var v = this.view, cm = this.grid.colModel;
52841 if(!cm.isHidden(v.getCellIndex(h))){
52849 prevVisible : function(h){
52850 var v = this.view, cm = this.grid.colModel;
52853 if(!cm.isHidden(v.getCellIndex(h))){
52861 positionIndicator : function(h, n, e){
52862 var x = Roo.lib.Event.getPageX(e);
52863 var r = Roo.lib.Dom.getRegion(n.firstChild);
52864 var px, pt, py = r.top + this.proxyOffsets[1];
52865 if((r.right - x) <= (r.right-r.left)/2){
52866 px = r.right+this.view.borderWidth;
52872 var oldIndex = this.view.getCellIndex(h);
52873 var newIndex = this.view.getCellIndex(n);
52875 if(this.grid.colModel.isFixed(newIndex)){
52879 var locked = this.grid.colModel.isLocked(newIndex);
52884 if(oldIndex < newIndex){
52887 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52890 px += this.proxyOffsets[0];
52891 this.proxyTop.setLeftTop(px, py);
52892 this.proxyTop.show();
52893 if(!this.bottomOffset){
52894 this.bottomOffset = this.view.mainHd.getHeight();
52896 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52897 this.proxyBottom.show();
52901 onNodeEnter : function(n, dd, e, data){
52902 if(data.header != n){
52903 this.positionIndicator(data.header, n, e);
52907 onNodeOver : function(n, dd, e, data){
52908 var result = false;
52909 if(data.header != n){
52910 result = this.positionIndicator(data.header, n, e);
52913 this.proxyTop.hide();
52914 this.proxyBottom.hide();
52916 return result ? this.dropAllowed : this.dropNotAllowed;
52919 onNodeOut : function(n, dd, e, data){
52920 this.proxyTop.hide();
52921 this.proxyBottom.hide();
52924 onNodeDrop : function(n, dd, e, data){
52925 var h = data.header;
52927 var cm = this.grid.colModel;
52928 var x = Roo.lib.Event.getPageX(e);
52929 var r = Roo.lib.Dom.getRegion(n.firstChild);
52930 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52931 var oldIndex = this.view.getCellIndex(h);
52932 var newIndex = this.view.getCellIndex(n);
52933 var locked = cm.isLocked(newIndex);
52937 if(oldIndex < newIndex){
52940 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52943 cm.setLocked(oldIndex, locked, true);
52944 cm.moveColumn(oldIndex, newIndex);
52945 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52953 * Ext JS Library 1.1.1
52954 * Copyright(c) 2006-2007, Ext JS, LLC.
52956 * Originally Released Under LGPL - original licence link has changed is not relivant.
52959 * <script type="text/javascript">
52963 * @class Roo.grid.GridView
52964 * @extends Roo.util.Observable
52967 * @param {Object} config
52969 Roo.grid.GridView = function(config){
52970 Roo.grid.GridView.superclass.constructor.call(this);
52973 Roo.apply(this, config);
52976 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52978 unselectable : 'unselectable="on"',
52979 unselectableCls : 'x-unselectable',
52982 rowClass : "x-grid-row",
52984 cellClass : "x-grid-col",
52986 tdClass : "x-grid-td",
52988 hdClass : "x-grid-hd",
52990 splitClass : "x-grid-split",
52992 sortClasses : ["sort-asc", "sort-desc"],
52994 enableMoveAnim : false,
52998 dh : Roo.DomHelper,
53000 fly : Roo.Element.fly,
53002 css : Roo.util.CSS,
53008 scrollIncrement : 22,
53010 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53012 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53014 bind : function(ds, cm){
53016 this.ds.un("load", this.onLoad, this);
53017 this.ds.un("datachanged", this.onDataChange, this);
53018 this.ds.un("add", this.onAdd, this);
53019 this.ds.un("remove", this.onRemove, this);
53020 this.ds.un("update", this.onUpdate, this);
53021 this.ds.un("clear", this.onClear, this);
53024 ds.on("load", this.onLoad, this);
53025 ds.on("datachanged", this.onDataChange, this);
53026 ds.on("add", this.onAdd, this);
53027 ds.on("remove", this.onRemove, this);
53028 ds.on("update", this.onUpdate, this);
53029 ds.on("clear", this.onClear, this);
53034 this.cm.un("widthchange", this.onColWidthChange, this);
53035 this.cm.un("headerchange", this.onHeaderChange, this);
53036 this.cm.un("hiddenchange", this.onHiddenChange, this);
53037 this.cm.un("columnmoved", this.onColumnMove, this);
53038 this.cm.un("columnlockchange", this.onColumnLock, this);
53041 this.generateRules(cm);
53042 cm.on("widthchange", this.onColWidthChange, this);
53043 cm.on("headerchange", this.onHeaderChange, this);
53044 cm.on("hiddenchange", this.onHiddenChange, this);
53045 cm.on("columnmoved", this.onColumnMove, this);
53046 cm.on("columnlockchange", this.onColumnLock, this);
53051 init: function(grid){
53052 Roo.grid.GridView.superclass.init.call(this, grid);
53054 this.bind(grid.dataSource, grid.colModel);
53056 grid.on("headerclick", this.handleHeaderClick, this);
53058 if(grid.trackMouseOver){
53059 grid.on("mouseover", this.onRowOver, this);
53060 grid.on("mouseout", this.onRowOut, this);
53062 grid.cancelTextSelection = function(){};
53063 this.gridId = grid.id;
53065 var tpls = this.templates || {};
53068 tpls.master = new Roo.Template(
53069 '<div class="x-grid" hidefocus="true">',
53070 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53071 '<div class="x-grid-topbar"></div>',
53072 '<div class="x-grid-scroller"><div></div></div>',
53073 '<div class="x-grid-locked">',
53074 '<div class="x-grid-header">{lockedHeader}</div>',
53075 '<div class="x-grid-body">{lockedBody}</div>',
53077 '<div class="x-grid-viewport">',
53078 '<div class="x-grid-header">{header}</div>',
53079 '<div class="x-grid-body">{body}</div>',
53081 '<div class="x-grid-bottombar"></div>',
53083 '<div class="x-grid-resize-proxy"> </div>',
53086 tpls.master.disableformats = true;
53090 tpls.header = new Roo.Template(
53091 '<table border="0" cellspacing="0" cellpadding="0">',
53092 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53095 tpls.header.disableformats = true;
53097 tpls.header.compile();
53100 tpls.hcell = new Roo.Template(
53101 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53102 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53105 tpls.hcell.disableFormats = true;
53107 tpls.hcell.compile();
53110 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53111 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53112 tpls.hsplit.disableFormats = true;
53114 tpls.hsplit.compile();
53117 tpls.body = new Roo.Template(
53118 '<table border="0" cellspacing="0" cellpadding="0">',
53119 "<tbody>{rows}</tbody>",
53122 tpls.body.disableFormats = true;
53124 tpls.body.compile();
53127 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53128 tpls.row.disableFormats = true;
53130 tpls.row.compile();
53133 tpls.cell = new Roo.Template(
53134 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53135 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53136 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53139 tpls.cell.disableFormats = true;
53141 tpls.cell.compile();
53143 this.templates = tpls;
53146 // remap these for backwards compat
53147 onColWidthChange : function(){
53148 this.updateColumns.apply(this, arguments);
53150 onHeaderChange : function(){
53151 this.updateHeaders.apply(this, arguments);
53153 onHiddenChange : function(){
53154 this.handleHiddenChange.apply(this, arguments);
53156 onColumnMove : function(){
53157 this.handleColumnMove.apply(this, arguments);
53159 onColumnLock : function(){
53160 this.handleLockChange.apply(this, arguments);
53163 onDataChange : function(){
53165 this.updateHeaderSortState();
53168 onClear : function(){
53172 onUpdate : function(ds, record){
53173 this.refreshRow(record);
53176 refreshRow : function(record){
53177 var ds = this.ds, index;
53178 if(typeof record == 'number'){
53180 record = ds.getAt(index);
53182 index = ds.indexOf(record);
53184 this.insertRows(ds, index, index, true);
53185 this.onRemove(ds, record, index+1, true);
53186 this.syncRowHeights(index, index);
53188 this.fireEvent("rowupdated", this, index, record);
53191 onAdd : function(ds, records, index){
53192 this.insertRows(ds, index, index + (records.length-1));
53195 onRemove : function(ds, record, index, isUpdate){
53196 if(isUpdate !== true){
53197 this.fireEvent("beforerowremoved", this, index, record);
53199 var bt = this.getBodyTable(), lt = this.getLockedTable();
53200 if(bt.rows[index]){
53201 bt.firstChild.removeChild(bt.rows[index]);
53203 if(lt.rows[index]){
53204 lt.firstChild.removeChild(lt.rows[index]);
53206 if(isUpdate !== true){
53207 this.stripeRows(index);
53208 this.syncRowHeights(index, index);
53210 this.fireEvent("rowremoved", this, index, record);
53214 onLoad : function(){
53215 this.scrollToTop();
53219 * Scrolls the grid to the top
53221 scrollToTop : function(){
53223 this.scroller.dom.scrollTop = 0;
53229 * Gets a panel in the header of the grid that can be used for toolbars etc.
53230 * After modifying the contents of this panel a call to grid.autoSize() may be
53231 * required to register any changes in size.
53232 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53233 * @return Roo.Element
53235 getHeaderPanel : function(doShow){
53237 this.headerPanel.show();
53239 return this.headerPanel;
53243 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53244 * After modifying the contents of this panel a call to grid.autoSize() may be
53245 * required to register any changes in size.
53246 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53247 * @return Roo.Element
53249 getFooterPanel : function(doShow){
53251 this.footerPanel.show();
53253 return this.footerPanel;
53256 initElements : function(){
53257 var E = Roo.Element;
53258 var el = this.grid.getGridEl().dom.firstChild;
53259 var cs = el.childNodes;
53261 this.el = new E(el);
53263 this.focusEl = new E(el.firstChild);
53264 this.focusEl.swallowEvent("click", true);
53266 this.headerPanel = new E(cs[1]);
53267 this.headerPanel.enableDisplayMode("block");
53269 this.scroller = new E(cs[2]);
53270 this.scrollSizer = new E(this.scroller.dom.firstChild);
53272 this.lockedWrap = new E(cs[3]);
53273 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53274 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53276 this.mainWrap = new E(cs[4]);
53277 this.mainHd = new E(this.mainWrap.dom.firstChild);
53278 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53280 this.footerPanel = new E(cs[5]);
53281 this.footerPanel.enableDisplayMode("block");
53283 this.resizeProxy = new E(cs[6]);
53285 this.headerSelector = String.format(
53286 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53287 this.lockedHd.id, this.mainHd.id
53290 this.splitterSelector = String.format(
53291 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53292 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53295 idToCssName : function(s)
53297 return s.replace(/[^a-z0-9]+/ig, '-');
53300 getHeaderCell : function(index){
53301 return Roo.DomQuery.select(this.headerSelector)[index];
53304 getHeaderCellMeasure : function(index){
53305 return this.getHeaderCell(index).firstChild;
53308 getHeaderCellText : function(index){
53309 return this.getHeaderCell(index).firstChild.firstChild;
53312 getLockedTable : function(){
53313 return this.lockedBody.dom.firstChild;
53316 getBodyTable : function(){
53317 return this.mainBody.dom.firstChild;
53320 getLockedRow : function(index){
53321 return this.getLockedTable().rows[index];
53324 getRow : function(index){
53325 return this.getBodyTable().rows[index];
53328 getRowComposite : function(index){
53330 this.rowEl = new Roo.CompositeElementLite();
53332 var els = [], lrow, mrow;
53333 if(lrow = this.getLockedRow(index)){
53336 if(mrow = this.getRow(index)){
53339 this.rowEl.elements = els;
53343 * Gets the 'td' of the cell
53345 * @param {Integer} rowIndex row to select
53346 * @param {Integer} colIndex column to select
53350 getCell : function(rowIndex, colIndex){
53351 var locked = this.cm.getLockedCount();
53353 if(colIndex < locked){
53354 source = this.lockedBody.dom.firstChild;
53356 source = this.mainBody.dom.firstChild;
53357 colIndex -= locked;
53359 return source.rows[rowIndex].childNodes[colIndex];
53362 getCellText : function(rowIndex, colIndex){
53363 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53366 getCellBox : function(cell){
53367 var b = this.fly(cell).getBox();
53368 if(Roo.isOpera){ // opera fails to report the Y
53369 b.y = cell.offsetTop + this.mainBody.getY();
53374 getCellIndex : function(cell){
53375 var id = String(cell.className).match(this.cellRE);
53377 return parseInt(id[1], 10);
53382 findHeaderIndex : function(n){
53383 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53384 return r ? this.getCellIndex(r) : false;
53387 findHeaderCell : function(n){
53388 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53389 return r ? r : false;
53392 findRowIndex : function(n){
53396 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53397 return r ? r.rowIndex : false;
53400 findCellIndex : function(node){
53401 var stop = this.el.dom;
53402 while(node && node != stop){
53403 if(this.findRE.test(node.className)){
53404 return this.getCellIndex(node);
53406 node = node.parentNode;
53411 getColumnId : function(index){
53412 return this.cm.getColumnId(index);
53415 getSplitters : function()
53417 if(this.splitterSelector){
53418 return Roo.DomQuery.select(this.splitterSelector);
53424 getSplitter : function(index){
53425 return this.getSplitters()[index];
53428 onRowOver : function(e, t){
53430 if((row = this.findRowIndex(t)) !== false){
53431 this.getRowComposite(row).addClass("x-grid-row-over");
53435 onRowOut : function(e, t){
53437 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53438 this.getRowComposite(row).removeClass("x-grid-row-over");
53442 renderHeaders : function(){
53444 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53445 var cb = [], lb = [], sb = [], lsb = [], p = {};
53446 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53447 p.cellId = "x-grid-hd-0-" + i;
53448 p.splitId = "x-grid-csplit-0-" + i;
53449 p.id = cm.getColumnId(i);
53450 p.title = cm.getColumnTooltip(i) || "";
53451 p.value = cm.getColumnHeader(i) || "";
53452 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53453 if(!cm.isLocked(i)){
53454 cb[cb.length] = ct.apply(p);
53455 sb[sb.length] = st.apply(p);
53457 lb[lb.length] = ct.apply(p);
53458 lsb[lsb.length] = st.apply(p);
53461 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53462 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53465 updateHeaders : function(){
53466 var html = this.renderHeaders();
53467 this.lockedHd.update(html[0]);
53468 this.mainHd.update(html[1]);
53472 * Focuses the specified row.
53473 * @param {Number} row The row index
53475 focusRow : function(row)
53477 //Roo.log('GridView.focusRow');
53478 var x = this.scroller.dom.scrollLeft;
53479 this.focusCell(row, 0, false);
53480 this.scroller.dom.scrollLeft = x;
53484 * Focuses the specified cell.
53485 * @param {Number} row The row index
53486 * @param {Number} col The column index
53487 * @param {Boolean} hscroll false to disable horizontal scrolling
53489 focusCell : function(row, col, hscroll)
53491 //Roo.log('GridView.focusCell');
53492 var el = this.ensureVisible(row, col, hscroll);
53493 this.focusEl.alignTo(el, "tl-tl");
53495 this.focusEl.focus();
53497 this.focusEl.focus.defer(1, this.focusEl);
53502 * Scrolls the specified cell into view
53503 * @param {Number} row The row index
53504 * @param {Number} col The column index
53505 * @param {Boolean} hscroll false to disable horizontal scrolling
53507 ensureVisible : function(row, col, hscroll)
53509 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53510 //return null; //disable for testing.
53511 if(typeof row != "number"){
53512 row = row.rowIndex;
53514 if(row < 0 && row >= this.ds.getCount()){
53517 col = (col !== undefined ? col : 0);
53518 var cm = this.grid.colModel;
53519 while(cm.isHidden(col)){
53523 var el = this.getCell(row, col);
53527 var c = this.scroller.dom;
53529 var ctop = parseInt(el.offsetTop, 10);
53530 var cleft = parseInt(el.offsetLeft, 10);
53531 var cbot = ctop + el.offsetHeight;
53532 var cright = cleft + el.offsetWidth;
53534 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53535 var stop = parseInt(c.scrollTop, 10);
53536 var sleft = parseInt(c.scrollLeft, 10);
53537 var sbot = stop + ch;
53538 var sright = sleft + c.clientWidth;
53540 Roo.log('GridView.ensureVisible:' +
53542 ' c.clientHeight:' + c.clientHeight +
53543 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53551 c.scrollTop = ctop;
53552 //Roo.log("set scrolltop to ctop DISABLE?");
53553 }else if(cbot > sbot){
53554 //Roo.log("set scrolltop to cbot-ch");
53555 c.scrollTop = cbot-ch;
53558 if(hscroll !== false){
53560 c.scrollLeft = cleft;
53561 }else if(cright > sright){
53562 c.scrollLeft = cright-c.clientWidth;
53569 updateColumns : function(){
53570 this.grid.stopEditing();
53571 var cm = this.grid.colModel, colIds = this.getColumnIds();
53572 //var totalWidth = cm.getTotalWidth();
53574 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53575 //if(cm.isHidden(i)) continue;
53576 var w = cm.getColumnWidth(i);
53577 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53578 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53580 this.updateSplitters();
53583 generateRules : function(cm){
53584 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53585 Roo.util.CSS.removeStyleSheet(rulesId);
53586 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53587 var cid = cm.getColumnId(i);
53589 if(cm.config[i].align){
53590 align = 'text-align:'+cm.config[i].align+';';
53593 if(cm.isHidden(i)){
53594 hidden = 'display:none;';
53596 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53598 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53599 this.hdSelector, cid, " {\n", align, width, "}\n",
53600 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53601 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53603 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53606 updateSplitters : function(){
53607 var cm = this.cm, s = this.getSplitters();
53608 if(s){ // splitters not created yet
53609 var pos = 0, locked = true;
53610 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53611 if(cm.isHidden(i)) continue;
53612 var w = cm.getColumnWidth(i); // make sure it's a number
53613 if(!cm.isLocked(i) && locked){
53618 s[i].style.left = (pos-this.splitOffset) + "px";
53623 handleHiddenChange : function(colModel, colIndex, hidden){
53625 this.hideColumn(colIndex);
53627 this.unhideColumn(colIndex);
53631 hideColumn : function(colIndex){
53632 var cid = this.getColumnId(colIndex);
53633 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53634 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53636 this.updateHeaders();
53638 this.updateSplitters();
53642 unhideColumn : function(colIndex){
53643 var cid = this.getColumnId(colIndex);
53644 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53645 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53648 this.updateHeaders();
53650 this.updateSplitters();
53654 insertRows : function(dm, firstRow, lastRow, isUpdate){
53655 if(firstRow == 0 && lastRow == dm.getCount()-1){
53659 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53661 var s = this.getScrollState();
53662 var markup = this.renderRows(firstRow, lastRow);
53663 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53664 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53665 this.restoreScroll(s);
53667 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53668 this.syncRowHeights(firstRow, lastRow);
53669 this.stripeRows(firstRow);
53675 bufferRows : function(markup, target, index){
53676 var before = null, trows = target.rows, tbody = target.tBodies[0];
53677 if(index < trows.length){
53678 before = trows[index];
53680 var b = document.createElement("div");
53681 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53682 var rows = b.firstChild.rows;
53683 for(var i = 0, len = rows.length; i < len; i++){
53685 tbody.insertBefore(rows[0], before);
53687 tbody.appendChild(rows[0]);
53694 deleteRows : function(dm, firstRow, lastRow){
53695 if(dm.getRowCount()<1){
53696 this.fireEvent("beforerefresh", this);
53697 this.mainBody.update("");
53698 this.lockedBody.update("");
53699 this.fireEvent("refresh", this);
53701 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53702 var bt = this.getBodyTable();
53703 var tbody = bt.firstChild;
53704 var rows = bt.rows;
53705 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53706 tbody.removeChild(rows[firstRow]);
53708 this.stripeRows(firstRow);
53709 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53713 updateRows : function(dataSource, firstRow, lastRow){
53714 var s = this.getScrollState();
53716 this.restoreScroll(s);
53719 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53723 this.updateHeaderSortState();
53726 getScrollState : function(){
53728 var sb = this.scroller.dom;
53729 return {left: sb.scrollLeft, top: sb.scrollTop};
53732 stripeRows : function(startRow){
53733 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53736 startRow = startRow || 0;
53737 var rows = this.getBodyTable().rows;
53738 var lrows = this.getLockedTable().rows;
53739 var cls = ' x-grid-row-alt ';
53740 for(var i = startRow, len = rows.length; i < len; i++){
53741 var row = rows[i], lrow = lrows[i];
53742 var isAlt = ((i+1) % 2 == 0);
53743 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53744 if(isAlt == hasAlt){
53748 row.className += " x-grid-row-alt";
53750 row.className = row.className.replace("x-grid-row-alt", "");
53753 lrow.className = row.className;
53758 restoreScroll : function(state){
53759 //Roo.log('GridView.restoreScroll');
53760 var sb = this.scroller.dom;
53761 sb.scrollLeft = state.left;
53762 sb.scrollTop = state.top;
53766 syncScroll : function(){
53767 //Roo.log('GridView.syncScroll');
53768 var sb = this.scroller.dom;
53769 var sh = this.mainHd.dom;
53770 var bs = this.mainBody.dom;
53771 var lv = this.lockedBody.dom;
53772 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53773 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53776 handleScroll : function(e){
53778 var sb = this.scroller.dom;
53779 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53783 handleWheel : function(e){
53784 var d = e.getWheelDelta();
53785 this.scroller.dom.scrollTop -= d*22;
53786 // set this here to prevent jumpy scrolling on large tables
53787 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53791 renderRows : function(startRow, endRow){
53792 // pull in all the crap needed to render rows
53793 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53794 var colCount = cm.getColumnCount();
53796 if(ds.getCount() < 1){
53800 // build a map for all the columns
53802 for(var i = 0; i < colCount; i++){
53803 var name = cm.getDataIndex(i);
53805 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53806 renderer : cm.getRenderer(i),
53807 id : cm.getColumnId(i),
53808 locked : cm.isLocked(i)
53812 startRow = startRow || 0;
53813 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53815 // records to render
53816 var rs = ds.getRange(startRow, endRow);
53818 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53821 // As much as I hate to duplicate code, this was branched because FireFox really hates
53822 // [].join("") on strings. The performance difference was substantial enough to
53823 // branch this function
53824 doRender : Roo.isGecko ?
53825 function(cs, rs, ds, startRow, colCount, stripe){
53826 var ts = this.templates, ct = ts.cell, rt = ts.row;
53828 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53830 var hasListener = this.grid.hasListener('rowclass');
53832 for(var j = 0, len = rs.length; j < len; j++){
53833 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53834 for(var i = 0; i < colCount; i++){
53836 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53838 p.css = p.attr = "";
53839 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53840 if(p.value == undefined || p.value === "") p.value = " ";
53841 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53842 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53844 var markup = ct.apply(p);
53852 if(stripe && ((rowIndex+1) % 2 == 0)){
53853 alt.push("x-grid-row-alt")
53856 alt.push( " x-grid-dirty-row");
53859 if(this.getRowClass){
53860 alt.push(this.getRowClass(r, rowIndex));
53866 rowIndex : rowIndex,
53869 this.grid.fireEvent('rowclass', this, rowcfg);
53870 alt.push(rowcfg.rowClass);
53872 rp.alt = alt.join(" ");
53873 lbuf+= rt.apply(rp);
53875 buf+= rt.apply(rp);
53877 return [lbuf, buf];
53879 function(cs, rs, ds, startRow, colCount, stripe){
53880 var ts = this.templates, ct = ts.cell, rt = ts.row;
53882 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53883 var hasListener = this.grid.hasListener('rowclass');
53886 for(var j = 0, len = rs.length; j < len; j++){
53887 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53888 for(var i = 0; i < colCount; i++){
53890 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53892 p.css = p.attr = "";
53893 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53894 if(p.value == undefined || p.value === "") p.value = " ";
53895 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53896 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53899 var markup = ct.apply(p);
53901 cb[cb.length] = markup;
53903 lcb[lcb.length] = markup;
53907 if(stripe && ((rowIndex+1) % 2 == 0)){
53908 alt.push( "x-grid-row-alt");
53911 alt.push(" x-grid-dirty-row");
53914 if(this.getRowClass){
53915 alt.push( this.getRowClass(r, rowIndex));
53921 rowIndex : rowIndex,
53924 this.grid.fireEvent('rowclass', this, rowcfg);
53925 alt.push(rowcfg.rowClass);
53927 rp.alt = alt.join(" ");
53928 rp.cells = lcb.join("");
53929 lbuf[lbuf.length] = rt.apply(rp);
53930 rp.cells = cb.join("");
53931 buf[buf.length] = rt.apply(rp);
53933 return [lbuf.join(""), buf.join("")];
53936 renderBody : function(){
53937 var markup = this.renderRows();
53938 var bt = this.templates.body;
53939 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53943 * Refreshes the grid
53944 * @param {Boolean} headersToo
53946 refresh : function(headersToo){
53947 this.fireEvent("beforerefresh", this);
53948 this.grid.stopEditing();
53949 var result = this.renderBody();
53950 this.lockedBody.update(result[0]);
53951 this.mainBody.update(result[1]);
53952 if(headersToo === true){
53953 this.updateHeaders();
53954 this.updateColumns();
53955 this.updateSplitters();
53956 this.updateHeaderSortState();
53958 this.syncRowHeights();
53960 this.fireEvent("refresh", this);
53963 handleColumnMove : function(cm, oldIndex, newIndex){
53964 this.indexMap = null;
53965 var s = this.getScrollState();
53966 this.refresh(true);
53967 this.restoreScroll(s);
53968 this.afterMove(newIndex);
53971 afterMove : function(colIndex){
53972 if(this.enableMoveAnim && Roo.enableFx){
53973 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53975 // if multisort - fix sortOrder, and reload..
53976 if (this.grid.dataSource.multiSort) {
53977 // the we can call sort again..
53978 var dm = this.grid.dataSource;
53979 var cm = this.grid.colModel;
53981 for(var i = 0; i < cm.config.length; i++ ) {
53983 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53984 continue; // dont' bother, it's not in sort list or being set.
53987 so.push(cm.config[i].dataIndex);
53990 dm.load(dm.lastOptions);
53997 updateCell : function(dm, rowIndex, dataIndex){
53998 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53999 if(typeof colIndex == "undefined"){ // not present in grid
54002 var cm = this.grid.colModel;
54003 var cell = this.getCell(rowIndex, colIndex);
54004 var cellText = this.getCellText(rowIndex, colIndex);
54007 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54008 id : cm.getColumnId(colIndex),
54009 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54011 var renderer = cm.getRenderer(colIndex);
54012 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54013 if(typeof val == "undefined" || val === "") val = " ";
54014 cellText.innerHTML = val;
54015 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54016 this.syncRowHeights(rowIndex, rowIndex);
54019 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54021 if(this.grid.autoSizeHeaders){
54022 var h = this.getHeaderCellMeasure(colIndex);
54023 maxWidth = Math.max(maxWidth, h.scrollWidth);
54026 if(this.cm.isLocked(colIndex)){
54027 tb = this.getLockedTable();
54030 tb = this.getBodyTable();
54031 index = colIndex - this.cm.getLockedCount();
54034 var rows = tb.rows;
54035 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54036 for(var i = 0; i < stopIndex; i++){
54037 var cell = rows[i].childNodes[index].firstChild;
54038 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54041 return maxWidth + /*margin for error in IE*/ 5;
54044 * Autofit a column to its content.
54045 * @param {Number} colIndex
54046 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54048 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54049 if(this.cm.isHidden(colIndex)){
54050 return; // can't calc a hidden column
54053 var cid = this.cm.getColumnId(colIndex);
54054 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54055 if(this.grid.autoSizeHeaders){
54056 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54059 var newWidth = this.calcColumnWidth(colIndex);
54060 this.cm.setColumnWidth(colIndex,
54061 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54062 if(!suppressEvent){
54063 this.grid.fireEvent("columnresize", colIndex, newWidth);
54068 * Autofits all columns to their content and then expands to fit any extra space in the grid
54070 autoSizeColumns : function(){
54071 var cm = this.grid.colModel;
54072 var colCount = cm.getColumnCount();
54073 for(var i = 0; i < colCount; i++){
54074 this.autoSizeColumn(i, true, true);
54076 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54079 this.updateColumns();
54085 * Autofits all columns to the grid's width proportionate with their current size
54086 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54088 fitColumns : function(reserveScrollSpace){
54089 var cm = this.grid.colModel;
54090 var colCount = cm.getColumnCount();
54094 for (i = 0; i < colCount; i++){
54095 if(!cm.isHidden(i) && !cm.isFixed(i)){
54096 w = cm.getColumnWidth(i);
54102 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54103 if(reserveScrollSpace){
54106 var frac = (avail - cm.getTotalWidth())/width;
54107 while (cols.length){
54110 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54112 this.updateColumns();
54116 onRowSelect : function(rowIndex){
54117 var row = this.getRowComposite(rowIndex);
54118 row.addClass("x-grid-row-selected");
54121 onRowDeselect : function(rowIndex){
54122 var row = this.getRowComposite(rowIndex);
54123 row.removeClass("x-grid-row-selected");
54126 onCellSelect : function(row, col){
54127 var cell = this.getCell(row, col);
54129 Roo.fly(cell).addClass("x-grid-cell-selected");
54133 onCellDeselect : function(row, col){
54134 var cell = this.getCell(row, col);
54136 Roo.fly(cell).removeClass("x-grid-cell-selected");
54140 updateHeaderSortState : function(){
54142 // sort state can be single { field: xxx, direction : yyy}
54143 // or { xxx=>ASC , yyy : DESC ..... }
54146 if (!this.ds.multiSort) {
54147 var state = this.ds.getSortState();
54151 mstate[state.field] = state.direction;
54152 // FIXME... - this is not used here.. but might be elsewhere..
54153 this.sortState = state;
54156 mstate = this.ds.sortToggle;
54158 //remove existing sort classes..
54160 var sc = this.sortClasses;
54161 var hds = this.el.select(this.headerSelector).removeClass(sc);
54163 for(var f in mstate) {
54165 var sortColumn = this.cm.findColumnIndex(f);
54167 if(sortColumn != -1){
54168 var sortDir = mstate[f];
54169 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54178 handleHeaderClick : function(g, index,e){
54180 Roo.log("header click");
54183 // touch events on header are handled by context
54184 this.handleHdCtx(g,index,e);
54189 if(this.headersDisabled){
54192 var dm = g.dataSource, cm = g.colModel;
54193 if(!cm.isSortable(index)){
54198 if (dm.multiSort) {
54199 // update the sortOrder
54201 for(var i = 0; i < cm.config.length; i++ ) {
54203 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54204 continue; // dont' bother, it's not in sort list or being set.
54207 so.push(cm.config[i].dataIndex);
54213 dm.sort(cm.getDataIndex(index));
54217 destroy : function(){
54219 this.colMenu.removeAll();
54220 Roo.menu.MenuMgr.unregister(this.colMenu);
54221 this.colMenu.getEl().remove();
54222 delete this.colMenu;
54225 this.hmenu.removeAll();
54226 Roo.menu.MenuMgr.unregister(this.hmenu);
54227 this.hmenu.getEl().remove();
54230 if(this.grid.enableColumnMove){
54231 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54233 for(var dd in dds){
54234 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54235 var elid = dds[dd].dragElId;
54237 Roo.get(elid).remove();
54238 } else if(dds[dd].config.isTarget){
54239 dds[dd].proxyTop.remove();
54240 dds[dd].proxyBottom.remove();
54243 if(Roo.dd.DDM.locationCache[dd]){
54244 delete Roo.dd.DDM.locationCache[dd];
54247 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54250 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54251 this.bind(null, null);
54252 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54255 handleLockChange : function(){
54256 this.refresh(true);
54259 onDenyColumnLock : function(){
54263 onDenyColumnHide : function(){
54267 handleHdMenuClick : function(item){
54268 var index = this.hdCtxIndex;
54269 var cm = this.cm, ds = this.ds;
54272 ds.sort(cm.getDataIndex(index), "ASC");
54275 ds.sort(cm.getDataIndex(index), "DESC");
54278 var lc = cm.getLockedCount();
54279 if(cm.getColumnCount(true) <= lc+1){
54280 this.onDenyColumnLock();
54284 cm.setLocked(index, true, true);
54285 cm.moveColumn(index, lc);
54286 this.grid.fireEvent("columnmove", index, lc);
54288 cm.setLocked(index, true);
54292 var lc = cm.getLockedCount();
54293 if((lc-1) != index){
54294 cm.setLocked(index, false, true);
54295 cm.moveColumn(index, lc-1);
54296 this.grid.fireEvent("columnmove", index, lc-1);
54298 cm.setLocked(index, false);
54301 case 'wider': // used to expand cols on touch..
54303 var cw = cm.getColumnWidth(index);
54304 cw += (item.id == 'wider' ? 1 : -1) * 50;
54305 cw = Math.max(0, cw);
54306 cw = Math.min(cw,4000);
54307 cm.setColumnWidth(index, cw);
54311 index = cm.getIndexById(item.id.substr(4));
54313 if(item.checked && cm.getColumnCount(true) <= 1){
54314 this.onDenyColumnHide();
54317 cm.setHidden(index, item.checked);
54323 beforeColMenuShow : function(){
54324 var cm = this.cm, colCount = cm.getColumnCount();
54325 this.colMenu.removeAll();
54326 for(var i = 0; i < colCount; i++){
54327 this.colMenu.add(new Roo.menu.CheckItem({
54328 id: "col-"+cm.getColumnId(i),
54329 text: cm.getColumnHeader(i),
54330 checked: !cm.isHidden(i),
54336 handleHdCtx : function(g, index, e){
54338 var hd = this.getHeaderCell(index);
54339 this.hdCtxIndex = index;
54340 var ms = this.hmenu.items, cm = this.cm;
54341 ms.get("asc").setDisabled(!cm.isSortable(index));
54342 ms.get("desc").setDisabled(!cm.isSortable(index));
54343 if(this.grid.enableColLock !== false){
54344 ms.get("lock").setDisabled(cm.isLocked(index));
54345 ms.get("unlock").setDisabled(!cm.isLocked(index));
54347 this.hmenu.show(hd, "tl-bl");
54350 handleHdOver : function(e){
54351 var hd = this.findHeaderCell(e.getTarget());
54352 if(hd && !this.headersDisabled){
54353 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54354 this.fly(hd).addClass("x-grid-hd-over");
54359 handleHdOut : function(e){
54360 var hd = this.findHeaderCell(e.getTarget());
54362 this.fly(hd).removeClass("x-grid-hd-over");
54366 handleSplitDblClick : function(e, t){
54367 var i = this.getCellIndex(t);
54368 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54369 this.autoSizeColumn(i, true);
54374 render : function(){
54377 var colCount = cm.getColumnCount();
54379 if(this.grid.monitorWindowResize === true){
54380 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54382 var header = this.renderHeaders();
54383 var body = this.templates.body.apply({rows:""});
54384 var html = this.templates.master.apply({
54387 lockedHeader: header[0],
54391 //this.updateColumns();
54393 this.grid.getGridEl().dom.innerHTML = html;
54395 this.initElements();
54397 // a kludge to fix the random scolling effect in webkit
54398 this.el.on("scroll", function() {
54399 this.el.dom.scrollTop=0; // hopefully not recursive..
54402 this.scroller.on("scroll", this.handleScroll, this);
54403 this.lockedBody.on("mousewheel", this.handleWheel, this);
54404 this.mainBody.on("mousewheel", this.handleWheel, this);
54406 this.mainHd.on("mouseover", this.handleHdOver, this);
54407 this.mainHd.on("mouseout", this.handleHdOut, this);
54408 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54409 {delegate: "."+this.splitClass});
54411 this.lockedHd.on("mouseover", this.handleHdOver, this);
54412 this.lockedHd.on("mouseout", this.handleHdOut, this);
54413 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54414 {delegate: "."+this.splitClass});
54416 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54417 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54420 this.updateSplitters();
54422 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54423 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54424 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54427 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54428 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54430 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54431 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54433 if(this.grid.enableColLock !== false){
54434 this.hmenu.add('-',
54435 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54436 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54440 this.hmenu.add('-',
54441 {id:"wider", text: this.columnsWiderText},
54442 {id:"narrow", text: this.columnsNarrowText }
54448 if(this.grid.enableColumnHide !== false){
54450 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54451 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54452 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54454 this.hmenu.add('-',
54455 {id:"columns", text: this.columnsText, menu: this.colMenu}
54458 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54460 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54463 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54464 this.dd = new Roo.grid.GridDragZone(this.grid, {
54465 ddGroup : this.grid.ddGroup || 'GridDD'
54471 for(var i = 0; i < colCount; i++){
54472 if(cm.isHidden(i)){
54473 this.hideColumn(i);
54475 if(cm.config[i].align){
54476 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54477 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54481 this.updateHeaderSortState();
54483 this.beforeInitialResize();
54486 // two part rendering gives faster view to the user
54487 this.renderPhase2.defer(1, this);
54490 renderPhase2 : function(){
54491 // render the rows now
54493 if(this.grid.autoSizeColumns){
54494 this.autoSizeColumns();
54498 beforeInitialResize : function(){
54502 onColumnSplitterMoved : function(i, w){
54503 this.userResized = true;
54504 var cm = this.grid.colModel;
54505 cm.setColumnWidth(i, w, true);
54506 var cid = cm.getColumnId(i);
54507 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54508 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54509 this.updateSplitters();
54511 this.grid.fireEvent("columnresize", i, w);
54514 syncRowHeights : function(startIndex, endIndex){
54515 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54516 startIndex = startIndex || 0;
54517 var mrows = this.getBodyTable().rows;
54518 var lrows = this.getLockedTable().rows;
54519 var len = mrows.length-1;
54520 endIndex = Math.min(endIndex || len, len);
54521 for(var i = startIndex; i <= endIndex; i++){
54522 var m = mrows[i], l = lrows[i];
54523 var h = Math.max(m.offsetHeight, l.offsetHeight);
54524 m.style.height = l.style.height = h + "px";
54529 layout : function(initialRender, is2ndPass){
54531 var auto = g.autoHeight;
54532 var scrollOffset = 16;
54533 var c = g.getGridEl(), cm = this.cm,
54534 expandCol = g.autoExpandColumn,
54536 //c.beginMeasure();
54538 if(!c.dom.offsetWidth){ // display:none?
54540 this.lockedWrap.show();
54541 this.mainWrap.show();
54546 var hasLock = this.cm.isLocked(0);
54548 var tbh = this.headerPanel.getHeight();
54549 var bbh = this.footerPanel.getHeight();
54552 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54553 var newHeight = ch + c.getBorderWidth("tb");
54555 newHeight = Math.min(g.maxHeight, newHeight);
54557 c.setHeight(newHeight);
54561 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54564 var s = this.scroller;
54566 var csize = c.getSize(true);
54568 this.el.setSize(csize.width, csize.height);
54570 this.headerPanel.setWidth(csize.width);
54571 this.footerPanel.setWidth(csize.width);
54573 var hdHeight = this.mainHd.getHeight();
54574 var vw = csize.width;
54575 var vh = csize.height - (tbh + bbh);
54579 var bt = this.getBodyTable();
54580 var ltWidth = hasLock ?
54581 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54583 var scrollHeight = bt.offsetHeight;
54584 var scrollWidth = ltWidth + bt.offsetWidth;
54585 var vscroll = false, hscroll = false;
54587 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54589 var lw = this.lockedWrap, mw = this.mainWrap;
54590 var lb = this.lockedBody, mb = this.mainBody;
54592 setTimeout(function(){
54593 var t = s.dom.offsetTop;
54594 var w = s.dom.clientWidth,
54595 h = s.dom.clientHeight;
54598 lw.setSize(ltWidth, h);
54600 mw.setLeftTop(ltWidth, t);
54601 mw.setSize(w-ltWidth, h);
54603 lb.setHeight(h-hdHeight);
54604 mb.setHeight(h-hdHeight);
54606 if(is2ndPass !== true && !gv.userResized && expandCol){
54607 // high speed resize without full column calculation
54609 var ci = cm.getIndexById(expandCol);
54611 ci = cm.findColumnIndex(expandCol);
54613 ci = Math.max(0, ci); // make sure it's got at least the first col.
54614 var expandId = cm.getColumnId(ci);
54615 var tw = cm.getTotalWidth(false);
54616 var currentWidth = cm.getColumnWidth(ci);
54617 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54618 if(currentWidth != cw){
54619 cm.setColumnWidth(ci, cw, true);
54620 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54621 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54622 gv.updateSplitters();
54623 gv.layout(false, true);
54635 onWindowResize : function(){
54636 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54642 appendFooter : function(parentEl){
54646 sortAscText : "Sort Ascending",
54647 sortDescText : "Sort Descending",
54648 lockText : "Lock Column",
54649 unlockText : "Unlock Column",
54650 columnsText : "Columns",
54652 columnsWiderText : "Wider",
54653 columnsNarrowText : "Thinner"
54657 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54658 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54659 this.proxy.el.addClass('x-grid3-col-dd');
54662 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54663 handleMouseDown : function(e){
54667 callHandleMouseDown : function(e){
54668 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54673 * Ext JS Library 1.1.1
54674 * Copyright(c) 2006-2007, Ext JS, LLC.
54676 * Originally Released Under LGPL - original licence link has changed is not relivant.
54679 * <script type="text/javascript">
54683 // This is a support class used internally by the Grid components
54684 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54686 this.view = grid.getView();
54687 this.proxy = this.view.resizeProxy;
54688 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54689 "gridSplitters" + this.grid.getGridEl().id, {
54690 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54692 this.setHandleElId(Roo.id(hd));
54693 this.setOuterHandleElId(Roo.id(hd2));
54694 this.scroll = false;
54696 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54697 fly: Roo.Element.fly,
54699 b4StartDrag : function(x, y){
54700 this.view.headersDisabled = true;
54701 this.proxy.setHeight(this.view.mainWrap.getHeight());
54702 var w = this.cm.getColumnWidth(this.cellIndex);
54703 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54704 this.resetConstraints();
54705 this.setXConstraint(minw, 1000);
54706 this.setYConstraint(0, 0);
54707 this.minX = x - minw;
54708 this.maxX = x + 1000;
54710 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54714 handleMouseDown : function(e){
54715 ev = Roo.EventObject.setEvent(e);
54716 var t = this.fly(ev.getTarget());
54717 if(t.hasClass("x-grid-split")){
54718 this.cellIndex = this.view.getCellIndex(t.dom);
54719 this.split = t.dom;
54720 this.cm = this.grid.colModel;
54721 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54722 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54727 endDrag : function(e){
54728 this.view.headersDisabled = false;
54729 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54730 var diff = endX - this.startPos;
54731 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54734 autoOffset : function(){
54735 this.setDelta(0,0);
54739 * Ext JS Library 1.1.1
54740 * Copyright(c) 2006-2007, Ext JS, LLC.
54742 * Originally Released Under LGPL - original licence link has changed is not relivant.
54745 * <script type="text/javascript">
54749 // This is a support class used internally by the Grid components
54750 Roo.grid.GridDragZone = function(grid, config){
54751 this.view = grid.getView();
54752 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54753 if(this.view.lockedBody){
54754 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54755 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54757 this.scroll = false;
54759 this.ddel = document.createElement('div');
54760 this.ddel.className = 'x-grid-dd-wrap';
54763 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54764 ddGroup : "GridDD",
54766 getDragData : function(e){
54767 var t = Roo.lib.Event.getTarget(e);
54768 var rowIndex = this.view.findRowIndex(t);
54769 var sm = this.grid.selModel;
54771 //Roo.log(rowIndex);
54773 if (sm.getSelectedCell) {
54774 // cell selection..
54775 if (!sm.getSelectedCell()) {
54778 if (rowIndex != sm.getSelectedCell()[0]) {
54784 if(rowIndex !== false){
54789 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54791 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54794 if (e.hasModifier()){
54795 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54798 Roo.log("getDragData");
54803 rowIndex: rowIndex,
54804 selections:sm.getSelections ? sm.getSelections() : (
54805 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54812 onInitDrag : function(e){
54813 var data = this.dragData;
54814 this.ddel.innerHTML = this.grid.getDragDropText();
54815 this.proxy.update(this.ddel);
54816 // fire start drag?
54819 afterRepair : function(){
54820 this.dragging = false;
54823 getRepairXY : function(e, data){
54827 onEndDrag : function(data, e){
54831 onValidDrop : function(dd, e, id){
54836 beforeInvalidDrop : function(e, id){
54841 * Ext JS Library 1.1.1
54842 * Copyright(c) 2006-2007, Ext JS, LLC.
54844 * Originally Released Under LGPL - original licence link has changed is not relivant.
54847 * <script type="text/javascript">
54852 * @class Roo.grid.ColumnModel
54853 * @extends Roo.util.Observable
54854 * This is the default implementation of a ColumnModel used by the Grid. It defines
54855 * the columns in the grid.
54858 var colModel = new Roo.grid.ColumnModel([
54859 {header: "Ticker", width: 60, sortable: true, locked: true},
54860 {header: "Company Name", width: 150, sortable: true},
54861 {header: "Market Cap.", width: 100, sortable: true},
54862 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54863 {header: "Employees", width: 100, sortable: true, resizable: false}
54868 * The config options listed for this class are options which may appear in each
54869 * individual column definition.
54870 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54872 * @param {Object} config An Array of column config objects. See this class's
54873 * config objects for details.
54875 Roo.grid.ColumnModel = function(config){
54877 * The config passed into the constructor
54879 this.config = config;
54882 // if no id, create one
54883 // if the column does not have a dataIndex mapping,
54884 // map it to the order it is in the config
54885 for(var i = 0, len = config.length; i < len; i++){
54887 if(typeof c.dataIndex == "undefined"){
54890 if(typeof c.renderer == "string"){
54891 c.renderer = Roo.util.Format[c.renderer];
54893 if(typeof c.id == "undefined"){
54896 if(c.editor && c.editor.xtype){
54897 c.editor = Roo.factory(c.editor, Roo.grid);
54899 if(c.editor && c.editor.isFormField){
54900 c.editor = new Roo.grid.GridEditor(c.editor);
54902 this.lookup[c.id] = c;
54906 * The width of columns which have no width specified (defaults to 100)
54909 this.defaultWidth = 100;
54912 * Default sortable of columns which have no sortable specified (defaults to false)
54915 this.defaultSortable = false;
54919 * @event widthchange
54920 * Fires when the width of a column changes.
54921 * @param {ColumnModel} this
54922 * @param {Number} columnIndex The column index
54923 * @param {Number} newWidth The new width
54925 "widthchange": true,
54927 * @event headerchange
54928 * Fires when the text of a header changes.
54929 * @param {ColumnModel} this
54930 * @param {Number} columnIndex The column index
54931 * @param {Number} newText The new header text
54933 "headerchange": true,
54935 * @event hiddenchange
54936 * Fires when a column is hidden or "unhidden".
54937 * @param {ColumnModel} this
54938 * @param {Number} columnIndex The column index
54939 * @param {Boolean} hidden true if hidden, false otherwise
54941 "hiddenchange": true,
54943 * @event columnmoved
54944 * Fires when a column is moved.
54945 * @param {ColumnModel} this
54946 * @param {Number} oldIndex
54947 * @param {Number} newIndex
54949 "columnmoved" : true,
54951 * @event columlockchange
54952 * Fires when a column's locked state is changed
54953 * @param {ColumnModel} this
54954 * @param {Number} colIndex
54955 * @param {Boolean} locked true if locked
54957 "columnlockchange" : true
54959 Roo.grid.ColumnModel.superclass.constructor.call(this);
54961 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54963 * @cfg {String} header The header text to display in the Grid view.
54966 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54967 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54968 * specified, the column's index is used as an index into the Record's data Array.
54971 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54972 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54975 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54976 * Defaults to the value of the {@link #defaultSortable} property.
54977 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54980 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54983 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54986 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54989 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54992 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54993 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54994 * default renderer uses the raw data value. If an object is returned (bootstrap only)
54995 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
54998 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55001 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55005 * Returns the id of the column at the specified index.
55006 * @param {Number} index The column index
55007 * @return {String} the id
55009 getColumnId : function(index){
55010 return this.config[index].id;
55014 * Returns the column for a specified id.
55015 * @param {String} id The column id
55016 * @return {Object} the column
55018 getColumnById : function(id){
55019 return this.lookup[id];
55024 * Returns the column for a specified dataIndex.
55025 * @param {String} dataIndex The column dataIndex
55026 * @return {Object|Boolean} the column or false if not found
55028 getColumnByDataIndex: function(dataIndex){
55029 var index = this.findColumnIndex(dataIndex);
55030 return index > -1 ? this.config[index] : false;
55034 * Returns the index for a specified column id.
55035 * @param {String} id The column id
55036 * @return {Number} the index, or -1 if not found
55038 getIndexById : function(id){
55039 for(var i = 0, len = this.config.length; i < len; i++){
55040 if(this.config[i].id == id){
55048 * Returns the index for a specified column dataIndex.
55049 * @param {String} dataIndex The column dataIndex
55050 * @return {Number} the index, or -1 if not found
55053 findColumnIndex : function(dataIndex){
55054 for(var i = 0, len = this.config.length; i < len; i++){
55055 if(this.config[i].dataIndex == dataIndex){
55063 moveColumn : function(oldIndex, newIndex){
55064 var c = this.config[oldIndex];
55065 this.config.splice(oldIndex, 1);
55066 this.config.splice(newIndex, 0, c);
55067 this.dataMap = null;
55068 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55071 isLocked : function(colIndex){
55072 return this.config[colIndex].locked === true;
55075 setLocked : function(colIndex, value, suppressEvent){
55076 if(this.isLocked(colIndex) == value){
55079 this.config[colIndex].locked = value;
55080 if(!suppressEvent){
55081 this.fireEvent("columnlockchange", this, colIndex, value);
55085 getTotalLockedWidth : function(){
55086 var totalWidth = 0;
55087 for(var i = 0; i < this.config.length; i++){
55088 if(this.isLocked(i) && !this.isHidden(i)){
55089 this.totalWidth += this.getColumnWidth(i);
55095 getLockedCount : function(){
55096 for(var i = 0, len = this.config.length; i < len; i++){
55097 if(!this.isLocked(i)){
55104 * Returns the number of columns.
55107 getColumnCount : function(visibleOnly){
55108 if(visibleOnly === true){
55110 for(var i = 0, len = this.config.length; i < len; i++){
55111 if(!this.isHidden(i)){
55117 return this.config.length;
55121 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55122 * @param {Function} fn
55123 * @param {Object} scope (optional)
55124 * @return {Array} result
55126 getColumnsBy : function(fn, scope){
55128 for(var i = 0, len = this.config.length; i < len; i++){
55129 var c = this.config[i];
55130 if(fn.call(scope||this, c, i) === true){
55138 * Returns true if the specified column is sortable.
55139 * @param {Number} col The column index
55140 * @return {Boolean}
55142 isSortable : function(col){
55143 if(typeof this.config[col].sortable == "undefined"){
55144 return this.defaultSortable;
55146 return this.config[col].sortable;
55150 * Returns the rendering (formatting) function defined for the column.
55151 * @param {Number} col The column index.
55152 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55154 getRenderer : function(col){
55155 if(!this.config[col].renderer){
55156 return Roo.grid.ColumnModel.defaultRenderer;
55158 return this.config[col].renderer;
55162 * Sets the rendering (formatting) function for a column.
55163 * @param {Number} col The column index
55164 * @param {Function} fn The function to use to process the cell's raw data
55165 * to return HTML markup for the grid view. The render function is called with
55166 * the following parameters:<ul>
55167 * <li>Data value.</li>
55168 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55169 * <li>css A CSS style string to apply to the table cell.</li>
55170 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55171 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55172 * <li>Row index</li>
55173 * <li>Column index</li>
55174 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55176 setRenderer : function(col, fn){
55177 this.config[col].renderer = fn;
55181 * Returns the width for the specified column.
55182 * @param {Number} col The column index
55185 getColumnWidth : function(col){
55186 return this.config[col].width * 1 || this.defaultWidth;
55190 * Sets the width for a column.
55191 * @param {Number} col The column index
55192 * @param {Number} width The new width
55194 setColumnWidth : function(col, width, suppressEvent){
55195 this.config[col].width = width;
55196 this.totalWidth = null;
55197 if(!suppressEvent){
55198 this.fireEvent("widthchange", this, col, width);
55203 * Returns the total width of all columns.
55204 * @param {Boolean} includeHidden True to include hidden column widths
55207 getTotalWidth : function(includeHidden){
55208 if(!this.totalWidth){
55209 this.totalWidth = 0;
55210 for(var i = 0, len = this.config.length; i < len; i++){
55211 if(includeHidden || !this.isHidden(i)){
55212 this.totalWidth += this.getColumnWidth(i);
55216 return this.totalWidth;
55220 * Returns the header for the specified column.
55221 * @param {Number} col The column index
55224 getColumnHeader : function(col){
55225 return this.config[col].header;
55229 * Sets the header for a column.
55230 * @param {Number} col The column index
55231 * @param {String} header The new header
55233 setColumnHeader : function(col, header){
55234 this.config[col].header = header;
55235 this.fireEvent("headerchange", this, col, header);
55239 * Returns the tooltip for the specified column.
55240 * @param {Number} col The column index
55243 getColumnTooltip : function(col){
55244 return this.config[col].tooltip;
55247 * Sets the tooltip for a column.
55248 * @param {Number} col The column index
55249 * @param {String} tooltip The new tooltip
55251 setColumnTooltip : function(col, tooltip){
55252 this.config[col].tooltip = tooltip;
55256 * Returns the dataIndex for the specified column.
55257 * @param {Number} col The column index
55260 getDataIndex : function(col){
55261 return this.config[col].dataIndex;
55265 * Sets the dataIndex for a column.
55266 * @param {Number} col The column index
55267 * @param {Number} dataIndex The new dataIndex
55269 setDataIndex : function(col, dataIndex){
55270 this.config[col].dataIndex = dataIndex;
55276 * Returns true if the cell is editable.
55277 * @param {Number} colIndex The column index
55278 * @param {Number} rowIndex The row index
55279 * @return {Boolean}
55281 isCellEditable : function(colIndex, rowIndex){
55282 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55286 * Returns the editor defined for the cell/column.
55287 * return false or null to disable editing.
55288 * @param {Number} colIndex The column index
55289 * @param {Number} rowIndex The row index
55292 getCellEditor : function(colIndex, rowIndex){
55293 return this.config[colIndex].editor;
55297 * Sets if a column is editable.
55298 * @param {Number} col The column index
55299 * @param {Boolean} editable True if the column is editable
55301 setEditable : function(col, editable){
55302 this.config[col].editable = editable;
55307 * Returns true if the column is hidden.
55308 * @param {Number} colIndex The column index
55309 * @return {Boolean}
55311 isHidden : function(colIndex){
55312 return this.config[colIndex].hidden;
55317 * Returns true if the column width cannot be changed
55319 isFixed : function(colIndex){
55320 return this.config[colIndex].fixed;
55324 * Returns true if the column can be resized
55325 * @return {Boolean}
55327 isResizable : function(colIndex){
55328 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55331 * Sets if a column is hidden.
55332 * @param {Number} colIndex The column index
55333 * @param {Boolean} hidden True if the column is hidden
55335 setHidden : function(colIndex, hidden){
55336 this.config[colIndex].hidden = hidden;
55337 this.totalWidth = null;
55338 this.fireEvent("hiddenchange", this, colIndex, hidden);
55342 * Sets the editor for a column.
55343 * @param {Number} col The column index
55344 * @param {Object} editor The editor object
55346 setEditor : function(col, editor){
55347 this.config[col].editor = editor;
55351 Roo.grid.ColumnModel.defaultRenderer = function(value){
55352 if(typeof value == "string" && value.length < 1){
55358 // Alias for backwards compatibility
55359 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55362 * Ext JS Library 1.1.1
55363 * Copyright(c) 2006-2007, Ext JS, LLC.
55365 * Originally Released Under LGPL - original licence link has changed is not relivant.
55368 * <script type="text/javascript">
55372 * @class Roo.grid.AbstractSelectionModel
55373 * @extends Roo.util.Observable
55374 * Abstract base class for grid SelectionModels. It provides the interface that should be
55375 * implemented by descendant classes. This class should not be directly instantiated.
55378 Roo.grid.AbstractSelectionModel = function(){
55379 this.locked = false;
55380 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55383 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55384 /** @ignore Called by the grid automatically. Do not call directly. */
55385 init : function(grid){
55391 * Locks the selections.
55394 this.locked = true;
55398 * Unlocks the selections.
55400 unlock : function(){
55401 this.locked = false;
55405 * Returns true if the selections are locked.
55406 * @return {Boolean}
55408 isLocked : function(){
55409 return this.locked;
55413 * Ext JS Library 1.1.1
55414 * Copyright(c) 2006-2007, Ext JS, LLC.
55416 * Originally Released Under LGPL - original licence link has changed is not relivant.
55419 * <script type="text/javascript">
55422 * @extends Roo.grid.AbstractSelectionModel
55423 * @class Roo.grid.RowSelectionModel
55424 * The default SelectionModel used by {@link Roo.grid.Grid}.
55425 * It supports multiple selections and keyboard selection/navigation.
55427 * @param {Object} config
55429 Roo.grid.RowSelectionModel = function(config){
55430 Roo.apply(this, config);
55431 this.selections = new Roo.util.MixedCollection(false, function(o){
55436 this.lastActive = false;
55440 * @event selectionchange
55441 * Fires when the selection changes
55442 * @param {SelectionModel} this
55444 "selectionchange" : true,
55446 * @event afterselectionchange
55447 * Fires after the selection changes (eg. by key press or clicking)
55448 * @param {SelectionModel} this
55450 "afterselectionchange" : true,
55452 * @event beforerowselect
55453 * Fires when a row is selected being selected, return false to cancel.
55454 * @param {SelectionModel} this
55455 * @param {Number} rowIndex The selected index
55456 * @param {Boolean} keepExisting False if other selections will be cleared
55458 "beforerowselect" : true,
55461 * Fires when a row is selected.
55462 * @param {SelectionModel} this
55463 * @param {Number} rowIndex The selected index
55464 * @param {Roo.data.Record} r The record
55466 "rowselect" : true,
55468 * @event rowdeselect
55469 * Fires when a row is deselected.
55470 * @param {SelectionModel} this
55471 * @param {Number} rowIndex The selected index
55473 "rowdeselect" : true
55475 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55476 this.locked = false;
55479 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55481 * @cfg {Boolean} singleSelect
55482 * True to allow selection of only one row at a time (defaults to false)
55484 singleSelect : false,
55487 initEvents : function(){
55489 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55490 this.grid.on("mousedown", this.handleMouseDown, this);
55491 }else{ // allow click to work like normal
55492 this.grid.on("rowclick", this.handleDragableRowClick, this);
55495 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55496 "up" : function(e){
55498 this.selectPrevious(e.shiftKey);
55499 }else if(this.last !== false && this.lastActive !== false){
55500 var last = this.last;
55501 this.selectRange(this.last, this.lastActive-1);
55502 this.grid.getView().focusRow(this.lastActive);
55503 if(last !== false){
55507 this.selectFirstRow();
55509 this.fireEvent("afterselectionchange", this);
55511 "down" : function(e){
55513 this.selectNext(e.shiftKey);
55514 }else if(this.last !== false && this.lastActive !== false){
55515 var last = this.last;
55516 this.selectRange(this.last, this.lastActive+1);
55517 this.grid.getView().focusRow(this.lastActive);
55518 if(last !== false){
55522 this.selectFirstRow();
55524 this.fireEvent("afterselectionchange", this);
55529 var view = this.grid.view;
55530 view.on("refresh", this.onRefresh, this);
55531 view.on("rowupdated", this.onRowUpdated, this);
55532 view.on("rowremoved", this.onRemove, this);
55536 onRefresh : function(){
55537 var ds = this.grid.dataSource, i, v = this.grid.view;
55538 var s = this.selections;
55539 s.each(function(r){
55540 if((i = ds.indexOfId(r.id)) != -1){
55549 onRemove : function(v, index, r){
55550 this.selections.remove(r);
55554 onRowUpdated : function(v, index, r){
55555 if(this.isSelected(r)){
55556 v.onRowSelect(index);
55562 * @param {Array} records The records to select
55563 * @param {Boolean} keepExisting (optional) True to keep existing selections
55565 selectRecords : function(records, keepExisting){
55567 this.clearSelections();
55569 var ds = this.grid.dataSource;
55570 for(var i = 0, len = records.length; i < len; i++){
55571 this.selectRow(ds.indexOf(records[i]), true);
55576 * Gets the number of selected rows.
55579 getCount : function(){
55580 return this.selections.length;
55584 * Selects the first row in the grid.
55586 selectFirstRow : function(){
55591 * Select the last row.
55592 * @param {Boolean} keepExisting (optional) True to keep existing selections
55594 selectLastRow : function(keepExisting){
55595 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55599 * Selects the row immediately following the last selected row.
55600 * @param {Boolean} keepExisting (optional) True to keep existing selections
55602 selectNext : function(keepExisting){
55603 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55604 this.selectRow(this.last+1, keepExisting);
55605 this.grid.getView().focusRow(this.last);
55610 * Selects the row that precedes the last selected row.
55611 * @param {Boolean} keepExisting (optional) True to keep existing selections
55613 selectPrevious : function(keepExisting){
55615 this.selectRow(this.last-1, keepExisting);
55616 this.grid.getView().focusRow(this.last);
55621 * Returns the selected records
55622 * @return {Array} Array of selected records
55624 getSelections : function(){
55625 return [].concat(this.selections.items);
55629 * Returns the first selected record.
55632 getSelected : function(){
55633 return this.selections.itemAt(0);
55638 * Clears all selections.
55640 clearSelections : function(fast){
55641 if(this.locked) return;
55643 var ds = this.grid.dataSource;
55644 var s = this.selections;
55645 s.each(function(r){
55646 this.deselectRow(ds.indexOfId(r.id));
55650 this.selections.clear();
55657 * Selects all rows.
55659 selectAll : function(){
55660 if(this.locked) return;
55661 this.selections.clear();
55662 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55663 this.selectRow(i, true);
55668 * Returns True if there is a selection.
55669 * @return {Boolean}
55671 hasSelection : function(){
55672 return this.selections.length > 0;
55676 * Returns True if the specified row is selected.
55677 * @param {Number/Record} record The record or index of the record to check
55678 * @return {Boolean}
55680 isSelected : function(index){
55681 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55682 return (r && this.selections.key(r.id) ? true : false);
55686 * Returns True if the specified record id is selected.
55687 * @param {String} id The id of record to check
55688 * @return {Boolean}
55690 isIdSelected : function(id){
55691 return (this.selections.key(id) ? true : false);
55695 handleMouseDown : function(e, t){
55696 var view = this.grid.getView(), rowIndex;
55697 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55700 if(e.shiftKey && this.last !== false){
55701 var last = this.last;
55702 this.selectRange(last, rowIndex, e.ctrlKey);
55703 this.last = last; // reset the last
55704 view.focusRow(rowIndex);
55706 var isSelected = this.isSelected(rowIndex);
55707 if(e.button !== 0 && isSelected){
55708 view.focusRow(rowIndex);
55709 }else if(e.ctrlKey && isSelected){
55710 this.deselectRow(rowIndex);
55711 }else if(!isSelected){
55712 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55713 view.focusRow(rowIndex);
55716 this.fireEvent("afterselectionchange", this);
55719 handleDragableRowClick : function(grid, rowIndex, e)
55721 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55722 this.selectRow(rowIndex, false);
55723 grid.view.focusRow(rowIndex);
55724 this.fireEvent("afterselectionchange", this);
55729 * Selects multiple rows.
55730 * @param {Array} rows Array of the indexes of the row to select
55731 * @param {Boolean} keepExisting (optional) True to keep existing selections
55733 selectRows : function(rows, keepExisting){
55735 this.clearSelections();
55737 for(var i = 0, len = rows.length; i < len; i++){
55738 this.selectRow(rows[i], true);
55743 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55744 * @param {Number} startRow The index of the first row in the range
55745 * @param {Number} endRow The index of the last row in the range
55746 * @param {Boolean} keepExisting (optional) True to retain existing selections
55748 selectRange : function(startRow, endRow, keepExisting){
55749 if(this.locked) return;
55751 this.clearSelections();
55753 if(startRow <= endRow){
55754 for(var i = startRow; i <= endRow; i++){
55755 this.selectRow(i, true);
55758 for(var i = startRow; i >= endRow; i--){
55759 this.selectRow(i, true);
55765 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55766 * @param {Number} startRow The index of the first row in the range
55767 * @param {Number} endRow The index of the last row in the range
55769 deselectRange : function(startRow, endRow, preventViewNotify){
55770 if(this.locked) return;
55771 for(var i = startRow; i <= endRow; i++){
55772 this.deselectRow(i, preventViewNotify);
55778 * @param {Number} row The index of the row to select
55779 * @param {Boolean} keepExisting (optional) True to keep existing selections
55781 selectRow : function(index, keepExisting, preventViewNotify){
55782 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55783 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55784 if(!keepExisting || this.singleSelect){
55785 this.clearSelections();
55787 var r = this.grid.dataSource.getAt(index);
55788 this.selections.add(r);
55789 this.last = this.lastActive = index;
55790 if(!preventViewNotify){
55791 this.grid.getView().onRowSelect(index);
55793 this.fireEvent("rowselect", this, index, r);
55794 this.fireEvent("selectionchange", this);
55800 * @param {Number} row The index of the row to deselect
55802 deselectRow : function(index, preventViewNotify){
55803 if(this.locked) return;
55804 if(this.last == index){
55807 if(this.lastActive == index){
55808 this.lastActive = false;
55810 var r = this.grid.dataSource.getAt(index);
55811 this.selections.remove(r);
55812 if(!preventViewNotify){
55813 this.grid.getView().onRowDeselect(index);
55815 this.fireEvent("rowdeselect", this, index);
55816 this.fireEvent("selectionchange", this);
55820 restoreLast : function(){
55822 this.last = this._last;
55827 acceptsNav : function(row, col, cm){
55828 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55832 onEditorKey : function(field, e){
55833 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55838 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55840 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55842 }else if(k == e.ENTER && !e.ctrlKey){
55846 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55848 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55850 }else if(k == e.ESC){
55854 g.startEditing(newCell[0], newCell[1]);
55859 * Ext JS Library 1.1.1
55860 * Copyright(c) 2006-2007, Ext JS, LLC.
55862 * Originally Released Under LGPL - original licence link has changed is not relivant.
55865 * <script type="text/javascript">
55868 * @class Roo.grid.CellSelectionModel
55869 * @extends Roo.grid.AbstractSelectionModel
55870 * This class provides the basic implementation for cell selection in a grid.
55872 * @param {Object} config The object containing the configuration of this model.
55873 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55875 Roo.grid.CellSelectionModel = function(config){
55876 Roo.apply(this, config);
55878 this.selection = null;
55882 * @event beforerowselect
55883 * Fires before a cell is selected.
55884 * @param {SelectionModel} this
55885 * @param {Number} rowIndex The selected row index
55886 * @param {Number} colIndex The selected cell index
55888 "beforecellselect" : true,
55890 * @event cellselect
55891 * Fires when a cell is selected.
55892 * @param {SelectionModel} this
55893 * @param {Number} rowIndex The selected row index
55894 * @param {Number} colIndex The selected cell index
55896 "cellselect" : true,
55898 * @event selectionchange
55899 * Fires when the active selection changes.
55900 * @param {SelectionModel} this
55901 * @param {Object} selection null for no selection or an object (o) with two properties
55903 <li>o.record: the record object for the row the selection is in</li>
55904 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55907 "selectionchange" : true,
55910 * Fires when the tab (or enter) was pressed on the last editable cell
55911 * You can use this to trigger add new row.
55912 * @param {SelectionModel} this
55916 * @event beforeeditnext
55917 * Fires before the next editable sell is made active
55918 * You can use this to skip to another cell or fire the tabend
55919 * if you set cell to false
55920 * @param {Object} eventdata object : { cell : [ row, col ] }
55922 "beforeeditnext" : true
55924 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55927 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55929 enter_is_tab: false,
55932 initEvents : function(){
55933 this.grid.on("mousedown", this.handleMouseDown, this);
55934 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55935 var view = this.grid.view;
55936 view.on("refresh", this.onViewChange, this);
55937 view.on("rowupdated", this.onRowUpdated, this);
55938 view.on("beforerowremoved", this.clearSelections, this);
55939 view.on("beforerowsinserted", this.clearSelections, this);
55940 if(this.grid.isEditor){
55941 this.grid.on("beforeedit", this.beforeEdit, this);
55946 beforeEdit : function(e){
55947 this.select(e.row, e.column, false, true, e.record);
55951 onRowUpdated : function(v, index, r){
55952 if(this.selection && this.selection.record == r){
55953 v.onCellSelect(index, this.selection.cell[1]);
55958 onViewChange : function(){
55959 this.clearSelections(true);
55963 * Returns the currently selected cell,.
55964 * @return {Array} The selected cell (row, column) or null if none selected.
55966 getSelectedCell : function(){
55967 return this.selection ? this.selection.cell : null;
55971 * Clears all selections.
55972 * @param {Boolean} true to prevent the gridview from being notified about the change.
55974 clearSelections : function(preventNotify){
55975 var s = this.selection;
55977 if(preventNotify !== true){
55978 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55980 this.selection = null;
55981 this.fireEvent("selectionchange", this, null);
55986 * Returns true if there is a selection.
55987 * @return {Boolean}
55989 hasSelection : function(){
55990 return this.selection ? true : false;
55994 handleMouseDown : function(e, t){
55995 var v = this.grid.getView();
55996 if(this.isLocked()){
55999 var row = v.findRowIndex(t);
56000 var cell = v.findCellIndex(t);
56001 if(row !== false && cell !== false){
56002 this.select(row, cell);
56008 * @param {Number} rowIndex
56009 * @param {Number} collIndex
56011 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56012 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56013 this.clearSelections();
56014 r = r || this.grid.dataSource.getAt(rowIndex);
56017 cell : [rowIndex, colIndex]
56019 if(!preventViewNotify){
56020 var v = this.grid.getView();
56021 v.onCellSelect(rowIndex, colIndex);
56022 if(preventFocus !== true){
56023 v.focusCell(rowIndex, colIndex);
56026 this.fireEvent("cellselect", this, rowIndex, colIndex);
56027 this.fireEvent("selectionchange", this, this.selection);
56032 isSelectable : function(rowIndex, colIndex, cm){
56033 return !cm.isHidden(colIndex);
56037 handleKeyDown : function(e){
56038 //Roo.log('Cell Sel Model handleKeyDown');
56039 if(!e.isNavKeyPress()){
56042 var g = this.grid, s = this.selection;
56045 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56047 this.select(cell[0], cell[1]);
56052 var walk = function(row, col, step){
56053 return g.walkCells(row, col, step, sm.isSelectable, sm);
56055 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56062 // handled by onEditorKey
56063 if (g.isEditor && g.editing) {
56067 newCell = walk(r, c-1, -1);
56069 newCell = walk(r, c+1, 1);
56074 newCell = walk(r+1, c, 1);
56078 newCell = walk(r-1, c, -1);
56082 newCell = walk(r, c+1, 1);
56086 newCell = walk(r, c-1, -1);
56091 if(g.isEditor && !g.editing){
56092 g.startEditing(r, c);
56101 this.select(newCell[0], newCell[1]);
56107 acceptsNav : function(row, col, cm){
56108 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56112 * @param {Number} field (not used) - as it's normally used as a listener
56113 * @param {Number} e - event - fake it by using
56115 * var e = Roo.EventObjectImpl.prototype;
56116 * e.keyCode = e.TAB
56120 onEditorKey : function(field, e){
56122 var k = e.getKey(),
56125 ed = g.activeEditor,
56127 ///Roo.log('onEditorKey' + k);
56130 if (this.enter_is_tab && k == e.ENTER) {
56136 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56138 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56144 } else if(k == e.ENTER && !e.ctrlKey){
56147 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56149 } else if(k == e.ESC){
56154 var ecall = { cell : newCell, forward : forward };
56155 this.fireEvent('beforeeditnext', ecall );
56156 newCell = ecall.cell;
56157 forward = ecall.forward;
56161 //Roo.log('next cell after edit');
56162 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56163 } else if (forward) {
56164 // tabbed past last
56165 this.fireEvent.defer(100, this, ['tabend',this]);
56170 * Ext JS Library 1.1.1
56171 * Copyright(c) 2006-2007, Ext JS, LLC.
56173 * Originally Released Under LGPL - original licence link has changed is not relivant.
56176 * <script type="text/javascript">
56180 * @class Roo.grid.EditorGrid
56181 * @extends Roo.grid.Grid
56182 * Class for creating and editable grid.
56183 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56184 * The container MUST have some type of size defined for the grid to fill. The container will be
56185 * automatically set to position relative if it isn't already.
56186 * @param {Object} dataSource The data model to bind to
56187 * @param {Object} colModel The column model with info about this grid's columns
56189 Roo.grid.EditorGrid = function(container, config){
56190 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56191 this.getGridEl().addClass("xedit-grid");
56193 if(!this.selModel){
56194 this.selModel = new Roo.grid.CellSelectionModel();
56197 this.activeEditor = null;
56201 * @event beforeedit
56202 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56203 * <ul style="padding:5px;padding-left:16px;">
56204 * <li>grid - This grid</li>
56205 * <li>record - The record being edited</li>
56206 * <li>field - The field name being edited</li>
56207 * <li>value - The value for the field being edited.</li>
56208 * <li>row - The grid row index</li>
56209 * <li>column - The grid column index</li>
56210 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56212 * @param {Object} e An edit event (see above for description)
56214 "beforeedit" : true,
56217 * Fires after a cell is edited. <br />
56218 * <ul style="padding:5px;padding-left:16px;">
56219 * <li>grid - This grid</li>
56220 * <li>record - The record being edited</li>
56221 * <li>field - The field name being edited</li>
56222 * <li>value - The value being set</li>
56223 * <li>originalValue - The original value for the field, before the edit.</li>
56224 * <li>row - The grid row index</li>
56225 * <li>column - The grid column index</li>
56227 * @param {Object} e An edit event (see above for description)
56229 "afteredit" : true,
56231 * @event validateedit
56232 * Fires after a cell is edited, but before the value is set in the record.
56233 * You can use this to modify the value being set in the field, Return false
56234 * to cancel the change. The edit event object has the following properties <br />
56235 * <ul style="padding:5px;padding-left:16px;">
56236 * <li>editor - This editor</li>
56237 * <li>grid - This grid</li>
56238 * <li>record - The record being edited</li>
56239 * <li>field - The field name being edited</li>
56240 * <li>value - The value being set</li>
56241 * <li>originalValue - The original value for the field, before the edit.</li>
56242 * <li>row - The grid row index</li>
56243 * <li>column - The grid column index</li>
56244 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56246 * @param {Object} e An edit event (see above for description)
56248 "validateedit" : true
56250 this.on("bodyscroll", this.stopEditing, this);
56251 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56254 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56256 * @cfg {Number} clicksToEdit
56257 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56264 trackMouseOver: false, // causes very odd FF errors
56266 onCellDblClick : function(g, row, col){
56267 this.startEditing(row, col);
56270 onEditComplete : function(ed, value, startValue){
56271 this.editing = false;
56272 this.activeEditor = null;
56273 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56275 var field = this.colModel.getDataIndex(ed.col);
56280 originalValue: startValue,
56287 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56290 if(String(value) !== String(startValue)){
56292 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56293 r.set(field, e.value);
56294 // if we are dealing with a combo box..
56295 // then we also set the 'name' colum to be the displayField
56296 if (ed.field.displayField && ed.field.name) {
56297 r.set(ed.field.name, ed.field.el.dom.value);
56300 delete e.cancel; //?? why!!!
56301 this.fireEvent("afteredit", e);
56304 this.fireEvent("afteredit", e); // always fire it!
56306 this.view.focusCell(ed.row, ed.col);
56310 * Starts editing the specified for the specified row/column
56311 * @param {Number} rowIndex
56312 * @param {Number} colIndex
56314 startEditing : function(row, col){
56315 this.stopEditing();
56316 if(this.colModel.isCellEditable(col, row)){
56317 this.view.ensureVisible(row, col, true);
56319 var r = this.dataSource.getAt(row);
56320 var field = this.colModel.getDataIndex(col);
56321 var cell = Roo.get(this.view.getCell(row,col));
56326 value: r.data[field],
56331 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56332 this.editing = true;
56333 var ed = this.colModel.getCellEditor(col, row);
56339 ed.render(ed.parentEl || document.body);
56345 (function(){ // complex but required for focus issues in safari, ie and opera
56349 ed.on("complete", this.onEditComplete, this, {single: true});
56350 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56351 this.activeEditor = ed;
56352 var v = r.data[field];
56353 ed.startEdit(this.view.getCell(row, col), v);
56354 // combo's with 'displayField and name set
56355 if (ed.field.displayField && ed.field.name) {
56356 ed.field.el.dom.value = r.data[ed.field.name];
56360 }).defer(50, this);
56366 * Stops any active editing
56368 stopEditing : function(){
56369 if(this.activeEditor){
56370 this.activeEditor.completeEdit();
56372 this.activeEditor = null;
56376 * Called to get grid's drag proxy text, by default returns this.ddText.
56379 getDragDropText : function(){
56380 var count = this.selModel.getSelectedCell() ? 1 : 0;
56381 return String.format(this.ddText, count, count == 1 ? '' : 's');
56386 * Ext JS Library 1.1.1
56387 * Copyright(c) 2006-2007, Ext JS, LLC.
56389 * Originally Released Under LGPL - original licence link has changed is not relivant.
56392 * <script type="text/javascript">
56395 // private - not really -- you end up using it !
56396 // This is a support class used internally by the Grid components
56399 * @class Roo.grid.GridEditor
56400 * @extends Roo.Editor
56401 * Class for creating and editable grid elements.
56402 * @param {Object} config any settings (must include field)
56404 Roo.grid.GridEditor = function(field, config){
56405 if (!config && field.field) {
56407 field = Roo.factory(config.field, Roo.form);
56409 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56410 field.monitorTab = false;
56413 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56416 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56419 alignment: "tl-tl",
56422 cls: "x-small-editor x-grid-editor",
56427 * Ext JS Library 1.1.1
56428 * Copyright(c) 2006-2007, Ext JS, LLC.
56430 * Originally Released Under LGPL - original licence link has changed is not relivant.
56433 * <script type="text/javascript">
56438 Roo.grid.PropertyRecord = Roo.data.Record.create([
56439 {name:'name',type:'string'}, 'value'
56443 Roo.grid.PropertyStore = function(grid, source){
56445 this.store = new Roo.data.Store({
56446 recordType : Roo.grid.PropertyRecord
56448 this.store.on('update', this.onUpdate, this);
56450 this.setSource(source);
56452 Roo.grid.PropertyStore.superclass.constructor.call(this);
56457 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56458 setSource : function(o){
56460 this.store.removeAll();
56463 if(this.isEditableValue(o[k])){
56464 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56467 this.store.loadRecords({records: data}, {}, true);
56470 onUpdate : function(ds, record, type){
56471 if(type == Roo.data.Record.EDIT){
56472 var v = record.data['value'];
56473 var oldValue = record.modified['value'];
56474 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56475 this.source[record.id] = v;
56477 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56484 getProperty : function(row){
56485 return this.store.getAt(row);
56488 isEditableValue: function(val){
56489 if(val && val instanceof Date){
56491 }else if(typeof val == 'object' || typeof val == 'function'){
56497 setValue : function(prop, value){
56498 this.source[prop] = value;
56499 this.store.getById(prop).set('value', value);
56502 getSource : function(){
56503 return this.source;
56507 Roo.grid.PropertyColumnModel = function(grid, store){
56510 g.PropertyColumnModel.superclass.constructor.call(this, [
56511 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56512 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56514 this.store = store;
56515 this.bselect = Roo.DomHelper.append(document.body, {
56516 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56517 {tag: 'option', value: 'true', html: 'true'},
56518 {tag: 'option', value: 'false', html: 'false'}
56521 Roo.id(this.bselect);
56524 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56525 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56526 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56527 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56528 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56530 this.renderCellDelegate = this.renderCell.createDelegate(this);
56531 this.renderPropDelegate = this.renderProp.createDelegate(this);
56534 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56538 valueText : 'Value',
56540 dateFormat : 'm/j/Y',
56543 renderDate : function(dateVal){
56544 return dateVal.dateFormat(this.dateFormat);
56547 renderBool : function(bVal){
56548 return bVal ? 'true' : 'false';
56551 isCellEditable : function(colIndex, rowIndex){
56552 return colIndex == 1;
56555 getRenderer : function(col){
56557 this.renderCellDelegate : this.renderPropDelegate;
56560 renderProp : function(v){
56561 return this.getPropertyName(v);
56564 renderCell : function(val){
56566 if(val instanceof Date){
56567 rv = this.renderDate(val);
56568 }else if(typeof val == 'boolean'){
56569 rv = this.renderBool(val);
56571 return Roo.util.Format.htmlEncode(rv);
56574 getPropertyName : function(name){
56575 var pn = this.grid.propertyNames;
56576 return pn && pn[name] ? pn[name] : name;
56579 getCellEditor : function(colIndex, rowIndex){
56580 var p = this.store.getProperty(rowIndex);
56581 var n = p.data['name'], val = p.data['value'];
56583 if(typeof(this.grid.customEditors[n]) == 'string'){
56584 return this.editors[this.grid.customEditors[n]];
56586 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56587 return this.grid.customEditors[n];
56589 if(val instanceof Date){
56590 return this.editors['date'];
56591 }else if(typeof val == 'number'){
56592 return this.editors['number'];
56593 }else if(typeof val == 'boolean'){
56594 return this.editors['boolean'];
56596 return this.editors['string'];
56602 * @class Roo.grid.PropertyGrid
56603 * @extends Roo.grid.EditorGrid
56604 * This class represents the interface of a component based property grid control.
56605 * <br><br>Usage:<pre><code>
56606 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56614 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56615 * The container MUST have some type of size defined for the grid to fill. The container will be
56616 * automatically set to position relative if it isn't already.
56617 * @param {Object} config A config object that sets properties on this grid.
56619 Roo.grid.PropertyGrid = function(container, config){
56620 config = config || {};
56621 var store = new Roo.grid.PropertyStore(this);
56622 this.store = store;
56623 var cm = new Roo.grid.PropertyColumnModel(this, store);
56624 store.store.sort('name', 'ASC');
56625 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56628 enableColLock:false,
56629 enableColumnMove:false,
56631 trackMouseOver: false,
56634 this.getGridEl().addClass('x-props-grid');
56635 this.lastEditRow = null;
56636 this.on('columnresize', this.onColumnResize, this);
56639 * @event beforepropertychange
56640 * Fires before a property changes (return false to stop?)
56641 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56642 * @param {String} id Record Id
56643 * @param {String} newval New Value
56644 * @param {String} oldval Old Value
56646 "beforepropertychange": true,
56648 * @event propertychange
56649 * Fires after a property changes
56650 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56651 * @param {String} id Record Id
56652 * @param {String} newval New Value
56653 * @param {String} oldval Old Value
56655 "propertychange": true
56657 this.customEditors = this.customEditors || {};
56659 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56662 * @cfg {Object} customEditors map of colnames=> custom editors.
56663 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56664 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56665 * false disables editing of the field.
56669 * @cfg {Object} propertyNames map of property Names to their displayed value
56672 render : function(){
56673 Roo.grid.PropertyGrid.superclass.render.call(this);
56674 this.autoSize.defer(100, this);
56677 autoSize : function(){
56678 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56680 this.view.fitColumns();
56684 onColumnResize : function(){
56685 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56689 * Sets the data for the Grid
56690 * accepts a Key => Value object of all the elements avaiable.
56691 * @param {Object} data to appear in grid.
56693 setSource : function(source){
56694 this.store.setSource(source);
56698 * Gets all the data from the grid.
56699 * @return {Object} data data stored in grid
56701 getSource : function(){
56702 return this.store.getSource();
56711 * @class Roo.grid.Calendar
56712 * @extends Roo.util.Grid
56713 * This class extends the Grid to provide a calendar widget
56714 * <br><br>Usage:<pre><code>
56715 var grid = new Roo.grid.Calendar("my-container-id", {
56718 selModel: mySelectionModel,
56719 autoSizeColumns: true,
56720 monitorWindowResize: false,
56721 trackMouseOver: true
56722 eventstore : real data store..
56728 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56729 * The container MUST have some type of size defined for the grid to fill. The container will be
56730 * automatically set to position relative if it isn't already.
56731 * @param {Object} config A config object that sets properties on this grid.
56733 Roo.grid.Calendar = function(container, config){
56734 // initialize the container
56735 this.container = Roo.get(container);
56736 this.container.update("");
56737 this.container.setStyle("overflow", "hidden");
56738 this.container.addClass('x-grid-container');
56740 this.id = this.container.id;
56742 Roo.apply(this, config);
56743 // check and correct shorthanded configs
56747 for (var r = 0;r < 6;r++) {
56750 for (var c =0;c < 7;c++) {
56754 if (this.eventStore) {
56755 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56756 this.eventStore.on('load',this.onLoad, this);
56757 this.eventStore.on('beforeload',this.clearEvents, this);
56761 this.dataSource = new Roo.data.Store({
56762 proxy: new Roo.data.MemoryProxy(rows),
56763 reader: new Roo.data.ArrayReader({}, [
56764 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56767 this.dataSource.load();
56768 this.ds = this.dataSource;
56769 this.ds.xmodule = this.xmodule || false;
56772 var cellRender = function(v,x,r)
56774 return String.format(
56775 '<div class="fc-day fc-widget-content"><div>' +
56776 '<div class="fc-event-container"></div>' +
56777 '<div class="fc-day-number">{0}</div>'+
56779 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56780 '</div></div>', v);
56785 this.colModel = new Roo.grid.ColumnModel( [
56787 xtype: 'ColumnModel',
56789 dataIndex : 'weekday0',
56791 renderer : cellRender
56794 xtype: 'ColumnModel',
56796 dataIndex : 'weekday1',
56798 renderer : cellRender
56801 xtype: 'ColumnModel',
56803 dataIndex : 'weekday2',
56804 header : 'Tuesday',
56805 renderer : cellRender
56808 xtype: 'ColumnModel',
56810 dataIndex : 'weekday3',
56811 header : 'Wednesday',
56812 renderer : cellRender
56815 xtype: 'ColumnModel',
56817 dataIndex : 'weekday4',
56818 header : 'Thursday',
56819 renderer : cellRender
56822 xtype: 'ColumnModel',
56824 dataIndex : 'weekday5',
56826 renderer : cellRender
56829 xtype: 'ColumnModel',
56831 dataIndex : 'weekday6',
56832 header : 'Saturday',
56833 renderer : cellRender
56836 this.cm = this.colModel;
56837 this.cm.xmodule = this.xmodule || false;
56841 //this.selModel = new Roo.grid.CellSelectionModel();
56842 //this.sm = this.selModel;
56843 //this.selModel.init(this);
56847 this.container.setWidth(this.width);
56851 this.container.setHeight(this.height);
56858 * The raw click event for the entire grid.
56859 * @param {Roo.EventObject} e
56864 * The raw dblclick event for the entire grid.
56865 * @param {Roo.EventObject} e
56869 * @event contextmenu
56870 * The raw contextmenu event for the entire grid.
56871 * @param {Roo.EventObject} e
56873 "contextmenu" : true,
56876 * The raw mousedown event for the entire grid.
56877 * @param {Roo.EventObject} e
56879 "mousedown" : true,
56882 * The raw mouseup event for the entire grid.
56883 * @param {Roo.EventObject} e
56888 * The raw mouseover event for the entire grid.
56889 * @param {Roo.EventObject} e
56891 "mouseover" : true,
56894 * The raw mouseout event for the entire grid.
56895 * @param {Roo.EventObject} e
56900 * The raw keypress event for the entire grid.
56901 * @param {Roo.EventObject} e
56906 * The raw keydown event for the entire grid.
56907 * @param {Roo.EventObject} e
56915 * Fires when a cell is clicked
56916 * @param {Grid} this
56917 * @param {Number} rowIndex
56918 * @param {Number} columnIndex
56919 * @param {Roo.EventObject} e
56921 "cellclick" : true,
56923 * @event celldblclick
56924 * Fires when a cell is double clicked
56925 * @param {Grid} this
56926 * @param {Number} rowIndex
56927 * @param {Number} columnIndex
56928 * @param {Roo.EventObject} e
56930 "celldblclick" : true,
56933 * Fires when a row is clicked
56934 * @param {Grid} this
56935 * @param {Number} rowIndex
56936 * @param {Roo.EventObject} e
56940 * @event rowdblclick
56941 * Fires when a row is double clicked
56942 * @param {Grid} this
56943 * @param {Number} rowIndex
56944 * @param {Roo.EventObject} e
56946 "rowdblclick" : true,
56948 * @event headerclick
56949 * Fires when a header is clicked
56950 * @param {Grid} this
56951 * @param {Number} columnIndex
56952 * @param {Roo.EventObject} e
56954 "headerclick" : true,
56956 * @event headerdblclick
56957 * Fires when a header cell is double clicked
56958 * @param {Grid} this
56959 * @param {Number} columnIndex
56960 * @param {Roo.EventObject} e
56962 "headerdblclick" : true,
56964 * @event rowcontextmenu
56965 * Fires when a row is right clicked
56966 * @param {Grid} this
56967 * @param {Number} rowIndex
56968 * @param {Roo.EventObject} e
56970 "rowcontextmenu" : true,
56972 * @event cellcontextmenu
56973 * Fires when a cell is right clicked
56974 * @param {Grid} this
56975 * @param {Number} rowIndex
56976 * @param {Number} cellIndex
56977 * @param {Roo.EventObject} e
56979 "cellcontextmenu" : true,
56981 * @event headercontextmenu
56982 * Fires when a header is right clicked
56983 * @param {Grid} this
56984 * @param {Number} columnIndex
56985 * @param {Roo.EventObject} e
56987 "headercontextmenu" : true,
56989 * @event bodyscroll
56990 * Fires when the body element is scrolled
56991 * @param {Number} scrollLeft
56992 * @param {Number} scrollTop
56994 "bodyscroll" : true,
56996 * @event columnresize
56997 * Fires when the user resizes a column
56998 * @param {Number} columnIndex
56999 * @param {Number} newSize
57001 "columnresize" : true,
57003 * @event columnmove
57004 * Fires when the user moves a column
57005 * @param {Number} oldIndex
57006 * @param {Number} newIndex
57008 "columnmove" : true,
57011 * Fires when row(s) start being dragged
57012 * @param {Grid} this
57013 * @param {Roo.GridDD} dd The drag drop object
57014 * @param {event} e The raw browser event
57016 "startdrag" : true,
57019 * Fires when a drag operation is complete
57020 * @param {Grid} this
57021 * @param {Roo.GridDD} dd The drag drop object
57022 * @param {event} e The raw browser event
57027 * Fires when dragged row(s) are dropped on a valid DD target
57028 * @param {Grid} this
57029 * @param {Roo.GridDD} dd The drag drop object
57030 * @param {String} targetId The target drag drop object
57031 * @param {event} e The raw browser event
57036 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57037 * @param {Grid} this
57038 * @param {Roo.GridDD} dd The drag drop object
57039 * @param {String} targetId The target drag drop object
57040 * @param {event} e The raw browser event
57045 * Fires when the dragged row(s) first cross another DD target while being dragged
57046 * @param {Grid} this
57047 * @param {Roo.GridDD} dd The drag drop object
57048 * @param {String} targetId The target drag drop object
57049 * @param {event} e The raw browser event
57051 "dragenter" : true,
57054 * Fires when the dragged row(s) leave another DD target while being dragged
57055 * @param {Grid} this
57056 * @param {Roo.GridDD} dd The drag drop object
57057 * @param {String} targetId The target drag drop object
57058 * @param {event} e The raw browser event
57063 * Fires when a row is rendered, so you can change add a style to it.
57064 * @param {GridView} gridview The grid view
57065 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57071 * Fires when the grid is rendered
57072 * @param {Grid} grid
57077 * Fires when a date is selected
57078 * @param {DatePicker} this
57079 * @param {Date} date The selected date
57083 * @event monthchange
57084 * Fires when the displayed month changes
57085 * @param {DatePicker} this
57086 * @param {Date} date The selected month
57088 'monthchange': true,
57090 * @event evententer
57091 * Fires when mouse over an event
57092 * @param {Calendar} this
57093 * @param {event} Event
57095 'evententer': true,
57097 * @event eventleave
57098 * Fires when the mouse leaves an
57099 * @param {Calendar} this
57102 'eventleave': true,
57104 * @event eventclick
57105 * Fires when the mouse click an
57106 * @param {Calendar} this
57109 'eventclick': true,
57111 * @event eventrender
57112 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57113 * @param {Calendar} this
57114 * @param {data} data to be modified
57116 'eventrender': true
57120 Roo.grid.Grid.superclass.constructor.call(this);
57121 this.on('render', function() {
57122 this.view.el.addClass('x-grid-cal');
57124 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57128 if (!Roo.grid.Calendar.style) {
57129 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57132 '.x-grid-cal .x-grid-col' : {
57133 height: 'auto !important',
57134 'vertical-align': 'top'
57136 '.x-grid-cal .fc-event-hori' : {
57147 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57149 * @cfg {Store} eventStore The store that loads events.
57154 activeDate : false,
57157 monitorWindowResize : false,
57160 resizeColumns : function() {
57161 var col = (this.view.el.getWidth() / 7) - 3;
57162 // loop through cols, and setWidth
57163 for(var i =0 ; i < 7 ; i++){
57164 this.cm.setColumnWidth(i, col);
57167 setDate :function(date) {
57169 Roo.log('setDate?');
57171 this.resizeColumns();
57172 var vd = this.activeDate;
57173 this.activeDate = date;
57174 // if(vd && this.el){
57175 // var t = date.getTime();
57176 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57177 // Roo.log('using add remove');
57179 // this.fireEvent('monthchange', this, date);
57181 // this.cells.removeClass("fc-state-highlight");
57182 // this.cells.each(function(c){
57183 // if(c.dateValue == t){
57184 // c.addClass("fc-state-highlight");
57185 // setTimeout(function(){
57186 // try{c.dom.firstChild.focus();}catch(e){}
57196 var days = date.getDaysInMonth();
57198 var firstOfMonth = date.getFirstDateOfMonth();
57199 var startingPos = firstOfMonth.getDay()-this.startDay;
57201 if(startingPos < this.startDay){
57205 var pm = date.add(Date.MONTH, -1);
57206 var prevStart = pm.getDaysInMonth()-startingPos;
57210 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57212 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57213 //this.cells.addClassOnOver('fc-state-hover');
57215 var cells = this.cells.elements;
57216 var textEls = this.textNodes;
57218 //Roo.each(cells, function(cell){
57219 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57222 days += startingPos;
57224 // convert everything to numbers so it's fast
57225 var day = 86400000;
57226 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57229 //Roo.log(prevStart);
57231 var today = new Date().clearTime().getTime();
57232 var sel = date.clearTime().getTime();
57233 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57234 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57235 var ddMatch = this.disabledDatesRE;
57236 var ddText = this.disabledDatesText;
57237 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57238 var ddaysText = this.disabledDaysText;
57239 var format = this.format;
57241 var setCellClass = function(cal, cell){
57243 //Roo.log('set Cell Class');
57245 var t = d.getTime();
57250 cell.dateValue = t;
57252 cell.className += " fc-today";
57253 cell.className += " fc-state-highlight";
57254 cell.title = cal.todayText;
57257 // disable highlight in other month..
57258 cell.className += " fc-state-highlight";
57263 //cell.className = " fc-state-disabled";
57264 cell.title = cal.minText;
57268 //cell.className = " fc-state-disabled";
57269 cell.title = cal.maxText;
57273 if(ddays.indexOf(d.getDay()) != -1){
57274 // cell.title = ddaysText;
57275 // cell.className = " fc-state-disabled";
57278 if(ddMatch && format){
57279 var fvalue = d.dateFormat(format);
57280 if(ddMatch.test(fvalue)){
57281 cell.title = ddText.replace("%0", fvalue);
57282 cell.className = " fc-state-disabled";
57286 if (!cell.initialClassName) {
57287 cell.initialClassName = cell.dom.className;
57290 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57295 for(; i < startingPos; i++) {
57296 cells[i].dayName = (++prevStart);
57297 Roo.log(textEls[i]);
57298 d.setDate(d.getDate()+1);
57300 //cells[i].className = "fc-past fc-other-month";
57301 setCellClass(this, cells[i]);
57306 for(; i < days; i++){
57307 intDay = i - startingPos + 1;
57308 cells[i].dayName = (intDay);
57309 d.setDate(d.getDate()+1);
57311 cells[i].className = ''; // "x-date-active";
57312 setCellClass(this, cells[i]);
57316 for(; i < 42; i++) {
57317 //textEls[i].innerHTML = (++extraDays);
57319 d.setDate(d.getDate()+1);
57320 cells[i].dayName = (++extraDays);
57321 cells[i].className = "fc-future fc-other-month";
57322 setCellClass(this, cells[i]);
57325 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57327 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57329 // this will cause all the cells to mis
57332 for (var r = 0;r < 6;r++) {
57333 for (var c =0;c < 7;c++) {
57334 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57338 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57339 for(i=0;i<cells.length;i++) {
57341 this.cells.elements[i].dayName = cells[i].dayName ;
57342 this.cells.elements[i].className = cells[i].className;
57343 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57344 this.cells.elements[i].title = cells[i].title ;
57345 this.cells.elements[i].dateValue = cells[i].dateValue ;
57351 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57352 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57354 ////if(totalRows != 6){
57355 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57356 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57359 this.fireEvent('monthchange', this, date);
57364 * Returns the grid's SelectionModel.
57365 * @return {SelectionModel}
57367 getSelectionModel : function(){
57368 if(!this.selModel){
57369 this.selModel = new Roo.grid.CellSelectionModel();
57371 return this.selModel;
57375 this.eventStore.load()
57381 findCell : function(dt) {
57382 dt = dt.clearTime().getTime();
57384 this.cells.each(function(c){
57385 //Roo.log("check " +c.dateValue + '?=' + dt);
57386 if(c.dateValue == dt){
57396 findCells : function(rec) {
57397 var s = rec.data.start_dt.clone().clearTime().getTime();
57399 var e= rec.data.end_dt.clone().clearTime().getTime();
57402 this.cells.each(function(c){
57403 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57405 if(c.dateValue > e){
57408 if(c.dateValue < s){
57417 findBestRow: function(cells)
57421 for (var i =0 ; i < cells.length;i++) {
57422 ret = Math.max(cells[i].rows || 0,ret);
57429 addItem : function(rec)
57431 // look for vertical location slot in
57432 var cells = this.findCells(rec);
57434 rec.row = this.findBestRow(cells);
57436 // work out the location.
57440 for(var i =0; i < cells.length; i++) {
57448 if (crow.start.getY() == cells[i].getY()) {
57450 crow.end = cells[i];
57466 for (var i = 0; i < cells.length;i++) {
57467 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57474 clearEvents: function() {
57476 if (!this.eventStore.getCount()) {
57479 // reset number of rows in cells.
57480 Roo.each(this.cells.elements, function(c){
57484 this.eventStore.each(function(e) {
57485 this.clearEvent(e);
57490 clearEvent : function(ev)
57493 Roo.each(ev.els, function(el) {
57494 el.un('mouseenter' ,this.onEventEnter, this);
57495 el.un('mouseleave' ,this.onEventLeave, this);
57503 renderEvent : function(ev,ctr) {
57505 ctr = this.view.el.select('.fc-event-container',true).first();
57509 this.clearEvent(ev);
57515 var cells = ev.cells;
57516 var rows = ev.rows;
57517 this.fireEvent('eventrender', this, ev);
57519 for(var i =0; i < rows.length; i++) {
57523 cls += ' fc-event-start';
57525 if ((i+1) == rows.length) {
57526 cls += ' fc-event-end';
57529 //Roo.log(ev.data);
57530 // how many rows should it span..
57531 var cg = this.eventTmpl.append(ctr,Roo.apply({
57534 }, ev.data) , true);
57537 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57538 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57539 cg.on('click', this.onEventClick, this, ev);
57543 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57544 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57547 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57548 cg.setWidth(ebox.right - sbox.x -2);
57552 renderEvents: function()
57554 // first make sure there is enough space..
57556 if (!this.eventTmpl) {
57557 this.eventTmpl = new Roo.Template(
57558 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57559 '<div class="fc-event-inner">' +
57560 '<span class="fc-event-time">{time}</span>' +
57561 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57563 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57571 this.cells.each(function(c) {
57572 //Roo.log(c.select('.fc-day-content div',true).first());
57573 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57576 var ctr = this.view.el.select('.fc-event-container',true).first();
57579 this.eventStore.each(function(ev){
57581 this.renderEvent(ev);
57585 this.view.layout();
57589 onEventEnter: function (e, el,event,d) {
57590 this.fireEvent('evententer', this, el, event);
57593 onEventLeave: function (e, el,event,d) {
57594 this.fireEvent('eventleave', this, el, event);
57597 onEventClick: function (e, el,event,d) {
57598 this.fireEvent('eventclick', this, el, event);
57601 onMonthChange: function () {
57605 onLoad: function () {
57607 //Roo.log('calendar onload');
57609 if(this.eventStore.getCount() > 0){
57613 this.eventStore.each(function(d){
57618 if (typeof(add.end_dt) == 'undefined') {
57619 Roo.log("Missing End time in calendar data: ");
57623 if (typeof(add.start_dt) == 'undefined') {
57624 Roo.log("Missing Start time in calendar data: ");
57628 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57629 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57630 add.id = add.id || d.id;
57631 add.title = add.title || '??';
57639 this.renderEvents();
57649 render : function ()
57653 if (!this.view.el.hasClass('course-timesheet')) {
57654 this.view.el.addClass('course-timesheet');
57656 if (this.tsStyle) {
57661 Roo.log(_this.grid.view.el.getWidth());
57664 this.tsStyle = Roo.util.CSS.createStyleSheet({
57665 '.course-timesheet .x-grid-row' : {
57668 '.x-grid-row td' : {
57669 'vertical-align' : 0
57671 '.course-edit-link' : {
57673 'text-overflow' : 'ellipsis',
57674 'overflow' : 'hidden',
57675 'white-space' : 'nowrap',
57676 'cursor' : 'pointer'
57681 '.de-act-sup-link' : {
57682 'color' : 'purple',
57683 'text-decoration' : 'line-through'
57687 'text-decoration' : 'line-through'
57689 '.course-timesheet .course-highlight' : {
57690 'border-top-style': 'dashed !important',
57691 'border-bottom-bottom': 'dashed !important'
57693 '.course-timesheet .course-item' : {
57694 'font-family' : 'tahoma, arial, helvetica',
57695 'font-size' : '11px',
57696 'overflow' : 'hidden',
57697 'padding-left' : '10px',
57698 'padding-right' : '10px',
57699 'padding-top' : '10px'
57707 monitorWindowResize : false,
57708 cellrenderer : function(v,x,r)
57713 xtype: 'CellSelectionModel',
57720 beforeload : function (_self, options)
57722 options.params = options.params || {};
57723 options.params._month = _this.monthField.getValue();
57724 options.params.limit = 9999;
57725 options.params['sort'] = 'when_dt';
57726 options.params['dir'] = 'ASC';
57727 this.proxy.loadResponse = this.loadResponse;
57729 //this.addColumns();
57731 load : function (_self, records, options)
57733 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57734 // if you click on the translation.. you can edit it...
57735 var el = Roo.get(this);
57736 var id = el.dom.getAttribute('data-id');
57737 var d = el.dom.getAttribute('data-date');
57738 var t = el.dom.getAttribute('data-time');
57739 //var id = this.child('span').dom.textContent;
57742 Pman.Dialog.CourseCalendar.show({
57746 productitem_active : id ? 1 : 0
57748 _this.grid.ds.load({});
57753 _this.panel.fireEvent('resize', [ '', '' ]);
57756 loadResponse : function(o, success, response){
57757 // this is overridden on before load..
57759 Roo.log("our code?");
57760 //Roo.log(success);
57761 //Roo.log(response)
57762 delete this.activeRequest;
57764 this.fireEvent("loadexception", this, o, response);
57765 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57770 result = o.reader.read(response);
57772 Roo.log("load exception?");
57773 this.fireEvent("loadexception", this, o, response, e);
57774 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57777 Roo.log("ready...");
57778 // loop through result.records;
57779 // and set this.tdate[date] = [] << array of records..
57781 Roo.each(result.records, function(r){
57783 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57784 _this.tdata[r.data.when_dt.format('j')] = [];
57786 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57789 //Roo.log(_this.tdata);
57791 result.records = [];
57792 result.totalRecords = 6;
57794 // let's generate some duumy records for the rows.
57795 //var st = _this.dateField.getValue();
57797 // work out monday..
57798 //st = st.add(Date.DAY, -1 * st.format('w'));
57800 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57802 var firstOfMonth = date.getFirstDayOfMonth();
57803 var days = date.getDaysInMonth();
57805 var firstAdded = false;
57806 for (var i = 0; i < result.totalRecords ; i++) {
57807 //var d= st.add(Date.DAY, i);
57810 for(var w = 0 ; w < 7 ; w++){
57811 if(!firstAdded && firstOfMonth != w){
57818 var dd = (d > 0 && d < 10) ? "0"+d : d;
57819 row['weekday'+w] = String.format(
57820 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57821 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57823 date.format('Y-m-')+dd
57826 if(typeof(_this.tdata[d]) != 'undefined'){
57827 Roo.each(_this.tdata[d], function(r){
57831 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57832 if(r.parent_id*1>0){
57833 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57836 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57837 deactive = 'de-act-link';
57840 row['weekday'+w] += String.format(
57841 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57843 r.product_id_name, //1
57844 r.when_dt.format('h:ia'), //2
57854 // only do this if something added..
57856 result.records.push(_this.grid.dataSource.reader.newRow(row));
57860 // push it twice. (second one with an hour..
57864 this.fireEvent("load", this, o, o.request.arg);
57865 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57867 sortInfo : {field: 'when_dt', direction : 'ASC' },
57869 xtype: 'HttpProxy',
57872 url : baseURL + '/Roo/Shop_course.php'
57875 xtype: 'JsonReader',
57892 'name': 'parent_id',
57896 'name': 'product_id',
57900 'name': 'productitem_id',
57918 click : function (_self, e)
57920 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57921 sd.setMonth(sd.getMonth()-1);
57922 _this.monthField.setValue(sd.format('Y-m-d'));
57923 _this.grid.ds.load({});
57929 xtype: 'Separator',
57933 xtype: 'MonthField',
57936 render : function (_self)
57938 _this.monthField = _self;
57939 // _this.monthField.set today
57941 select : function (combo, date)
57943 _this.grid.ds.load({});
57946 value : (function() { return new Date(); })()
57949 xtype: 'Separator',
57955 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57965 click : function (_self, e)
57967 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57968 sd.setMonth(sd.getMonth()+1);
57969 _this.monthField.setValue(sd.format('Y-m-d'));
57970 _this.grid.ds.load({});
57983 * Ext JS Library 1.1.1
57984 * Copyright(c) 2006-2007, Ext JS, LLC.
57986 * Originally Released Under LGPL - original licence link has changed is not relivant.
57989 * <script type="text/javascript">
57993 * @class Roo.LoadMask
57994 * A simple utility class for generically masking elements while loading data. If the element being masked has
57995 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57996 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57997 * element's UpdateManager load indicator and will be destroyed after the initial load.
57999 * Create a new LoadMask
58000 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58001 * @param {Object} config The config object
58003 Roo.LoadMask = function(el, config){
58004 this.el = Roo.get(el);
58005 Roo.apply(this, config);
58007 this.store.on('beforeload', this.onBeforeLoad, this);
58008 this.store.on('load', this.onLoad, this);
58009 this.store.on('loadexception', this.onLoadException, this);
58010 this.removeMask = false;
58012 var um = this.el.getUpdateManager();
58013 um.showLoadIndicator = false; // disable the default indicator
58014 um.on('beforeupdate', this.onBeforeLoad, this);
58015 um.on('update', this.onLoad, this);
58016 um.on('failure', this.onLoad, this);
58017 this.removeMask = true;
58021 Roo.LoadMask.prototype = {
58023 * @cfg {Boolean} removeMask
58024 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58025 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58028 * @cfg {String} msg
58029 * The text to display in a centered loading message box (defaults to 'Loading...')
58031 msg : 'Loading...',
58033 * @cfg {String} msgCls
58034 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58036 msgCls : 'x-mask-loading',
58039 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58045 * Disables the mask to prevent it from being displayed
58047 disable : function(){
58048 this.disabled = true;
58052 * Enables the mask so that it can be displayed
58054 enable : function(){
58055 this.disabled = false;
58058 onLoadException : function()
58060 Roo.log(arguments);
58062 if (typeof(arguments[3]) != 'undefined') {
58063 Roo.MessageBox.alert("Error loading",arguments[3]);
58067 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58068 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58077 this.el.unmask(this.removeMask);
58080 onLoad : function()
58082 this.el.unmask(this.removeMask);
58086 onBeforeLoad : function(){
58087 if(!this.disabled){
58088 this.el.mask(this.msg, this.msgCls);
58093 destroy : function(){
58095 this.store.un('beforeload', this.onBeforeLoad, this);
58096 this.store.un('load', this.onLoad, this);
58097 this.store.un('loadexception', this.onLoadException, this);
58099 var um = this.el.getUpdateManager();
58100 um.un('beforeupdate', this.onBeforeLoad, this);
58101 um.un('update', this.onLoad, this);
58102 um.un('failure', this.onLoad, this);
58107 * Ext JS Library 1.1.1
58108 * Copyright(c) 2006-2007, Ext JS, LLC.
58110 * Originally Released Under LGPL - original licence link has changed is not relivant.
58113 * <script type="text/javascript">
58118 * @class Roo.XTemplate
58119 * @extends Roo.Template
58120 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58122 var t = new Roo.XTemplate(
58123 '<select name="{name}">',
58124 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58128 // then append, applying the master template values
58131 * Supported features:
58136 {a_variable} - output encoded.
58137 {a_variable.format:("Y-m-d")} - call a method on the variable
58138 {a_variable:raw} - unencoded output
58139 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58140 {a_variable:this.method_on_template(...)} - call a method on the template object.
58145 <tpl for="a_variable or condition.."></tpl>
58146 <tpl if="a_variable or condition"></tpl>
58147 <tpl exec="some javascript"></tpl>
58148 <tpl name="named_template"></tpl> (experimental)
58150 <tpl for="."></tpl> - just iterate the property..
58151 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58155 Roo.XTemplate = function()
58157 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58164 Roo.extend(Roo.XTemplate, Roo.Template, {
58167 * The various sub templates
58172 * basic tag replacing syntax
58175 * // you can fake an object call by doing this
58179 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58182 * compile the template
58184 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58187 compile: function()
58191 s = ['<tpl>', s, '</tpl>'].join('');
58193 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58194 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58195 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58196 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58197 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58202 while(true == !!(m = s.match(re))){
58203 var forMatch = m[0].match(nameRe),
58204 ifMatch = m[0].match(ifRe),
58205 execMatch = m[0].match(execRe),
58206 namedMatch = m[0].match(namedRe),
58211 name = forMatch && forMatch[1] ? forMatch[1] : '';
58214 // if - puts fn into test..
58215 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58217 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58222 // exec - calls a function... returns empty if true is returned.
58223 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58225 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58233 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58234 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58235 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58238 var uid = namedMatch ? namedMatch[1] : id;
58242 id: namedMatch ? namedMatch[1] : id,
58249 s = s.replace(m[0], '');
58251 s = s.replace(m[0], '{xtpl'+ id + '}');
58256 for(var i = tpls.length-1; i >= 0; --i){
58257 this.compileTpl(tpls[i]);
58258 this.tpls[tpls[i].id] = tpls[i];
58260 this.master = tpls[tpls.length-1];
58264 * same as applyTemplate, except it's done to one of the subTemplates
58265 * when using named templates, you can do:
58267 * var str = pl.applySubTemplate('your-name', values);
58270 * @param {Number} id of the template
58271 * @param {Object} values to apply to template
58272 * @param {Object} parent (normaly the instance of this object)
58274 applySubTemplate : function(id, values, parent)
58278 var t = this.tpls[id];
58282 if(t.test && !t.test.call(this, values, parent)){
58286 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58287 Roo.log(e.toString());
58293 if(t.exec && t.exec.call(this, values, parent)){
58297 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58298 Roo.log(e.toString());
58303 var vs = t.target ? t.target.call(this, values, parent) : values;
58304 parent = t.target ? values : parent;
58305 if(t.target && vs instanceof Array){
58307 for(var i = 0, len = vs.length; i < len; i++){
58308 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58310 return buf.join('');
58312 return t.compiled.call(this, vs, parent);
58314 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58315 Roo.log(e.toString());
58316 Roo.log(t.compiled);
58321 compileTpl : function(tpl)
58323 var fm = Roo.util.Format;
58324 var useF = this.disableFormats !== true;
58325 var sep = Roo.isGecko ? "+" : ",";
58326 var undef = function(str) {
58327 Roo.log("Property not found :" + str);
58331 var fn = function(m, name, format, args)
58333 //Roo.log(arguments);
58334 args = args ? args.replace(/\\'/g,"'") : args;
58335 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58336 if (typeof(format) == 'undefined') {
58337 format= 'htmlEncode';
58339 if (format == 'raw' ) {
58343 if(name.substr(0, 4) == 'xtpl'){
58344 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58347 // build an array of options to determine if value is undefined..
58349 // basically get 'xxxx.yyyy' then do
58350 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58351 // (function () { Roo.log("Property not found"); return ''; })() :
58356 Roo.each(name.split('.'), function(st) {
58357 lookfor += (lookfor.length ? '.': '') + st;
58358 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58361 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58364 if(format && useF){
58366 args = args ? ',' + args : "";
58368 if(format.substr(0, 5) != "this."){
58369 format = "fm." + format + '(';
58371 format = 'this.call("'+ format.substr(5) + '", ';
58375 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58379 // called with xxyx.yuu:(test,test)
58381 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58383 // raw.. - :raw modifier..
58384 return "'"+ sep + udef_st + name + ")"+sep+"'";
58388 // branched to use + in gecko and [].join() in others
58390 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58391 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58394 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58395 body.push(tpl.body.replace(/(\r\n|\n)/g,
58396 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58397 body.push("'].join('');};};");
58398 body = body.join('');
58401 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58403 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58409 applyTemplate : function(values){
58410 return this.master.compiled.call(this, values, {});
58411 //var s = this.subs;
58414 apply : function(){
58415 return this.applyTemplate.apply(this, arguments);
58420 Roo.XTemplate.from = function(el){
58421 el = Roo.getDom(el);
58422 return new Roo.XTemplate(el.value || el.innerHTML);